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