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