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