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