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