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