]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.cpp
tex2lyx: support for \item with opt arg in itemize environment
[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_char_width(FontInfo const & font, char_type c)
505 {
506         return theFontMetrics(font).width(c);
507 }
508
509
510 int mathed_char_kerning(FontInfo const & font, char_type c)
511 {
512         frontend::FontMetrics const & fm = theFontMetrics(font);
513         return fm.rbearing(c) - fm.width(c);
514 }
515
516
517 void mathed_string_dim(FontInfo const & font,
518                        docstring const & s,
519                        Dimension & dim)
520 {
521         frontend::FontMetrics const & fm = theFontMetrics(font);
522         dim.asc = 0;
523         dim.des = 0;
524         for (docstring::const_iterator it = s.begin();
525              it != s.end();
526              ++it) {
527                 dim.asc = max(dim.asc, fm.ascent(*it));
528                 dim.des = max(dim.des, fm.descent(*it));
529         }
530         dim.wid = fm.width(s);
531 }
532
533
534 int mathed_string_width(FontInfo const & font, docstring const & s)
535 {
536         return theFontMetrics(font).width(s);
537 }
538
539
540 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
541         docstring const & name)
542 {
543         if (name == ".") {
544                 pi.pain.line(x + w/2, y, x + w/2, y + h,
545                           Color_cursor, Painter::line_onoffdash);
546                 return;
547         }
548
549         deco_struct const * mds = search_deco(name);
550         if (!mds) {
551                 lyxerr << "Deco was not found. Programming error?" << endl;
552                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
553                 return;
554         }
555
556         int const n = (w < h) ? w : h;
557         int const r = mds->angle;
558         double const * d = mds->data;
559
560         if (h > 70 && (name == "(" || name == ")"))
561                 d = parenthHigh;
562
563         Matrix mt(r, w, h);
564         Matrix sqmt(r, n, n);
565
566         if (r > 0 && r < 3)
567                 y += h;
568
569         if (r >= 2)
570                 x += w;
571
572         for (int i = 0; d[i]; ) {
573                 int code = int(d[i++]);
574                 if (code & 1) {  // code == 1 || code == 3
575                         double xx = d[i++];
576                         double yy = d[i++];
577                         double x2 = d[i++];
578                         double y2 = d[i++];
579                         if (code == 3)
580                                 sqmt.transform(xx, yy);
581                         else
582                                 mt.transform(xx, yy);
583                         mt.transform(x2, y2);
584                         pi.pain.line(
585                                 int(x + xx + 0.5), int(y + yy + 0.5),
586                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
587                                 pi.base.font.color());
588                 } else {
589                         int xp[32];
590                         int yp[32];
591                         int const n = int(d[i++]);
592                         for (int j = 0; j < n; ++j) {
593                                 double xx = d[i++];
594                                 double yy = d[i++];
595 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
596                                 if (code == 4)
597                                         sqmt.transform(xx, yy);
598                                 else
599                                         mt.transform(xx, yy);
600                                 xp[j] = int(x + xx + 0.5);
601                                 yp[j] = int(y + yy + 0.5);
602                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
603                         }
604                         pi.pain.lines(xp, yp, n, pi.base.font.color());
605                 }
606         }
607 }
608
609
610 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
611 {
612         FontInfo font = mi.base.font;
613         augmentFont(font, from_ascii("mathnormal"));
614         mathed_string_dim(font, str, dim);
615 }
616
617
618 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
619 {
620         FontInfo f = pi.base.font;
621         augmentFont(f, from_ascii("mathnormal"));
622         f.setColor(Color_latex);
623         pi.pain.text(x, y, str, f);
624 }
625
626
627 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
628 {
629         FontInfo f = pi.base.font;
630         augmentFont(f, from_ascii("mathnormal"));
631         f.setColor(Color_foreground);
632         pi.pain.text(x, y, str, f);
633 }
634
635
636 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
637 {
638         frontend::FontMetrics const & fm = theFontMetrics(font);
639         asc = fm.maxAscent();
640         des = fm.maxDescent();
641 }
642
643
644 struct fontinfo {
645         string cmd_;
646         FontFamily family_;
647         FontSeries series_;
648         FontShape  shape_;
649         ColorCode        color_;
650 };
651
652
653 FontFamily const inh_family = INHERIT_FAMILY;
654 FontSeries const inh_series = INHERIT_SERIES;
655 FontShape  const inh_shape  = INHERIT_SHAPE;
656
657
658 // mathnormal should be the first, otherwise the fallback further down
659 // does not work
660 fontinfo fontinfos[] = {
661         // math fonts
662         {"mathnormal",    ROMAN_FAMILY, MEDIUM_SERIES,
663                           ITALIC_SHAPE, Color_math},
664         {"mathbf",        inh_family, BOLD_SERIES,
665                           inh_shape, Color_math},
666         {"mathcal",       CMSY_FAMILY, inh_series,
667                           inh_shape, Color_math},
668         {"mathfrak",      EUFRAK_FAMILY, inh_series,
669                           inh_shape, Color_math},
670         {"mathrm",        ROMAN_FAMILY, inh_series,
671                           UP_SHAPE, Color_math},
672         {"mathsf",        SANS_FAMILY, inh_series,
673                           inh_shape, Color_math},
674         {"mathbb",        MSB_FAMILY, inh_series,
675                           inh_shape, Color_math},
676         {"mathtt",        TYPEWRITER_FAMILY, inh_series,
677                           inh_shape, Color_math},
678         {"mathit",        inh_family, inh_series,
679                           ITALIC_SHAPE, Color_math},
680         {"mathscr",       RSFS_FAMILY, inh_series,
681                           inh_shape, Color_math},
682         {"cmex",          CMEX_FAMILY, inh_series,
683                           inh_shape, Color_math},
684         {"cmm",           CMM_FAMILY, inh_series,
685                           inh_shape, Color_math},
686         {"cmr",           CMR_FAMILY, inh_series,
687                           inh_shape, Color_math},
688         {"cmsy",          CMSY_FAMILY, inh_series,
689                           inh_shape, Color_math},
690         {"eufrak",        EUFRAK_FAMILY, inh_series,
691                           inh_shape, Color_math},
692         {"msa",           MSA_FAMILY, inh_series,
693                           inh_shape, Color_math},
694         {"msb",           MSB_FAMILY, inh_series,
695                           inh_shape, Color_math},
696         {"stmry",         STMARY_FAMILY, inh_series,
697                           inh_shape, Color_math},
698         {"wasy",          WASY_FAMILY, inh_series,
699                           inh_shape, Color_math},
700         {"esint",         ESINT_FAMILY, inh_series,
701                           inh_shape, Color_math},
702
703         // Text fonts
704         {"text",          inh_family, inh_series,
705                           inh_shape, Color_foreground},
706         {"textbf",        inh_family, BOLD_SERIES,
707                           inh_shape, Color_foreground},
708         {"textit",        inh_family, inh_series,
709                           ITALIC_SHAPE, Color_foreground},
710         {"textmd",        inh_family, MEDIUM_SERIES,
711                           inh_shape, Color_foreground},
712         {"textnormal",    inh_family, inh_series,
713                           UP_SHAPE, Color_foreground},
714         {"textrm",        ROMAN_FAMILY,
715                           inh_series, UP_SHAPE,Color_foreground},
716         {"textsc",        inh_family, inh_series,
717                           SMALLCAPS_SHAPE, Color_foreground},
718         {"textsf",        SANS_FAMILY, inh_series,
719                           inh_shape, Color_foreground},
720         {"textsl",        inh_family, inh_series,
721                           SLANTED_SHAPE, Color_foreground},
722         {"texttt",        TYPEWRITER_FAMILY, inh_series,
723                           inh_shape, Color_foreground},
724         {"textup",        inh_family, inh_series,
725                           UP_SHAPE, Color_foreground},
726
727         // TIPA support
728         {"textipa",       inh_family, inh_series,
729                           inh_shape, Color_foreground},
730
731         // mhchem support
732         {"ce",            inh_family, inh_series,
733                           inh_shape, Color_foreground},
734         {"cf",            inh_family, inh_series,
735                           inh_shape, Color_foreground},
736
737         // LyX internal usage
738         {"lyxtex",        inh_family, inh_series,
739                           UP_SHAPE, Color_latex},
740         // FIXME: The following two don't work on OS X, since the Symbol font
741         //        uses a different encoding, and is therefore disabled in
742         //        FontLoader::available().
743         {"lyxsymbol",     SYMBOL_FAMILY, inh_series,
744                           inh_shape, Color_math},
745         {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
746                           inh_shape, Color_math},
747         {"lyxblacktext",  ROMAN_FAMILY, MEDIUM_SERIES,
748                           UP_SHAPE, Color_foreground},
749         {"lyxnochange",   inh_family, inh_series,
750                           inh_shape, Color_foreground},
751         {"lyxfakebb",     TYPEWRITER_FAMILY, BOLD_SERIES,
752                           UP_SHAPE, Color_math},
753         {"lyxfakecal",    SANS_FAMILY, MEDIUM_SERIES,
754                           ITALIC_SHAPE, Color_math},
755         {"lyxfakefrak",   ROMAN_FAMILY, BOLD_SERIES,
756                           ITALIC_SHAPE, Color_math}
757 };
758
759
760 fontinfo * lookupFont(docstring const & name0)
761 {
762         //lyxerr << "searching font '" << name << "'" << endl;
763         int const n = sizeof(fontinfos) / sizeof(fontinfo);
764         string name = to_utf8(name0);
765         for (int i = 0; i < n; ++i)
766                 if (fontinfos[i].cmd_ == name) {
767                         //lyxerr << "found '" << i << "'" << endl;
768                         return fontinfos + i;
769                 }
770         return 0;
771 }
772
773
774 fontinfo * searchFont(docstring const & name)
775 {
776         fontinfo * f = lookupFont(name);
777         return f ? f : fontinfos;
778         // this should be mathnormal
779         //return searchFont("mathnormal");
780 }
781
782
783 bool isFontName(docstring const & name)
784 {
785         return lookupFont(name);
786 }
787
788
789 bool isMathFont(docstring const & name)
790 {
791         fontinfo * f = lookupFont(name);
792         return f && f->color_ == Color_math;
793 }
794
795
796 bool isTextFont(docstring const & name)
797 {
798         fontinfo * f = lookupFont(name);
799         return f && f->color_ == Color_foreground;
800 }
801
802
803 FontInfo getFont(docstring const & name)
804 {
805         FontInfo font;
806         augmentFont(font, name);
807         return font;
808 }
809
810
811 void fakeFont(docstring const & orig, docstring const & fake)
812 {
813         fontinfo * forig = searchFont(orig);
814         fontinfo * ffake = searchFont(fake);
815         if (forig && ffake) {
816                 forig->family_ = ffake->family_;
817                 forig->series_ = ffake->series_;
818                 forig->shape_  = ffake->shape_;
819                 forig->color_  = ffake->color_;
820         } else {
821                 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
822                        << to_utf8(fake) << "'" << endl;
823         }
824 }
825
826
827 void augmentFont(FontInfo & font, docstring const & name)
828 {
829         static bool initialized = false;
830         if (!initialized) {
831                 initialized = true;
832                 // fake fonts if necessary
833                 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
834                         fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
835                 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
836                         fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
837         }
838         fontinfo * info = searchFont(name);
839         if (info->family_ != inh_family)
840                 font.setFamily(info->family_);
841         if (info->series_ != inh_series)
842                 font.setSeries(info->series_);
843         if (info->shape_ != inh_shape)
844                 font.setShape(info->shape_);
845         if (info->color_ != Color_none)
846                 font.setColor(info->color_);
847 }
848
849
850 bool isAlphaSymbol(MathAtom const & at)
851 {
852         if (at->asCharInset() ||
853             (at->asSymbolInset() &&
854              at->asSymbolInset()->isOrdAlpha()))
855                 return true;
856
857         if (at->asFontInset()) {
858                 MathData const & ar = at->asFontInset()->cell(0);
859                 for (size_t i = 0; i < ar.size(); ++i) {
860                         if (!(ar[i]->asCharInset() ||
861                               (ar[i]->asSymbolInset() &&
862                                ar[i]->asSymbolInset()->isOrdAlpha())))
863                                 return false;
864                 }
865                 return true;
866         }
867         return false;
868 }
869
870
871 docstring asString(MathData const & ar)
872 {
873         odocstringstream os;
874         WriteStream ws(os);
875         ws << ar;
876         return os.str();
877 }
878
879
880 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
881 {
882         bool quiet = pf & Parse::QUIET;
883         if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
884                 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
885 }
886
887
888 docstring asString(InsetMath const & inset)
889 {
890         odocstringstream os;
891         WriteStream ws(os);
892         inset.write(ws);
893         return os.str();
894 }
895
896
897 docstring asString(MathAtom const & at)
898 {
899         odocstringstream os;
900         WriteStream ws(os);
901         at->write(ws);
902         return os.str();
903 }
904
905
906 } // namespace lyx