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