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