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