]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.cpp
Bulk cleanup/fix incorrect annotation at the end of namespaces.
[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;
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 /* The math units. Quoting TeX by Topic, p.205:
517  *
518  * Spacing around mathematical objects is measured in mu units. A mu
519  * is 1/18th part of \fontdimen6 of the font in family 2 in the
520  * current style, the ‘quad’ value of the symbol font.
521  *
522  * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
523  * inserted around (binary) relations, except where these are preceded
524  * or followed by other relations or punctuation, and except if they
525  * follow an open, or precede a close symbol.
526  *
527  * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
528  * is put around binary operators.
529  *
530  * A \thinmuskip (default value in plain TeX: 3mu) follows after
531  * punctuation, and is put around inner objects, except where these
532  * are followed by a close or preceded by an open symbol, and except
533  * if the other object is a large operator or a binary relation.
534  *
535  * See the file MathClass.cpp for a formal implementation of the rules
536  * above.
537  */
538
539 int mathed_mu(FontInfo const & font, double mu)
540 {
541         MetricsBase mb(nullptr, font);
542         return Length(mu, Length::MU).inPixels(mb);
543 }
544
545 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
546 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
547 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
548
549
550 int mathed_char_width(FontInfo const & font, char_type c)
551 {
552         return theFontMetrics(font).width(c);
553 }
554
555
556 int mathed_char_kerning(FontInfo const & font, char_type c)
557 {
558         frontend::FontMetrics const & fm = theFontMetrics(font);
559         return max(0, fm.rbearing(c) - fm.width(c));
560 }
561
562
563 void mathed_string_dim(FontInfo const & font,
564                        docstring const & s,
565                        Dimension & dim)
566 {
567         frontend::FontMetrics const & fm = theFontMetrics(font);
568         dim.asc = 0;
569         dim.des = 0;
570         for (docstring::const_iterator it = s.begin();
571              it != s.end();
572              ++it) {
573                 dim.asc = max(dim.asc, fm.ascent(*it));
574                 dim.des = max(dim.des, fm.descent(*it));
575         }
576         dim.wid = fm.width(s);
577 }
578
579
580 int mathed_string_width(FontInfo const & font, docstring const & s)
581 {
582         return theFontMetrics(font).width(s);
583 }
584
585
586 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
587         docstring const & name)
588 {
589         if (name == ".") {
590                 pi.pain.line(x + w/2, y, x + w/2, y + h,
591                           Color_cursor, Painter::line_onoffdash);
592                 return;
593         }
594
595         deco_struct const * mds = search_deco(name);
596         if (!mds) {
597                 lyxerr << "Deco was not found. Programming error?" << endl;
598                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
599                 return;
600         }
601
602         int const n = (w < h) ? w : h;
603         int const r = mds->angle;
604         double const * d = mds->data;
605
606         if (h > 70 && (name == "(" || name == ")"))
607                 d = parenthHigh;
608
609         Matrix mt(r, w, h);
610         Matrix sqmt(r, n, n);
611
612         if (r > 0 && r < 3)
613                 y += h;
614
615         if (r >= 2)
616                 x += w;
617
618         for (int i = 0; d[i]; ) {
619                 int code = int(d[i++]);
620                 if (code & 1) {  // code == 1 || code == 3
621                         double xx = d[i++];
622                         double yy = d[i++];
623                         double x2 = d[i++];
624                         double y2 = d[i++];
625                         if (code == 3)
626                                 sqmt.transform(xx, yy);
627                         else
628                                 mt.transform(xx, yy);
629                         mt.transform(x2, y2);
630                         pi.pain.line(
631                                 int(x + xx + 0.5), int(y + yy + 0.5),
632                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
633                                 pi.base.font.color());
634                 } else {
635                         int xp[32];
636                         int yp[32];
637                         int const n = int(d[i++]);
638                         for (int j = 0; j < n; ++j) {
639                                 double xx = d[i++];
640                                 double yy = d[i++];
641 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
642                                 if (code == 4)
643                                         sqmt.transform(xx, yy);
644                                 else
645                                         mt.transform(xx, yy);
646                                 xp[j] = int(x + xx + 0.5);
647                                 yp[j] = int(y + yy + 0.5);
648                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
649                         }
650                         pi.pain.lines(xp, yp, n, pi.base.font.color());
651                 }
652         }
653 }
654
655
656 void mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
657 {
658         LASSERT((bool)sym, return);
659         //lyxerr << "metrics: symbol: '" << sym->name
660         //      << "' in font: '" << sym->inset
661         //      << "' drawn as: '" << sym->draw
662         //      << "'" << endl;
663
664         bool const italic_upcase_greek = sym->inset == "cmr" &&
665                 sym->extra == "mathalpha" &&
666                 mb.fontname == "mathit";
667         std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
668         Changer dummy = mb.changeFontSet(font);
669         mathed_string_dim(mb.font, sym->draw, dim);
670 }
671
672
673 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
674 {
675         LASSERT((bool)sym, return);
676         //lyxerr << "drawing: symbol: '" << sym->name
677         //      << "' in font: '" << sym->inset
678         //      << "' drawn as: '" << sym->draw
679         //      << "'" << endl;
680
681         bool const italic_upcase_greek = sym->inset == "cmr" &&
682                 sym->extra == "mathalpha" &&
683                 pi.base.fontname == "mathit";
684         std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
685
686         Changer dummy = pi.base.changeFontSet(font);
687         pi.draw(x, y, sym->draw);
688 }
689
690
691 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
692 {
693         FontInfo font = mi.base.font;
694         augmentFont(font, "mathnormal");
695         mathed_string_dim(font, str, dim);
696 }
697
698
699 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
700 {
701         FontInfo f = pi.base.font;
702         augmentFont(f, "mathnormal");
703         f.setColor(Color_latex);
704         pi.pain.text(x, y, str, f);
705 }
706
707
708 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
709 {
710         FontInfo f = pi.base.font;
711         augmentFont(f, "mathnormal");
712         f.setColor(Color_foreground);
713         pi.pain.text(x, y, str, f);
714 }
715
716
717 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
718 {
719         frontend::FontMetrics const & fm = theFontMetrics(font);
720         asc = fm.maxAscent();
721         des = fm.maxDescent();
722 }
723
724
725 struct fontinfo {
726         string cmd_;
727         FontFamily family_;
728         FontSeries series_;
729         FontShape  shape_;
730         ColorCode        color_;
731 };
732
733
734 FontFamily const inh_family = INHERIT_FAMILY;
735 FontSeries const inh_series = INHERIT_SERIES;
736 FontShape  const inh_shape  = INHERIT_SHAPE;
737
738
739 // mathnormal should be the first, otherwise the fallback further down
740 // does not work
741 fontinfo fontinfos[] = {
742         // math fonts
743         // Color_math determines which fonts are math (see isMathFont)
744         {"mathnormal",    ROMAN_FAMILY, MEDIUM_SERIES,
745                           ITALIC_SHAPE, Color_math},
746         {"mathbf",        inh_family, BOLD_SERIES,
747                           inh_shape, Color_math},
748         {"mathcal",       CMSY_FAMILY, inh_series,
749                           inh_shape, Color_math},
750         {"mathfrak",      EUFRAK_FAMILY, inh_series,
751                           inh_shape, Color_math},
752         {"mathrm",        ROMAN_FAMILY, inh_series,
753                           UP_SHAPE, Color_math},
754         {"mathsf",        SANS_FAMILY, inh_series,
755                           inh_shape, Color_math},
756         {"mathbb",        MSB_FAMILY, inh_series,
757                           inh_shape, Color_math},
758         {"mathtt",        TYPEWRITER_FAMILY, inh_series,
759                           inh_shape, Color_math},
760         {"mathit",        inh_family, inh_series,
761                           ITALIC_SHAPE, Color_math},
762         {"mathscr",       RSFS_FAMILY, inh_series,
763                           inh_shape, Color_math},
764         {"cmex",          CMEX_FAMILY, inh_series,
765                           inh_shape, Color_math},
766         {"cmm",           CMM_FAMILY, inh_series,
767                           inh_shape, Color_math},
768         {"cmr",           CMR_FAMILY, inh_series,
769                           inh_shape, Color_math},
770         {"cmsy",          CMSY_FAMILY, inh_series,
771                           inh_shape, Color_math},
772         {"eufrak",        EUFRAK_FAMILY, inh_series,
773                           inh_shape, Color_math},
774         {"msa",           MSA_FAMILY, inh_series,
775                           inh_shape, Color_math},
776         {"msb",           MSB_FAMILY, inh_series,
777                           inh_shape, Color_math},
778         {"stmry",         STMARY_FAMILY, inh_series,
779                           inh_shape, Color_math},
780         {"wasy",          WASY_FAMILY, inh_series,
781                           inh_shape, Color_math},
782         {"esint",         ESINT_FAMILY, inh_series,
783                           inh_shape, Color_math},
784
785         // Text fonts
786         {"text",          inh_family, inh_series,
787                           inh_shape, Color_foreground},
788         {"textbf",        inh_family, BOLD_SERIES,
789                           inh_shape, Color_foreground},
790         {"textit",        inh_family, inh_series,
791                           ITALIC_SHAPE, Color_foreground},
792         {"textmd",        inh_family, MEDIUM_SERIES,
793                           inh_shape, Color_foreground},
794         {"textnormal",    inh_family, inh_series,
795                           UP_SHAPE, Color_foreground},
796         {"textrm",        ROMAN_FAMILY,
797                           inh_series, UP_SHAPE,Color_foreground},
798         {"textsc",        inh_family, inh_series,
799                           SMALLCAPS_SHAPE, Color_foreground},
800         {"textsf",        SANS_FAMILY, inh_series,
801                           inh_shape, Color_foreground},
802         {"textsl",        inh_family, inh_series,
803                           SLANTED_SHAPE, Color_foreground},
804         {"texttt",        TYPEWRITER_FAMILY, inh_series,
805                           inh_shape, Color_foreground},
806         {"textup",        inh_family, inh_series,
807                           UP_SHAPE, Color_foreground},
808
809         // TIPA support
810         {"textipa",       inh_family, inh_series,
811                           inh_shape, Color_foreground},
812
813         // mhchem support
814         {"ce",            inh_family, inh_series,
815                           inh_shape, Color_foreground},
816         {"cf",            inh_family, inh_series,
817                           inh_shape, Color_foreground},
818
819         // LyX internal usage
820         {"lyxtex",        inh_family, inh_series,
821                           UP_SHAPE, Color_latex},
822         // FIXME: The following two don't work on OS X, since the Symbol font
823         //        uses a different encoding, and is therefore disabled in
824         //        FontLoader::available().
825         {"lyxsymbol",     SYMBOL_FAMILY, inh_series,
826                           inh_shape, Color_math},
827         {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
828                           inh_shape, Color_math},
829         {"lyxblacktext",  ROMAN_FAMILY, MEDIUM_SERIES,
830                           UP_SHAPE, Color_foreground},
831         {"lyxnochange",   inh_family, inh_series,
832                           inh_shape, Color_foreground},
833         {"lyxfakebb",     TYPEWRITER_FAMILY, BOLD_SERIES,
834                           UP_SHAPE, Color_math},
835         {"lyxfakecal",    SANS_FAMILY, MEDIUM_SERIES,
836                           ITALIC_SHAPE, Color_math},
837         {"lyxfakefrak",   ROMAN_FAMILY, BOLD_SERIES,
838                           ITALIC_SHAPE, Color_math}
839 };
840
841
842 fontinfo * lookupFont(string const & name)
843 {
844         //lyxerr << "searching font '" << name << "'" << endl;
845         int const n = sizeof(fontinfos) / sizeof(fontinfo);
846         for (int i = 0; i < n; ++i)
847                 if (fontinfos[i].cmd_ == name) {
848                         //lyxerr << "found '" << i << "'" << endl;
849                         return fontinfos + i;
850                 }
851         return 0;
852 }
853
854
855 fontinfo * searchFont(string const & name)
856 {
857         fontinfo * f = lookupFont(name);
858         return f ? f : fontinfos;
859         // this should be mathnormal
860         //return searchFont("mathnormal");
861 }
862
863
864 bool isFontName(string const & name)
865 {
866         return lookupFont(name);
867 }
868
869
870 bool isMathFont(string const & name)
871 {
872         fontinfo * f = lookupFont(name);
873         return f && f->color_ == Color_math;
874 }
875
876
877 bool isTextFont(string const & name)
878 {
879         fontinfo * f = lookupFont(name);
880         return f && f->color_ == Color_foreground;
881 }
882
883
884 FontInfo getFont(string const & name)
885 {
886         FontInfo font;
887         augmentFont(font, name);
888         return font;
889 }
890
891
892 void fakeFont(string const & orig, string const & fake)
893 {
894         fontinfo * forig = searchFont(orig);
895         fontinfo * ffake = searchFont(fake);
896         if (forig && ffake) {
897                 forig->family_ = ffake->family_;
898                 forig->series_ = ffake->series_;
899                 forig->shape_  = ffake->shape_;
900                 forig->color_  = ffake->color_;
901         } else {
902                 lyxerr << "Can't fake font '" << orig << "' with '"
903                        << fake << "'" << endl;
904         }
905 }
906
907
908 void augmentFont(FontInfo & font, string const & name)
909 {
910         static bool initialized = false;
911         if (!initialized) {
912                 initialized = true;
913                 // fake fonts if necessary
914                 if (!theFontLoader().available(getFont("mathfrak")))
915                         fakeFont("mathfrak", "lyxfakefrak");
916                 if (!theFontLoader().available(getFont("mathcal")))
917                         fakeFont("mathcal", "lyxfakecal");
918         }
919         fontinfo * info = searchFont(name);
920         if (info->family_ != inh_family)
921                 font.setFamily(info->family_);
922         if (info->series_ != inh_series)
923                 font.setSeries(info->series_);
924         if (info->shape_ != inh_shape)
925                 font.setShape(info->shape_);
926         if (info->color_ != Color_none)
927                 font.setColor(info->color_);
928 }
929
930
931 bool isAlphaSymbol(MathAtom const & at)
932 {
933         if (at->asCharInset() ||
934             (at->asSymbolInset() &&
935              at->asSymbolInset()->isOrdAlpha()))
936                 return true;
937
938         if (at->asFontInset()) {
939                 MathData const & ar = at->asFontInset()->cell(0);
940                 for (size_t i = 0; i < ar.size(); ++i) {
941                         if (!(ar[i]->asCharInset() ||
942                               (ar[i]->asSymbolInset() &&
943                                ar[i]->asSymbolInset()->isOrdAlpha())))
944                                 return false;
945                 }
946                 return true;
947         }
948         return false;
949 }
950
951
952 docstring asString(MathData const & ar)
953 {
954         odocstringstream os;
955         otexrowstream ots(os);
956         WriteStream ws(ots);
957         ws << ar;
958         return os.str();
959 }
960
961
962 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
963 {
964         // If the QUIET flag is set, we are going to parse for either
965         // a paste operation or a macro definition. We try to do the
966         // right thing in all cases.
967
968         bool quiet = pf & Parse::QUIET;
969         bool macro = pf & Parse::MACRODEF;
970         if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
971                 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
972 }
973
974
975 docstring asString(InsetMath const & inset)
976 {
977         odocstringstream os;
978         otexrowstream ots(os);
979         WriteStream ws(ots);
980         inset.write(ws);
981         return os.str();
982 }
983
984
985 docstring asString(MathAtom const & at)
986 {
987         odocstringstream os;
988         otexrowstream ots(os);
989         WriteStream ws(ots);
990         at->write(ws);
991         return os.str();
992 }
993
994
995 int axis_height(MetricsBase & mb)
996 {
997         Changer dummy = mb.changeFontSet("mathnormal");
998         return theFontMetrics(mb.font).ascent('-') - 1;
999 }
1000
1001
1002 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1003 {
1004         MathWordList const & words = mathedWordList();
1005         MathWordList::const_iterator it = words.find(word);
1006         if (it != words.end()) {
1007                 string const req = it->second.requires;
1008                 if (!req.empty())
1009                         features.require(req);
1010         }
1011 }
1012
1013
1014 } // namespace lyx