]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.cpp
Fix horizontal lines in math arrays
[lyx.git] / src / mathed / MathSupport.cpp
1 /**
2  * \file MathSupport.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "MathSupport.h"
15
16 #include "InsetMathFont.h"
17 #include "InsetMathSymbol.h"
18 #include "MathData.h"
19 #include "MathParser.h"
20 #include "MathStream.h"
21
22 #include "MetricsInfo.h"
23
24 #include "frontends/FontLoader.h"
25 #include "frontends/FontMetrics.h"
26 #include "frontends/Painter.h"
27
28 #include "support/debug.h"
29 #include "support/docstream.h"
30 #include "support/lyxlib.h"
31
32 #include <map>
33 #include <algorithm>
34
35 using namespace std;
36
37 namespace lyx {
38
39 using frontend::Painter;
40
41
42 ///
43 class Matrix {
44 public:
45         ///
46         Matrix(int, double, double);
47         ///
48         void transform(double &, double &);
49 private:
50         ///
51         double m_[2][2];
52 };
53
54
55 Matrix::Matrix(int code, double x, double y)
56 {
57         double const cs = (code & 1) ? 0 : (1 - code);
58         double const sn = (code & 1) ? (2 - code) : 0;
59         m_[0][0] =  cs * x;
60         m_[0][1] =  sn * x;
61         m_[1][0] = -sn * y;
62         m_[1][1] =  cs * y;
63 }
64
65
66 void Matrix::transform(double & x, double & y)
67 {
68         double xx = m_[0][0] * x + m_[0][1] * y;
69         double yy = m_[1][0] * x + m_[1][1] * y;
70         x = xx;
71         y = yy;
72 }
73
74
75
76 namespace {
77
78 /*
79  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
80  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
81  */
82
83
84 double const parenthHigh[] = {
85         2, 13,
86         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
87         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
88         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
89         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
90         0.9840, 0.9986,
91         0
92 };
93
94
95 double const parenth[] = {
96         2, 13,
97         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
98         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
99         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
100         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
101         0.9930, 0.9919,
102         0
103 };
104
105
106 double const brace[] = {
107         2, 21,
108         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
109         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
110         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
111         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
112         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
113         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
114         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
115         0
116 };
117
118
119 double const mapsto[] = {
120         2, 3,
121         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
122         1, 0.015, 0.475, 0.945, 0.475,
123         1, 0.015, 0.015, 0.015, 0.985,
124         0
125 };
126
127
128 double const lhook[] = {
129         2, 3,
130         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
131         1, 0.015, 0.475, 0.7, 0.475,
132         2, 5,
133         0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
134         0.825, 0.35, 0.7, 0.475,
135         0
136 };
137
138
139 double const rhook[] = {
140         2, 3,
141         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
142         1, 0.3, 0.475, 0.985, 0.475,
143         2, 5,
144         0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
145         0.175, 0.35, 0.3, 0.475,
146         0
147 };
148
149
150 double const LRArrow[] = {
151         2, 3,
152         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
153         2, 3,
154         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
155         1, 0.2, 0.8, 0.8, 0.8,
156         1, 0.2, 0.2, 0.8, 0.2,
157         0
158 };
159
160
161 double const LArrow[] = {
162         2, 3,
163         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
164         1, 0.2, 0.8, 0.985, 0.8,
165         1, 0.2, 0.2, 0.985, 0.2,
166         0
167 };
168
169
170 double const lharpoondown[] = {
171         2, 2,
172         0.015, 0.5, 0.25, 0.985,
173         1, 0.02, 0.475, 0.985, 0.475,
174         0
175 };
176
177
178 double const lharpoonup[] = {
179         2, 2,
180         0.25, 0.015, 0.015, 0.5,
181         1, 0.02, 0.525, 0.985, 0.525,
182         0
183 };
184
185
186 double const lrharpoons[] = {
187         2, 2,
188         0.25, 0.015, 0.015, 0.225,
189         1, 0.02, 0.23, 0.985, 0.23,
190         2, 2,
191         0.75, 0.985, 0.985, 0.775,
192         1, 0.02, 0.7, 0.980, 0.7,
193         0
194 };
195
196
197 double const rlharpoons[] = {
198         2, 2,
199         0.75, 0.015, 0.985, 0.225,
200         1, 0.02, 0.23, 0.985, 0.23,
201         2, 2,
202         0.25, 0.985, 0.015, 0.775,
203         1, 0.02, 0.7, 0.980, 0.7,
204         0
205 };
206
207
208 double const arrow[] = {
209         4, 7,
210         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
211         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
212         0.9500, 0.7500,
213         3, 0.5000, 0.1500, 0.5000, 0.9500,
214         0
215 };
216
217
218 double const Arrow[] = {
219         4, 7,
220         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
221         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
222         0.9500, 0.7500,
223         3, 0.3500, 0.5000, 0.3500, 0.9500,
224         3, 0.6500, 0.5000, 0.6500, 0.9500,
225         0
226 };
227
228
229 double const udarrow[] = {
230         2, 3,
231         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
232         2, 3,
233         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
234         1, 0.5, 0.1,  0.5, 0.9,
235         0
236 };
237
238
239 double const Udarrow[] = {
240         2, 3,
241         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
242         2, 3,
243         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
244         1, 0.35, 0.2, 0.35, 0.8,
245         1, 0.65, 0.2, 0.65, 0.8,
246         0
247 };
248
249
250 double const brack[] = {
251         2, 4,
252         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
253         0
254 };
255
256
257 double const dbrack[] = {
258         2, 4,
259         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
260         2, 2,
261         0.50, 0.05,  0.50, 0.95,
262         0
263 };
264
265
266 double const corner[] = {
267         2, 3,
268         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
269         0
270 };
271
272
273 double const angle[] = {
274         2, 3,
275         1, 0,  0.05, 0.5,  1, 1,
276         0
277 };
278
279
280 double const slash[] = {
281         1, 0.95, 0.05, 0.05, 0.95,
282         0
283 };
284
285
286 double const hline[] = {
287         1, 0.00, 0.5, 1.0, 0.5,
288         0
289 };
290
291
292 double const ddot[] = {
293         1, 0.2, 0.5, 0.3, 0.5,
294         1, 0.7, 0.5, 0.8, 0.5,
295         0
296 };
297
298
299 double const dddot[] = {
300         1, 0.1,  0.5, 0.2,  0.5,
301         1, 0.45, 0.5, 0.55, 0.5,
302         1, 0.8,  0.5, 0.9,  0.5,
303         0
304 };
305
306
307 double const ddddot[] = {
308         1, 0.1,  0.5, 0.2,  0.5,
309         1, 0.45, 0.5, 0.55, 0.5,
310         1, 0.8,  0.5, 0.9,  0.5,
311         1, 1.15, 0.5, 1.25, 0.5,
312         0
313 };
314
315
316 double const hline3[] = {
317         1, 0.1,   0,  0.15,  0,
318         1, 0.475, 0,  0.525, 0,
319         1, 0.85,  0,  0.9,   0,
320         0
321 };
322
323
324 double const dline3[] = {
325         1, 0.1,   0.1,   0.15,  0.15,
326         1, 0.475, 0.475, 0.525, 0.525,
327         1, 0.85,  0.85,  0.9,   0.9,
328         0
329 };
330
331
332 double const hlinesmall[] = {
333         1, 0.4, 0.5, 0.6, 0.5,
334         0
335 };
336
337
338 double const ring[] = {
339         2, 5,
340         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
341         0
342 };
343
344
345 double const vert[] = {
346         1, 0.5, 0.05,  0.5, 0.95,
347         0
348 };
349
350
351 double const  Vert[] = {
352         1, 0.3, 0.05,  0.3, 0.95,
353         1, 0.7, 0.05,  0.7, 0.95,
354         0
355 };
356
357
358 double const tilde[] = {
359         2, 4,
360         0.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 0.2,
361         0
362 };
363
364
365 struct deco_struct {
366         double const * data;
367         int angle;
368 };
369
370 struct named_deco_struct {
371         char const * name;
372         double const * data;
373         int angle;
374 };
375
376 named_deco_struct deco_table[] = {
377         // Decorations
378         {"widehat",             angle,        3 },
379         {"widetilde",           tilde,        0 },
380         {"underbar",            hline,        0 },
381         {"underline",           hline,        0 },
382         {"overline",            hline,        0 },
383         {"underbrace",          brace,        1 },
384         {"overbrace",           brace,        3 },
385         {"overleftarrow",       arrow,        1 },
386         {"overrightarrow",      arrow,        3 },
387         {"overleftrightarrow",  udarrow,      1 },
388         {"xhookleftarrow",      lhook,        0 },
389         {"xhookrightarrow",     rhook,        0 },
390         {"xleftarrow",          arrow,        1 },
391         {"xLeftarrow",          LArrow,       0 },
392         {"xleftharpoondown",    lharpoondown, 0 },
393         {"xleftharpoonup",      lharpoonup,   0 },
394         {"xleftrightharpoons",  lrharpoons,   0 },
395         {"xleftrightarrow",     udarrow,      1 },
396         {"xLeftrightarrow",     LRArrow,      0 },
397         {"xmapsto",             mapsto,       0 },
398         {"xrightarrow",         arrow,        3 },
399         {"xRightarrow",         LArrow,       2 },
400         {"xrightharpoondown",   lharpoonup,   2 },
401         {"xrightharpoonup",     lharpoondown, 2 },
402         {"xrightleftharpoons",  rlharpoons,   0 },
403         {"underleftarrow",      arrow,        1 },
404         {"underrightarrow",     arrow,        3 },
405         {"underleftrightarrow", udarrow,      1 },
406         {"undertilde",          tilde,        0 },
407         {"utilde",              tilde,        0 },
408
409         // Delimiters
410         {"(",              parenth,    0 },
411         {")",              parenth,    2 },
412         {"{",              brace,      0 },
413         {"}",              brace,      2 },
414         {"lbrace",         brace,      0 },
415         {"rbrace",         brace,      2 },
416         {"[",              brack,      0 },
417         {"]",              brack,      2 },
418         {"llbracket",      dbrack,     0 },
419         {"rrbracket",      dbrack,     2 },
420         {"|",              vert,       0 },
421         {"/",              slash,      0 },
422         {"slash",          slash,      0 },
423         {"vert",           vert,       0 },
424         {"lvert",          vert,       0 },
425         {"rvert",          vert,       0 },
426         {"Vert",           Vert,       0 },
427         {"lVert",          Vert,       0 },
428         {"rVert",          Vert,       0 },
429         {"'",              slash,      1 },
430         {"<",              angle,      0 },
431         {">",              angle,      2 },
432         {"\\",             slash,      1 },
433         {"backslash",      slash,      1 },
434         {"langle",         angle,      0 },
435         {"lceil",          corner,     0 },
436         {"lfloor",         corner,     1 },
437         {"rangle",         angle,      2 },
438         {"rceil",          corner,     3 },
439         {"rfloor",         corner,     2 },
440         {"downarrow",      arrow,      2 },
441         {"Downarrow",      Arrow,      2 },
442         {"uparrow",        arrow,      0 },
443         {"Uparrow",        Arrow,      0 },
444         {"updownarrow",    udarrow,    0 },
445         {"Updownarrow",    Udarrow,    0 },
446
447         // Accents
448         {"ddot",           ddot,       0 },
449         {"dddot",          dddot,      0 },
450         {"ddddot",         ddddot,     0 },
451         {"hat",            angle,      3 },
452         {"grave",          slash,      1 },
453         {"acute",          slash,      0 },
454         {"tilde",          tilde,      0 },
455         {"bar",            hline,      0 },
456         {"dot",            hlinesmall, 0 },
457         {"check",          angle,      1 },
458         {"breve",          parenth,    1 },
459         {"vec",            arrow,      3 },
460         {"mathring",       ring,       0 },
461
462         // Dots
463         {"dots",           hline3,     0 },
464         {"ldots",          hline3,     0 },
465         {"cdots",          hline3,     0 },
466         {"vdots",          hline3,     1 },
467         {"ddots",          dline3,     0 },
468         {"adots",          dline3,     1 },
469         {"iddots",         dline3,     1 },
470         {"dotsb",          hline3,     0 },
471         {"dotsc",          hline3,     0 },
472         {"dotsi",          hline3,     0 },
473         {"dotsm",          hline3,     0 },
474         {"dotso",          hline3,     0 }
475 };
476
477
478 map<docstring, deco_struct> deco_list;
479
480 // sort the table on startup
481 class init_deco_table {
482 public:
483         init_deco_table() {
484                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
485                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
486                         deco_struct d;
487                         d.data  = p->data;
488                         d.angle = p->angle;
489                         deco_list[from_ascii(p->name)] = d;
490                 }
491         }
492 };
493
494 static init_deco_table dummy;
495
496
497 deco_struct const * search_deco(docstring const & name)
498 {
499         map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
500         return p == deco_list.end() ? 0 : &(p->second);
501 }
502
503
504 } // namespace anon
505
506
507 int mathed_font_em(FontInfo const & font)
508 {
509         return theFontMetrics(font).em();
510 }
511
512 /* The math units. Quoting TeX by Topic, p.205:
513  *
514  * Spacing around mathematical objects is measured in mu units. A mu
515  * is 1/18th part of \fontdimen6 of the font in family 2 in the
516  * current style, the ‘quad’ value of the symbol font.
517  *
518  * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
519  * inserted around (binary) relations, except where these are preceded
520  * or followed by other relations or punctuation, and except if they
521  * follow an open, or precede a close symbol.
522  *
523  * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
524  * is put around binary operators.
525  *
526  * A \thinmuskip (default value in plain TeX: 3mu) follows after
527  * punctuation, and is put around inner objects, except where these
528  * are followed by a close or preceded by an open symbol, and except
529  * if the other object is a large operator or a binary relation.
530  */
531
532 int mathed_thinmuskip(FontInfo font)
533 {
534         font.setFamily(SYMBOL_FAMILY);
535         return support::iround(3.0 / 18 * theFontMetrics(font).em());
536 }
537
538
539 int mathed_medmuskip(FontInfo font)
540 {
541         font.setFamily(SYMBOL_FAMILY);
542         return support::iround(4.0 / 18 * theFontMetrics(font).em());
543 }
544
545
546 int mathed_thickmuskip(FontInfo font)
547 {
548         font.setFamily(SYMBOL_FAMILY);
549         return support::iround(5.0 / 18 * theFontMetrics(font).em());
550 }
551
552
553 int mathed_char_width(FontInfo const & font, char_type c)
554 {
555         return theFontMetrics(font).width(c);
556 }
557
558
559 int mathed_char_kerning(FontInfo const & font, char_type c)
560 {
561         frontend::FontMetrics const & fm = theFontMetrics(font);
562         return fm.rbearing(c) - fm.width(c);
563 }
564
565
566 void mathed_string_dim(FontInfo const & font,
567                        docstring const & s,
568                        Dimension & dim)
569 {
570         frontend::FontMetrics const & fm = theFontMetrics(font);
571         dim.asc = 0;
572         dim.des = 0;
573         for (docstring::const_iterator it = s.begin();
574              it != s.end();
575              ++it) {
576                 dim.asc = max(dim.asc, fm.ascent(*it));
577                 dim.des = max(dim.des, fm.descent(*it));
578         }
579         dim.wid = fm.width(s);
580 }
581
582
583 int mathed_string_width(FontInfo const & font, docstring const & s)
584 {
585         return theFontMetrics(font).width(s);
586 }
587
588
589 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
590         docstring const & name)
591 {
592         if (name == ".") {
593                 pi.pain.line(x + w/2, y, x + w/2, y + h,
594                           Color_cursor, Painter::line_onoffdash);
595                 return;
596         }
597
598         deco_struct const * mds = search_deco(name);
599         if (!mds) {
600                 lyxerr << "Deco was not found. Programming error?" << endl;
601                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
602                 return;
603         }
604
605         int const n = (w < h) ? w : h;
606         int const r = mds->angle;
607         double const * d = mds->data;
608
609         if (h > 70 && (name == "(" || name == ")"))
610                 d = parenthHigh;
611
612         Matrix mt(r, w, h);
613         Matrix sqmt(r, n, n);
614
615         if (r > 0 && r < 3)
616                 y += h;
617
618         if (r >= 2)
619                 x += w;
620
621         for (int i = 0; d[i]; ) {
622                 int code = int(d[i++]);
623                 if (code & 1) {  // code == 1 || code == 3
624                         double xx = d[i++];
625                         double yy = d[i++];
626                         double x2 = d[i++];
627                         double y2 = d[i++];
628                         if (code == 3)
629                                 sqmt.transform(xx, yy);
630                         else
631                                 mt.transform(xx, yy);
632                         mt.transform(x2, y2);
633                         pi.pain.line(
634                                 int(x + xx + 0.5), int(y + yy + 0.5),
635                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
636                                 pi.base.font.color());
637                 } else {
638                         int xp[32];
639                         int yp[32];
640                         int const n = int(d[i++]);
641                         for (int j = 0; j < n; ++j) {
642                                 double xx = d[i++];
643                                 double yy = d[i++];
644 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
645                                 if (code == 4)
646                                         sqmt.transform(xx, yy);
647                                 else
648                                         mt.transform(xx, yy);
649                                 xp[j] = int(x + xx + 0.5);
650                                 yp[j] = int(y + yy + 0.5);
651                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
652                         }
653                         pi.pain.lines(xp, yp, n, pi.base.font.color());
654                 }
655         }
656 }
657
658
659 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
660 {
661         FontInfo font = mi.base.font;
662         augmentFont(font, "mathnormal");
663         mathed_string_dim(font, str, dim);
664 }
665
666
667 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
668 {
669         FontInfo f = pi.base.font;
670         augmentFont(f, "mathnormal");
671         f.setColor(Color_latex);
672         pi.pain.text(x, y, str, f);
673 }
674
675
676 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
677 {
678         FontInfo f = pi.base.font;
679         augmentFont(f, "mathnormal");
680         f.setColor(Color_foreground);
681         pi.pain.text(x, y, str, f);
682 }
683
684
685 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
686 {
687         frontend::FontMetrics const & fm = theFontMetrics(font);
688         asc = fm.maxAscent();
689         des = fm.maxDescent();
690 }
691
692
693 struct fontinfo {
694         string cmd_;
695         FontFamily family_;
696         FontSeries series_;
697         FontShape  shape_;
698         ColorCode        color_;
699 };
700
701
702 FontFamily const inh_family = INHERIT_FAMILY;
703 FontSeries const inh_series = INHERIT_SERIES;
704 FontShape  const inh_shape  = INHERIT_SHAPE;
705
706
707 // mathnormal should be the first, otherwise the fallback further down
708 // does not work
709 fontinfo fontinfos[] = {
710         // math fonts
711         {"mathnormal",    ROMAN_FAMILY, MEDIUM_SERIES,
712                           ITALIC_SHAPE, Color_math},
713         {"mathbf",        inh_family, BOLD_SERIES,
714                           inh_shape, Color_math},
715         {"mathcal",       CMSY_FAMILY, inh_series,
716                           inh_shape, Color_math},
717         {"mathfrak",      EUFRAK_FAMILY, inh_series,
718                           inh_shape, Color_math},
719         {"mathrm",        ROMAN_FAMILY, inh_series,
720                           UP_SHAPE, Color_math},
721         {"mathsf",        SANS_FAMILY, inh_series,
722                           inh_shape, Color_math},
723         {"mathbb",        MSB_FAMILY, inh_series,
724                           inh_shape, Color_math},
725         {"mathtt",        TYPEWRITER_FAMILY, inh_series,
726                           inh_shape, Color_math},
727         {"mathit",        inh_family, inh_series,
728                           ITALIC_SHAPE, Color_math},
729         {"mathscr",       RSFS_FAMILY, inh_series,
730                           inh_shape, Color_math},
731         {"cmex",          CMEX_FAMILY, inh_series,
732                           inh_shape, Color_math},
733         {"cmm",           CMM_FAMILY, inh_series,
734                           inh_shape, Color_math},
735         {"cmr",           CMR_FAMILY, inh_series,
736                           inh_shape, Color_math},
737         {"cmsy",          CMSY_FAMILY, inh_series,
738                           inh_shape, Color_math},
739         {"eufrak",        EUFRAK_FAMILY, inh_series,
740                           inh_shape, Color_math},
741         {"msa",           MSA_FAMILY, inh_series,
742                           inh_shape, Color_math},
743         {"msb",           MSB_FAMILY, inh_series,
744                           inh_shape, Color_math},
745         {"stmry",         STMARY_FAMILY, inh_series,
746                           inh_shape, Color_math},
747         {"wasy",          WASY_FAMILY, inh_series,
748                           inh_shape, Color_math},
749         {"esint",         ESINT_FAMILY, inh_series,
750                           inh_shape, Color_math},
751
752         // Text fonts
753         {"text",          inh_family, inh_series,
754                           inh_shape, Color_foreground},
755         {"textbf",        inh_family, BOLD_SERIES,
756                           inh_shape, Color_foreground},
757         {"textit",        inh_family, inh_series,
758                           ITALIC_SHAPE, Color_foreground},
759         {"textmd",        inh_family, MEDIUM_SERIES,
760                           inh_shape, Color_foreground},
761         {"textnormal",    inh_family, inh_series,
762                           UP_SHAPE, Color_foreground},
763         {"textrm",        ROMAN_FAMILY,
764                           inh_series, UP_SHAPE,Color_foreground},
765         {"textsc",        inh_family, inh_series,
766                           SMALLCAPS_SHAPE, Color_foreground},
767         {"textsf",        SANS_FAMILY, inh_series,
768                           inh_shape, Color_foreground},
769         {"textsl",        inh_family, inh_series,
770                           SLANTED_SHAPE, Color_foreground},
771         {"texttt",        TYPEWRITER_FAMILY, inh_series,
772                           inh_shape, Color_foreground},
773         {"textup",        inh_family, inh_series,
774                           UP_SHAPE, Color_foreground},
775
776         // TIPA support
777         {"textipa",       inh_family, inh_series,
778                           inh_shape, Color_foreground},
779
780         // mhchem support
781         {"ce",            inh_family, inh_series,
782                           inh_shape, Color_foreground},
783         {"cf",            inh_family, inh_series,
784                           inh_shape, Color_foreground},
785
786         // LyX internal usage
787         {"lyxtex",        inh_family, inh_series,
788                           UP_SHAPE, Color_latex},
789         // FIXME: The following two don't work on OS X, since the Symbol font
790         //        uses a different encoding, and is therefore disabled in
791         //        FontLoader::available().
792         {"lyxsymbol",     SYMBOL_FAMILY, inh_series,
793                           inh_shape, Color_math},
794         {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
795                           inh_shape, Color_math},
796         {"lyxblacktext",  ROMAN_FAMILY, MEDIUM_SERIES,
797                           UP_SHAPE, Color_foreground},
798         {"lyxnochange",   inh_family, inh_series,
799                           inh_shape, Color_foreground},
800         {"lyxfakebb",     TYPEWRITER_FAMILY, BOLD_SERIES,
801                           UP_SHAPE, Color_math},
802         {"lyxfakecal",    SANS_FAMILY, MEDIUM_SERIES,
803                           ITALIC_SHAPE, Color_math},
804         {"lyxfakefrak",   ROMAN_FAMILY, BOLD_SERIES,
805                           ITALIC_SHAPE, Color_math}
806 };
807
808
809 fontinfo * lookupFont(string const & name)
810 {
811         //lyxerr << "searching font '" << name << "'" << endl;
812         int const n = sizeof(fontinfos) / sizeof(fontinfo);
813         for (int i = 0; i < n; ++i)
814                 if (fontinfos[i].cmd_ == name) {
815                         //lyxerr << "found '" << i << "'" << endl;
816                         return fontinfos + i;
817                 }
818         return 0;
819 }
820
821
822 fontinfo * searchFont(string const & name)
823 {
824         fontinfo * f = lookupFont(name);
825         return f ? f : fontinfos;
826         // this should be mathnormal
827         //return searchFont("mathnormal");
828 }
829
830
831 bool isFontName(string const & name)
832 {
833         return lookupFont(name);
834 }
835
836
837 bool isMathFont(string const & name)
838 {
839         fontinfo * f = lookupFont(name);
840         return f && f->color_ == Color_math;
841 }
842
843
844 bool isTextFont(string const & name)
845 {
846         fontinfo * f = lookupFont(name);
847         return f && f->color_ == Color_foreground;
848 }
849
850
851 FontInfo getFont(string const & name)
852 {
853         FontInfo font;
854         augmentFont(font, name);
855         return font;
856 }
857
858
859 void fakeFont(string const & orig, string const & fake)
860 {
861         fontinfo * forig = searchFont(orig);
862         fontinfo * ffake = searchFont(fake);
863         if (forig && ffake) {
864                 forig->family_ = ffake->family_;
865                 forig->series_ = ffake->series_;
866                 forig->shape_  = ffake->shape_;
867                 forig->color_  = ffake->color_;
868         } else {
869                 lyxerr << "Can't fake font '" << orig << "' with '"
870                        << fake << "'" << endl;
871         }
872 }
873
874
875 void augmentFont(FontInfo & font, string const & name)
876 {
877         static bool initialized = false;
878         if (!initialized) {
879                 initialized = true;
880                 // fake fonts if necessary
881                 if (!theFontLoader().available(getFont("mathfrak")))
882                         fakeFont("mathfrak", "lyxfakefrak");
883                 if (!theFontLoader().available(getFont("mathcal")))
884                         fakeFont("mathcal", "lyxfakecal");
885         }
886         fontinfo * info = searchFont(name);
887         if (info->family_ != inh_family)
888                 font.setFamily(info->family_);
889         if (info->series_ != inh_series)
890                 font.setSeries(info->series_);
891         if (info->shape_ != inh_shape)
892                 font.setShape(info->shape_);
893         if (info->color_ != Color_none)
894                 font.setColor(info->color_);
895 }
896
897
898 bool isAlphaSymbol(MathAtom const & at)
899 {
900         if (at->asCharInset() ||
901             (at->asSymbolInset() &&
902              at->asSymbolInset()->isOrdAlpha()))
903                 return true;
904
905         if (at->asFontInset()) {
906                 MathData const & ar = at->asFontInset()->cell(0);
907                 for (size_t i = 0; i < ar.size(); ++i) {
908                         if (!(ar[i]->asCharInset() ||
909                               (ar[i]->asSymbolInset() &&
910                                ar[i]->asSymbolInset()->isOrdAlpha())))
911                                 return false;
912                 }
913                 return true;
914         }
915         return false;
916 }
917
918
919 docstring asString(MathData const & ar)
920 {
921         odocstringstream os;
922         otexrowstream ots(os);
923         WriteStream ws(ots);
924         ws << ar;
925         return os.str();
926 }
927
928
929 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
930 {
931         bool quiet = pf & Parse::QUIET;
932         if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
933                 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
934 }
935
936
937 docstring asString(InsetMath const & inset)
938 {
939         odocstringstream os;
940         otexrowstream ots(os);
941         WriteStream ws(ots);
942         inset.write(ws);
943         return os.str();
944 }
945
946
947 docstring asString(MathAtom const & at)
948 {
949         odocstringstream os;
950         otexrowstream ots(os);
951         WriteStream ws(ots);
952         at->write(ws);
953         return os.str();
954 }
955
956
957 } // namespace lyx