]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
preliminary support for \mbox
[lyx.git] / src / mathed / math_support.C
1 #include <config.h>
2
3 #include <map>
4
5 #include "math_support.h"
6 #include "lyxfont.h"
7 #include "FontLoader.h"
8 #include "font.h"
9 #include "math_defs.h"
10 #include "math_inset.h"
11 #include "math_parser.h"
12 #include "Painter.h"
13 #include "debug.h"
14
15 using std::map;
16 using std::endl;
17 using std::max;
18
19
20 bool isBinaryOp(char c, MathTextCodes type)
21 {
22         return type < LM_TC_SYMB && strchr("+-<>=/*", c);
23 }
24
25
26 ///
27 class Matrix {
28 public:
29         ///
30         Matrix(int, double, double);
31         ///
32         void transform(double &, double &);
33 private:
34         ///
35         double m_[2][2];
36 };
37
38
39 Matrix::Matrix(int code, double x, double y)
40 {
41         double const cs = (code & 1) ? 0 : (1 - code);
42         double const sn = (code & 1) ? (2 - code) : 0;
43         m_[0][0] =  cs * x;
44         m_[0][1] =  sn * x;
45         m_[1][0] = -sn * y;
46         m_[1][1] =  cs * y;
47 }
48
49
50 void Matrix::transform(double & x, double & y)
51 {
52         double xx = m_[0][0] * x + m_[0][1] * y;
53         double yy = m_[1][0] * x + m_[1][1] * y;
54         x = xx;
55         y = yy;
56 }
57
58
59 namespace {
60
61 LyXFont * MathFonts = 0;
62 bool font_available[LM_FONT_END];
63 bool font_available_initialized[LM_FONT_END];
64
65 enum MathFont {
66         FONT_IT,
67         FONT_SYMBOL,
68         FONT_SYMBOLI,
69         FONT_BF,
70         FONT_TT,
71         FONT_RM,
72         FONT_SF,
73         FONT_CMR,
74         FONT_CMSY,
75         FONT_CMM,
76         FONT_CMEX,
77         FONT_MSA,
78         FONT_MSB,
79         FONT_EUFRAK,
80         FONT_FAKEBB,
81         FONT_FAKECAL,
82         FONT_FAKEFRAK,
83         FONT_NUM
84 };
85
86 void mathed_init_fonts()
87 {
88         MathFonts = new LyXFont[FONT_NUM]; //DEC cxx cannot initialize all fonts
89         //at once (JMarc) rc
90
91         for (int i = 0 ; i < FONT_NUM ; ++i) {
92                 MathFonts[i] = LyXFont(LyXFont::ALL_SANE);
93         }
94
95         MathFonts[FONT_IT].setShape(LyXFont::ITALIC_SHAPE);
96
97         MathFonts[FONT_SYMBOL].setFamily(LyXFont::SYMBOL_FAMILY);
98
99         MathFonts[FONT_SYMBOLI].setFamily(LyXFont::SYMBOL_FAMILY);
100         MathFonts[FONT_SYMBOLI].setShape(LyXFont::ITALIC_SHAPE);
101
102         MathFonts[FONT_BF].setSeries(LyXFont::BOLD_SERIES);
103
104         MathFonts[FONT_TT].setFamily(LyXFont::TYPEWRITER_FAMILY);
105         MathFonts[FONT_RM].setFamily(LyXFont::ROMAN_FAMILY);
106         MathFonts[FONT_SF].setFamily(LyXFont::SANS_FAMILY);
107
108         MathFonts[FONT_CMR].setFamily(LyXFont::CMR_FAMILY);
109         MathFonts[FONT_CMSY].setFamily(LyXFont::CMSY_FAMILY);
110         MathFonts[FONT_CMM].setFamily(LyXFont::CMM_FAMILY);
111         MathFonts[FONT_CMEX].setFamily(LyXFont::CMEX_FAMILY);
112         MathFonts[FONT_MSA].setFamily(LyXFont::MSA_FAMILY);
113         MathFonts[FONT_MSB].setFamily(LyXFont::MSB_FAMILY);
114         MathFonts[FONT_EUFRAK].setFamily(LyXFont::EUFRAK_FAMILY);
115
116         MathFonts[FONT_FAKEBB].setFamily(LyXFont::TYPEWRITER_FAMILY);
117         MathFonts[FONT_FAKEBB].setSeries(LyXFont::BOLD_SERIES);
118
119         MathFonts[FONT_FAKECAL].setFamily(LyXFont::SANS_FAMILY);
120         MathFonts[FONT_FAKECAL].setShape(LyXFont::ITALIC_SHAPE);
121
122         MathFonts[FONT_FAKEFRAK].setFamily(LyXFont::SANS_FAMILY);
123         MathFonts[FONT_FAKEFRAK].setSeries(LyXFont::BOLD_SERIES);
124
125         for (int i = 0; i < LM_FONT_END; ++i)
126                 font_available_initialized[i] = false;
127 }
128
129
130 LyXFont const & whichFontBaseIntern(MathTextCodes type)
131 {
132         if (!MathFonts)
133                 mathed_init_fonts();
134
135         switch (type) {
136         case LM_TC_SYMB:        
137         case LM_TC_BOLDSYMB:    
138                 return MathFonts[FONT_SYMBOLI];
139
140         case LM_TC_VAR:
141         case LM_TC_IT:
142                 return MathFonts[FONT_IT];
143
144         case LM_TC_BF:
145                 return MathFonts[FONT_BF];
146
147         case LM_TC_BB:
148                 return MathFonts[FONT_MSB];
149
150         case LM_TC_CAL:
151                 return MathFonts[FONT_CMSY];
152
153         case LM_TC_TT:
154                 return MathFonts[FONT_TT];
155
156         case LM_TC_BOX:
157         case LM_TC_TEXTRM:
158         case LM_TC_CONST:
159         case LM_TC_TEX:
160         case LM_TC_RM:
161                 return MathFonts[FONT_RM];
162
163         case LM_TC_SF:
164                 return MathFonts[FONT_SF];
165
166         case LM_TC_CMR:
167                 return MathFonts[FONT_CMR];
168
169         case LM_TC_CMSY:
170                 return MathFonts[FONT_CMSY];
171
172         case LM_TC_CMM:
173                 return MathFonts[FONT_CMM];
174
175         case LM_TC_CMEX:
176                 return MathFonts[FONT_CMEX];
177
178         case LM_TC_MSA:
179                 return MathFonts[FONT_MSA];
180
181         case LM_TC_MSB:
182                 return MathFonts[FONT_MSB];
183
184         case LM_TC_EUFRAK:
185                 return MathFonts[FONT_EUFRAK];
186
187         default:
188                 break;
189         }
190         return MathFonts[1];
191 }
192
193 LyXFont const & whichFontBase(MathTextCodes type)
194 {
195         if (!MathFonts)
196                 mathed_init_fonts();
197
198         switch (type) {
199         case LM_TC_BB:
200                 if (math_font_available(LM_TC_MSB))
201                         return MathFonts[FONT_MSB];
202                 else
203                         return MathFonts[FONT_FAKEBB];
204
205         case LM_TC_CAL:
206                 if (math_font_available(LM_TC_CMSY))
207                         return MathFonts[FONT_CMSY];
208                 else
209                         return MathFonts[FONT_FAKECAL];
210
211         case LM_TC_EUFRAK:
212                 if (math_font_available(LM_TC_EUFRAK))
213                         return MathFonts[FONT_EUFRAK];
214                 else
215                         return MathFonts[FONT_FAKEFRAK];
216
217         default:
218                 break;
219         }
220         return whichFontBaseIntern(type);
221 }
222
223
224 LyXFont whichFont(MathTextCodes type, MathMetricsInfo const & size)
225 {
226         LyXFont f = whichFontBase(type);
227         // use actual size
228         f.setSize(size.font.size());
229
230         switch (size.style) {
231         case LM_ST_DISPLAY:
232                 if (type == LM_TC_BOLDSYMB || type == LM_TC_CMEX) {
233                         f.incSize();
234                         f.incSize();
235                 }
236                 break;
237
238         case LM_ST_TEXT:
239                 break;
240
241         case LM_ST_SCRIPT:
242                 f.decSize();
243                 f.decSize();
244                 break;
245
246         case LM_ST_SCRIPTSCRIPT:
247                 f.decSize();
248                 f.decSize();
249                 f.decSize();
250                 break;
251
252         default:
253                 lyxerr << "Math Error: wrong font size: " << size.style << endl;
254                 break;
255         }
256
257         if (type != LM_TC_TEXTRM && type != LM_TC_BOX)
258                 f.setColor(LColor::math);
259
260         if (type == LM_TC_TEX)
261                 f.setColor(LColor::latex);
262
263         return f;
264 }
265
266 } // namespace
267
268
269 bool math_font_available(MathTextCodes type)
270 {
271         if (!font_available_initialized[type]) {
272                 font_available_initialized[type] = true;
273                 font_available[type] = fontloader.available(whichFontBaseIntern(type));
274         }
275         return font_available[type];
276 }
277
278
279 namespace {
280
281 /*
282  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
283  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
284  */
285
286
287 double const parenthHigh[] = {
288         2, 13,
289         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
290         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
291         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
292         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
293         0.9840, 0.9986,
294         0
295 };
296
297
298 double const parenth[] = {
299         2, 13,
300         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
301         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
302         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
303         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
304         0.9930, 0.9919,
305         0
306 };
307
308
309 double const brace[] = {
310         2, 21,
311         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
312         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
313         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
314         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
315         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
316         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
317         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
318         0
319 };
320
321
322 double const arrow[] = {
323         4, 7,
324         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
325         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
326         0.9500, 0.7500,
327         3, 0.5000, 0.1500, 0.5000, 0.9500,
328         0
329 };
330
331
332 double const Arrow[] = {
333         4, 7,
334         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
335         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
336         0.9500, 0.7500,
337         3, 0.3500, 0.5000, 0.3500, 0.9500,
338         3, 0.6500, 0.5000, 0.6500, 0.9500,
339         0
340 };
341
342
343 double const udarrow[] = {
344         2, 3,
345         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
346         2, 3,
347         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
348         1, 0.5, 0.2,  0.5, 0.8,
349         0
350 };
351
352
353 double const Udarrow[] = {
354         2, 3,
355         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
356         2, 3,
357         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
358         1, 0.35, 0.2, 0.35, 0.8,
359         1, 0.65, 0.2, 0.65, 0.8,
360         0
361 };
362
363
364 double const brack[] = {
365         2, 4,
366         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
367         0
368 };
369
370
371 double const corner[] = {
372         2, 3,
373         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
374         0
375 };
376
377
378 double const angle[] = {
379         2, 3,
380         1, 0,  0.05, 0.5,  1, 1,
381         0
382 };
383
384
385 double const slash[] = {
386         1, 0.95, 0.05, 0.05, 0.95,
387         0
388 };
389
390
391 double const hline[] = {
392         1, 0.00, 0.5, 1.0, 0.5,
393         0
394 };
395
396
397 double const hline2[] = {
398         1, 0.1, 0.5,  0.3, 0.5,
399         1, 0.7, 0.5,  0.9, 0.5,
400         0
401 };
402
403
404 double const hline3[] = {
405         1, 0.1,   0,  0.15,  0,
406         1, 0.475, 0,  0.525, 0,
407         1, 0.85,  0,  0.9,   0,
408         0
409 };
410
411
412 double const dline3[] = {
413         1, 0.1,   0.1,   0.15,  0.15,
414         1, 0.475, 0.475, 0.525, 0.525,
415         1, 0.85,  0.85,  0.9,   0.9,
416         0
417 };
418
419
420 double const hlinesmall[] = {
421         1, 0.4, 0.5, 0.6, 0.5,
422         0
423 };
424
425
426 double const vert[] = {
427         1, 0.5, 0.05,  0.5, 0.95,
428         0
429 };
430
431
432 double const  Vert[] = {
433         1, 0.3, 0.05,  0.3, 0.95,
434         1, 0.7, 0.05,  0.7, 0.95,
435         0
436 };
437
438
439 double const tilde[] = {
440         2, 4,
441         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
442         0
443 };
444
445
446 struct deco_struct {
447         double const * data;
448         int angle;
449 };
450
451 struct named_deco_struct {
452         char const * name;
453         double const * data;
454         int angle;
455 };
456
457 named_deco_struct deco_table[] = {
458         // Decorations
459         {"widehat",        angle,      3 },
460         {"widetilde",      tilde,      0 },
461         {"underline",      hline,      0 },
462         {"overline",       hline,      0 },
463         {"underbrace",     brace,      1 },
464         {"overbrace",      brace,      3 },
465         {"overleftarrow",  arrow,      1 },
466         {"overrightarrow", arrow,      3 },
467         
468         // Delimiters
469         {"(",              parenth,    0 },
470         {")",              parenth,    2 },
471         {"{",              brace,      0 },
472         {"}",              brace,      2 },
473         {"[",              brack,      0 },
474         {"]",              brack,      2 },
475         {"|",              vert,       0 },
476         {"/",              slash,      0 },
477         {"Vert",           Vert,       0 },
478         {"'",              slash,      1 },
479         {"backslash",      slash,      1 },
480         {"langle",         angle,      0 },
481         {"lceil",          corner,     0 },
482         {"lfloor",         corner,     1 },
483         {"rangle",         angle,      2 },
484         {"rceil",          corner,     3 },
485         {"rfloor",         corner,     2 },
486         {"downarrow",      arrow,      2 },
487         {"Downarrow",      Arrow,      2 },
488         {"uparrow",        arrow,      0 },
489         {"Uparrow",        Arrow,      0 },
490         {"updownarrow",    udarrow,    0 },
491         {"Updownarrow",    Udarrow,    0 },     
492         
493         // Accents
494         {"ddot",           hline2,     0 },
495         {"hat",            angle,      3 },
496         {"grave",          slash,      1 },
497         {"acute",          slash,      0 },
498         {"tilde",          tilde,      0 },
499         {"bar",            hline,      0 },
500         {"dot",            hlinesmall, 0 },
501         {"check",          angle,      1 },
502         {"breve",          parenth,    1 },
503         {"vec",            arrow,      3 },
504         {"not",            slash,      0 },
505         
506         // Dots
507         {"ldots",          hline3,     0 },
508         {"cdots",          hline3,     0 },
509         {"vdots",          hline3,     1 },
510         {"ddots",          dline3,     0 }
511 };
512
513
514 map<string, deco_struct> deco_list;
515
516 // sort the table on startup
517 struct init_deco_table {
518         init_deco_table() {
519                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
520                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
521                         deco_struct d;
522                         d.data  = p->data;
523                         d.angle = p->angle;
524                         deco_list[p->name]= d;
525                 }
526         }
527 };
528
529 static init_deco_table dummy;
530
531
532 deco_struct const * search_deco(string const & name)
533 {
534         map<string, deco_struct>::const_iterator p = deco_list.find(name);
535         return (p == deco_list.end()) ? 0 : &(p->second);
536 }
537
538
539 } // namespace anon
540
541
542 void mathed_char_dim(MathTextCodes type, MathMetricsInfo const & size,
543         unsigned char c, int & asc, int & des, int & wid)
544 {
545         LyXFont const font = whichFont(type, size);
546         des = lyxfont::descent(c, font);
547         asc = lyxfont::ascent(c, font);
548         wid = mathed_char_width(type, size, c);
549 }
550
551
552 int mathed_char_height(MathTextCodes type, MathMetricsInfo const & size,
553         unsigned char c, int & asc, int & des)
554 {
555         LyXFont const font = whichFont(type, size);
556         des = lyxfont::descent(c, font);
557         asc = lyxfont::ascent(c, font);
558         return asc + des;
559 }
560
561
562 int mathed_char_height(MathTextCodes type, MathMetricsInfo const & size,
563         unsigned char c)
564 {
565         int asc;
566         int des;
567         return mathed_char_height(type, size, c, asc, des);
568 }
569
570
571 int mathed_char_ascent(MathTextCodes type, MathMetricsInfo const & size,
572         unsigned char c)
573 {
574         LyXFont const font = whichFont(type, size);
575         return lyxfont::ascent(c, font);
576 }
577
578
579 int mathed_char_descent(MathTextCodes type, MathMetricsInfo const & size,
580         unsigned char c)
581 {
582         LyXFont const font = whichFont(type, size);
583         return lyxfont::descent(c, font);
584 }
585
586
587 int mathed_char_width(MathTextCodes type, MathMetricsInfo const & size,
588         unsigned char c)
589 {
590         LyXFont const font = whichFont(type, size);
591         if (isBinaryOp(c, type))
592                 return lyxfont::width(c, font) + 2 * lyxfont::width(' ', font);
593         else
594                 return lyxfont::width(c, font);
595 }
596
597
598 void mathed_string_dim(MathTextCodes type, MathMetricsInfo const & size,
599         string const & s, int & asc, int & des, int & wid)
600 {
601         mathed_string_height(type, size, s, asc, des);
602         wid = mathed_string_width(type, size, s);
603 }
604
605
606 int mathed_string_height(MathTextCodes type, MathMetricsInfo const & size,
607         string const & s, int & asc, int & des)
608 {
609         LyXFont const font = whichFont(type, size);
610         asc = des = 0;
611         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
612                 des = max(des, lyxfont::descent(*it, font));
613                 asc = max(asc, lyxfont::ascent(*it, font));
614         }
615         return asc + des;
616 }
617
618
619 int mathed_string_width(MathTextCodes type, MathMetricsInfo const & size,
620         string const & s)
621 {
622         return lyxfont::width(s, whichFont(type, size));
623 }
624
625
626 int mathed_string_ascent(MathTextCodes type, MathMetricsInfo const & size,
627         string const & s)
628 {
629         LyXFont const font = whichFont(type, size);
630         int asc = 0;
631         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
632                 asc = max(asc, lyxfont::ascent(*it, font));
633         return asc;
634 }
635
636
637 int mathed_string_descent(MathTextCodes type, MathMetricsInfo const & size,
638         string const & s)
639 {
640         LyXFont const font = whichFont(type, size);
641         int des = 0;
642         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
643                 des = max(des, lyxfont::descent(*it, font));
644         return des;
645 }
646
647
648
649 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
650         const string & name)
651 {
652         if (name == ".") {
653                 pain.line(x + w/2, y, x + w/2, y + h,
654                           LColor::mathcursor, Painter::line_onoffdash);
655                 return;
656         }       
657         
658         deco_struct const * mds = search_deco(name);
659         if (!mds) {
660                 lyxerr << "Deco was not found. Programming error?\n";
661                 lyxerr << "name: '" << name << "'\n";
662                 return;
663         }
664         
665         int const n = (w < h) ? w : h;
666         int const r = mds->angle;
667         double const * d = mds->data;
668         
669         if (h > 70 && (name == "(" || name == ")"))
670                 d = parenthHigh;
671         
672         Matrix mt(r, w, h);
673         Matrix sqmt(r, n, n);
674
675         if (r > 0 && r < 3)
676                 y += h;
677
678         if (r >= 2)
679                 x += w;
680
681         for (int i = 0; d[i]; ) {
682                 int code = int(d[i++]);
683                 if (code & 1) {  // code == 1 || code == 3
684                         double xx = d[i++];
685                         double yy = d[i++];
686                         double x2 = d[i++];
687                         double y2 = d[i++];
688                         if (code == 3)
689                                 sqmt.transform(xx, yy);
690                         else
691                                 mt.transform(xx, yy);
692                         mt.transform(x2, y2);
693                         pain.line(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
694                                         LColor::math);
695                 }       else {
696                         int xp[32];
697                         int yp[32];
698                         int const n = int(d[i++]);
699                         for (int j = 0; j < n; ++j) {
700                                 double xx = d[i++];
701                                 double yy = d[i++];
702 //           lyxerr << " " << xx << " " << yy << " ";
703                                 if (code == 4)
704                                         sqmt.transform(xx, yy);
705                                 else
706                                         mt.transform(xx, yy);
707                                 xp[j] = x + int(xx);
708                                 yp[j] = y + int(yy);
709                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
710                         }
711                         pain.lines(xp, yp, n, LColor::math);
712                 }
713         }
714 }
715
716
717 // In the future maybe we use a better fonts renderer
718 void drawStr(Painter & pain, MathTextCodes type, MathMetricsInfo const & siz,
719         int x, int y, string const & s)
720 {
721         pain.text(x, y, s, whichFont(type, siz));
722 }
723
724
725 void drawChar(Painter & pain, MathTextCodes type, MathMetricsInfo const & siz,
726         int x, int y, char c)
727 {
728         string s;
729         if (isBinaryOp(c, type))
730                 s += ' ';
731         s += c;
732         if (isBinaryOp(c, type))
733                 s += ' ';
734         drawStr(pain, type, siz, x, y, s);
735 }
736
737
738 // decrease math size for super- and subscripts
739 void smallerStyleScript(MathMetricsInfo & st)
740 {
741         switch (st.style) {
742                 case LM_ST_DISPLAY:
743                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
744                 default:            st.style = LM_ST_SCRIPTSCRIPT;
745         }
746 }
747
748
749 // decrease math size for fractions
750 void smallerStyleFrac(MathMetricsInfo & st)
751 {
752         switch (st.style) {
753                 case LM_ST_DISPLAY: st.style = LM_ST_TEXT; break;
754                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
755                 default:            st.style = LM_ST_SCRIPTSCRIPT;
756         }
757 }
758
759
760 void math_font_max_dim(MathTextCodes code, MathMetricsInfo const & siz,
761         int & asc, int & des)
762 {
763         LyXFont font = whichFont(code, siz);
764         asc = lyxfont::maxAscent(font);
765         des = lyxfont::maxDescent(font);
766 }
767
768
769 char const * latex_mathspace[] = {
770         "!", ",", ":", ";", "quad", "qquad"
771 };
772
773
774 char const * math_font_name(MathTextCodes code)
775 {
776         static char const * theFontNames[] = {
777                 "mathrm",
778                 "mathcal",
779                 "mathfrak",
780                 "mathbf",
781                 "mathbb",
782                 "mathsf",
783                 "mathtt",
784                 "mathit",
785                 "textrm"
786         };
787
788         if (code >= LM_TC_RM && code <= LM_TC_TEXTRM) 
789                 return theFontNames[code - LM_TC_RM];
790         return 0;
791 }