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