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