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