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