]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.cpp
FindAdv: Added handling of some chars found in unnicodesymbols
[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 dot[] = {
336         5, 0.5, 0.5, 0.1, 0.1,
337         0
338 };
339
340
341 double const ddot[] = {
342         5, 0.2, 0.5, 0.1, 0.1,
343         5, 0.7, 0.5, 0.1, 0.1,
344         0
345 };
346
347
348 double const dddot[] = {
349         5, 0.1, 0.5, 0.1, 0.1,
350         5, 0.5, 0.5, 0.1, 0.1,
351         5, 0.9, 0.5, 0.1, 0.1,
352         0
353 };
354
355
356 double const ddddot[] = {
357         5, -0.1, 0.5, 0.1, 0.1,
358         5,  0.3, 0.5, 0.1, 0.1,
359         5,  0.7, 0.5, 0.1, 0.1,
360         5,  1.1, 0.5, 0.1, 0.1,
361         0
362 };
363
364
365 double const hline3[] = {
366         5, 0.15, 0.0, 0.0625, 0.0625,
367         5, 0.50, 0.0, 0.0625, 0.0625,
368         5, 0.85, 0.0, 0.0625, 0.0625,
369         0
370 };
371
372
373 double const dline3[] = {
374         5, 0.25, 0.225, 0.0625, 0.0625,
375         5, 0.50, 0.475, 0.0625, 0.0625,
376         5, 0.75, 0.725, 0.0625, 0.0625,
377         0
378 };
379
380
381 double const ring[] = {
382         2, 13,
383         0.5000, 0.7750,  0.6375, 0.7375,  0.7375, 0.6375,  0.7750, 0.5000,
384         0.7375, 0.3625,  0.6375, 0.2625,  0.5000, 0.2250,  0.3625, 0.2625,
385         0.2625, 0.3625,  0.2250, 0.5000,  0.2625, 0.6375,  0.3625, 0.7375,
386         0.5000, 0.7750,
387         0
388 };
389
390
391 double const vert[] = {
392         1, 0.5, 0.05,  0.5, 0.95,
393         0
394 };
395
396
397 double const  Vert[] = {
398         1, 0.3, 0.05,  0.3, 0.95,
399         1, 0.7, 0.05,  0.7, 0.95,
400         0
401 };
402
403
404 double const tilde[] = {
405         2, 10,
406         0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
407         0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
408         0
409 };
410
411
412 struct deco_struct {
413         double const * data;
414         int angle;
415 };
416
417 struct named_deco_struct {
418         char const * name;
419         double const * data;
420         int angle;
421 };
422
423 named_deco_struct deco_table[] = {
424         // Decorations
425         {"widehat",             angle,        3 },
426         {"widetilde",           tilde,        0 },
427         {"underbar",            hline,        0 },
428         {"underline",           hline,        0 },
429         {"overline",            hline,        0 },
430         {"underbrace",          brace,        1 },
431         {"overbrace",           brace,        3 },
432         {"overleftarrow",       arrow,        1 },
433         {"overrightarrow",      arrow,        3 },
434         {"overleftrightarrow",  udarrow,      1 },
435         {"xhookleftarrow",      lhook,        0 },
436         {"xhookrightarrow",     rhook,        0 },
437         {"xleftarrow",          arrow,        1 },
438         {"xLeftarrow",          LArrow,       0 },
439         {"xleftharpoondown",    lharpoondown, 0 },
440         {"xleftharpoonup",      lharpoonup,   0 },
441         {"xleftrightharpoons",  lrharpoons,   0 },
442         {"xleftrightarrow",     udarrow,      1 },
443         {"xLeftrightarrow",     LRArrow,      0 },
444         {"xmapsto",             mapsto,       0 },
445         {"xrightarrow",         arrow,        3 },
446         {"xRightarrow",         LArrow,       2 },
447         {"xrightharpoondown",   lharpoonup,   2 },
448         {"xrightharpoonup",     lharpoondown, 2 },
449         {"xrightleftharpoons",  rlharpoons,   0 },
450         {"underleftarrow",      arrow,        1 },
451         {"underrightarrow",     arrow,        3 },
452         {"underleftrightarrow", udarrow,      1 },
453         {"undertilde",          tilde,        0 },
454         {"utilde",              tilde,        0 },
455
456         // Delimiters
457         {"(",              parenth,    0 },
458         {")",              parenth,    2 },
459         {"{",              brace,      0 },
460         {"}",              brace,      2 },
461         {"lbrace",         brace,      0 },
462         {"rbrace",         brace,      2 },
463         {"[",              brack,      0 },
464         {"]",              brack,      2 },
465         {"llbracket",      dbrack,     0 },
466         {"rrbracket",      dbrack,     2 },
467         {"|",              vert,       0 },
468         {"/",              slash,      0 },
469         {"slash",          slash,      0 },
470         {"vert",           vert,       0 },
471         {"lvert",          vert,       0 },
472         {"rvert",          vert,       0 },
473         {"Vert",           Vert,       0 },
474         {"lVert",          Vert,       0 },
475         {"rVert",          Vert,       0 },
476         {"'",              slash,      1 },
477         {"<",              angle,      0 },
478         {">",              angle,      2 },
479         {"\\",             slash,      1 },
480         {"backslash",      slash,      1 },
481         {"langle",         angle,      0 },
482         {"lceil",          corner,     0 },
483         {"lfloor",         corner,     1 },
484         {"rangle",         angle,      2 },
485         {"rceil",          corner,     3 },
486         {"rfloor",         corner,     2 },
487         {"downarrow",      arrow,      2 },
488         {"Downarrow",      Arrow,      2 },
489         {"uparrow",        arrow,      0 },
490         {"Uparrow",        Arrow,      0 },
491         {"updownarrow",    udarrow,    0 },
492         {"Updownarrow",    Udarrow,    0 },
493
494         // Accents
495         {"ddot",           ddot,       0 },
496         {"dddot",          dddot,      0 },
497         {"ddddot",         ddddot,     0 },
498         {"hat",            angle,      3 },
499         {"grave",          slash,      1 },
500         {"acute",          slash,      0 },
501         {"tilde",          tilde,      0 },
502         {"bar",            hline,      0 },
503         {"dot",            dot,        0 },
504         {"check",          angle,      1 },
505         {"breve",          breve,      0 },
506         {"vec",            vec,        3 },
507         {"mathring",       ring,       0 },
508
509         // Dots
510         {"dots",           hline3,     0 },
511         {"ldots",          hline3,     0 },
512         {"cdots",          hline3,     0 },
513         {"vdots",          hline3,     1 },
514         {"ddots",          dline3,     0 },
515         {"adots",          dline3,     1 },
516         {"iddots",         dline3,     1 },
517         {"dotsb",          hline3,     0 },
518         {"dotsc",          hline3,     0 },
519         {"dotsi",          hline3,     0 },
520         {"dotsm",          hline3,     0 },
521         {"dotso",          hline3,     0 }
522 };
523
524
525 map<docstring, deco_struct> deco_list;
526
527 // sort the table on startup
528 class init_deco_table {
529 public:
530         init_deco_table() {
531                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
532                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
533                         deco_struct d;
534                         d.data  = p->data;
535                         d.angle = p->angle;
536                         deco_list[from_ascii(p->name)] = d;
537                 }
538         }
539 };
540
541 static init_deco_table dummy_deco_table;
542
543
544 deco_struct const * search_deco(docstring const & name)
545 {
546         map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
547         return p == deco_list.end() ? 0 : &(p->second);
548 }
549
550
551 } // namespace
552
553
554 int mathed_font_em(FontInfo const & font)
555 {
556         return theFontMetrics(font).em();
557 }
558
559
560 int mathed_font_x_height(FontInfo const & font)
561 {
562         return theFontMetrics(font).xHeight();
563 }
564
565 /* The math units. Quoting TeX by Topic, p.205:
566  *
567  * Spacing around mathematical objects is measured in mu units. A mu
568  * is 1/18th part of \fontdimen6 of the font in family 2 in the
569  * current style, the ‘quad’ value of the symbol font.
570  *
571  * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
572  * inserted around (binary) relations, except where these are preceded
573  * or followed by other relations or punctuation, and except if they
574  * follow an open, or precede a close symbol.
575  *
576  * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
577  * is put around binary operators.
578  *
579  * A \thinmuskip (default value in plain TeX: 3mu) follows after
580  * punctuation, and is put around inner objects, except where these
581  * are followed by a close or preceded by an open symbol, and except
582  * if the other object is a large operator or a binary relation.
583  *
584  * See the file MathClass.cpp for a formal implementation of the rules
585  * above.
586  */
587
588 int mathed_mu(FontInfo const & font, double mu)
589 {
590         MetricsBase mb(nullptr, font);
591         return mb.inPixels(Length(mu, Length::MU));
592 }
593
594 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
595 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
596 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
597
598
599 int mathed_char_width(FontInfo const & font, char_type c)
600 {
601         return theFontMetrics(font).width(c);
602 }
603
604
605 int mathed_char_kerning(FontInfo const & font, char_type c)
606 {
607         frontend::FontMetrics const & fm = theFontMetrics(font);
608         return max(0, fm.rbearing(c) - fm.width(c));
609 }
610
611
612 double mathed_char_slope(MetricsBase const & mb, char_type c)
613 {
614         bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
615         if (slanted && mb.fontname == "mathnormal")
616                 return theFontMetrics(mb.font).italicSlope();
617         return 0.0;
618 }
619
620
621 void mathed_string_dim(FontInfo const & font,
622                        docstring const & s,
623                        Dimension & dim)
624 {
625         frontend::FontMetrics const & fm = theFontMetrics(font);
626         dim.asc = 0;
627         dim.des = 0;
628         for (char_type const c : s) {
629                 dim.asc = max(dim.asc, fm.ascent(c));
630                 dim.des = max(dim.des, fm.descent(c));
631         }
632         dim.wid = fm.width(s);
633 }
634
635
636 int mathed_string_width(FontInfo const & font, docstring const & s)
637 {
638         return theFontMetrics(font).width(s);
639 }
640
641
642 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
643         docstring const & name)
644 {
645         int const lw = pi.base.solidLineThickness();
646
647         if (name == ".") {
648                 pi.pain.line(x + w/2, y, x + w/2, y + h,
649                           Color_cursor, Painter::line_onoffdash, lw);
650                 return;
651         }
652
653         deco_struct const * mds = search_deco(name);
654         if (!mds) {
655                 lyxerr << "Deco was not found. Programming error?" << endl;
656                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
657                 return;
658         }
659
660         int const n = (w < h) ? w : h;
661         int const r = mds->angle;
662         double const * d = mds->data;
663
664         if (h > 70 && (name == "(" || name == ")"))
665                 d = parenthHigh;
666
667         Matrix mt(r, w, h);
668         Matrix sqmt(r, n, n);
669
670         if (r > 0 && r < 3)
671                 y += h;
672
673         if (r >= 2)
674                 x += w;
675
676         for (int i = 0; d[i]; ) {
677                 int code = int(d[i++]);
678                 if (code == 1 || code == 3) {
679                         double xx = d[i++];
680                         double yy = d[i++];
681                         double x2 = d[i++];
682                         double y2 = d[i++];
683                         if (code == 3)
684                                 sqmt.transform(xx, yy);
685                         else
686                                 mt.transform(xx, yy);
687                         mt.transform(x2, y2);
688                         pi.pain.line(
689                                 int(x + xx + 0.5), int(y + yy + 0.5),
690                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
691                                 pi.base.font.color(), Painter::line_solid, lw);
692                 } else if (code == 5) {
693                         double xx = d[i++];
694                         double yy = d[i++];
695                         double x2 = xx + d[i++];
696                         double y2 = yy + d[i++];
697                         mt.transform(xx, yy);
698                         mt.transform(x2, y2);
699                         double const xc = x + xx;
700                         double const yc = y + yy;
701                         double const rx = x2 - xx;
702                         double const ry = y2 - yy;
703                         pi.pain.ellipse(xc, yc, rx, ry,
704                                 pi.base.font.color(), Painter::fill_winding);
705                 } else {
706                         int xp[32];
707                         int yp[32];
708                         double xshift = (code == 6 ? d[i++] : 0.0);
709                         double yshift = (code == 6 ? d[i++] : 0.0);
710                         int const n2 = int(d[i++]);
711                         for (int j = 0; j < n2; ++j) {
712                                 double xx = d[i++] + xshift;
713                                 double yy = d[i++] + yshift;
714 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
715                                 if (code == 4 || code == 6) {
716                                         sqmt.transform(xx, yy);
717                                         if (code == 6) {
718                                                 if (r == 0 && xshift == 0.0)
719                                                         yy += h;
720                                                 else
721                                                         xx += w;
722                                         }
723                                 } else
724                                         mt.transform(xx, yy);
725                                 xp[j] = int(x + xx + 0.5);
726                                 yp[j] = int(y + yy + 0.5);
727                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
728                         }
729                         pi.pain.lines(xp, yp, n2, pi.base.font.color(),
730                                 Painter::fill_none, Painter::line_solid, lw);
731                 }
732         }
733 }
734
735
736 docstring const &  mathedSymbol(MetricsBase & mb, latexkeys const * sym)
737 {
738         return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
739                 sym->dsp_draw : sym->draw;
740 }
741
742
743 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
744 {
745         LASSERT((bool)sym, return 0);
746         //lyxerr << "metrics: symbol: '" << sym->name
747         //      << "' in font: '" << sym->inset
748         //      << "' drawn as: '" << sym->draw
749         //      << "'" << endl;
750
751         bool const italic_upcase_greek = sym->inset == "cmr" &&
752                 sym->extra == "mathalpha" &&
753                 mb.fontname == "mathit";
754         std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
755         bool const change_font = font != "cmr" ||
756                                 (mb.fontname != "mathbb" &&
757                                  mb.fontname != "mathds" &&
758                                  mb.fontname != "mathfrak" &&
759                                  mb.fontname != "mathcal" &&
760                                  mb.fontname != "mathscr");
761         Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
762         mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
763         return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
764 }
765
766
767 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
768 {
769         LASSERT((bool)sym, return);
770         //lyxerr << "drawing: symbol: '" << sym->name
771         //      << "' in font: '" << sym->inset
772         //      << "' drawn as: '" << sym->draw
773         //      << "'" << endl;
774
775         bool const italic_upcase_greek = sym->inset == "cmr" &&
776                 sym->extra == "mathalpha" &&
777                 pi.base.fontname == "mathit";
778         std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
779         bool const change_font = font != "cmr" ||
780                                 (pi.base.fontname != "mathbb" &&
781                                  pi.base.fontname != "mathds" &&
782                                  pi.base.fontname != "mathfrak" &&
783                                  pi.base.fontname != "mathcal" &&
784                                  pi.base.fontname != "mathscr");
785         Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
786         pi.draw(x, y, mathedSymbol(pi.base, sym));
787 }
788
789
790 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
791 {
792         FontInfo font = mi.base.font;
793         augmentFont(font, "mathnormal");
794         mathed_string_dim(font, str, dim);
795 }
796
797
798 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
799 {
800         FontInfo f = pi.base.font;
801         augmentFont(f, "mathnormal");
802         f.setColor(Color_latex);
803         pi.pain.text(x, y, str, f);
804 }
805
806
807 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
808 {
809         FontInfo f = pi.base.font;
810         augmentFont(f, "mathnormal");
811         f.setColor(Color_foreground);
812         pi.pain.text(x, y, str, f);
813 }
814
815
816 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
817 {
818         frontend::FontMetrics const & fm = theFontMetrics(font);
819         asc = fm.maxAscent();
820         des = fm.maxDescent();
821 }
822
823
824 struct fontinfo {
825         string cmd_;
826         FontFamily family_;
827         FontSeries series_;
828         FontShape  shape_;
829         ColorCode        color_;
830 };
831
832
833 FontFamily const inh_family = INHERIT_FAMILY;
834 FontSeries const inh_series = INHERIT_SERIES;
835 FontShape  const inh_shape  = INHERIT_SHAPE;
836
837
838 // mathnormal should be the first, otherwise the fallback further down
839 // does not work
840 fontinfo fontinfos[] = {
841         // math fonts
842         // Color_math determines which fonts are math (see isMathFont)
843         {"mathnormal",    ROMAN_FAMILY, MEDIUM_SERIES,
844                           ITALIC_SHAPE, Color_math},
845         {"mathbf",        inh_family, BOLD_SERIES,
846                           inh_shape, Color_math},
847         {"mathcal",       CMSY_FAMILY, inh_series,
848                           inh_shape, Color_math},
849         {"mathfrak",      EUFRAK_FAMILY, inh_series,
850                           inh_shape, Color_math},
851         {"mathrm",        ROMAN_FAMILY, inh_series,
852                           UP_SHAPE, Color_math},
853         {"mathsf",        SANS_FAMILY, inh_series,
854                           inh_shape, Color_math},
855         {"mathbb",        MSB_FAMILY, inh_series,
856                           inh_shape, Color_math},
857         {"mathds",        DS_FAMILY, inh_series,
858                           inh_shape, Color_math},
859         {"mathtt",        TYPEWRITER_FAMILY, inh_series,
860                           inh_shape, Color_math},
861         {"mathit",        inh_family, inh_series,
862                           ITALIC_SHAPE, Color_math},
863         {"mathscr",       RSFS_FAMILY, inh_series,
864                           inh_shape, Color_math},
865         {"cmex",          CMEX_FAMILY, inh_series,
866                           inh_shape, Color_math},
867         {"cmm",           CMM_FAMILY, inh_series,
868                           inh_shape, Color_math},
869         {"cmr",           CMR_FAMILY, inh_series,
870                           inh_shape, Color_math},
871         {"cmsy",          CMSY_FAMILY, inh_series,
872                           inh_shape, Color_math},
873         {"eufrak",        EUFRAK_FAMILY, inh_series,
874                           inh_shape, Color_math},
875         {"msa",           MSA_FAMILY, inh_series,
876                           inh_shape, Color_math},
877         {"msb",           MSB_FAMILY, inh_series,
878                           inh_shape, Color_math},
879         {"stmry",         STMARY_FAMILY, inh_series,
880                           inh_shape, Color_math},
881         {"wasy",          WASY_FAMILY, inh_series,
882                           inh_shape, Color_math},
883         {"esint",         ESINT_FAMILY, inh_series,
884                           inh_shape, Color_math},
885
886         // Text fonts
887         {"text",          inh_family, inh_series,
888                           inh_shape, Color_foreground},
889         {"textbf",        inh_family, BOLD_SERIES,
890                           inh_shape, Color_foreground},
891         {"textit",        inh_family, inh_series,
892                           ITALIC_SHAPE, Color_foreground},
893         {"textmd",        inh_family, MEDIUM_SERIES,
894                           inh_shape, Color_foreground},
895         {"textnormal",    inh_family, inh_series,
896                           UP_SHAPE, Color_foreground},
897         {"textrm",        ROMAN_FAMILY,
898                           inh_series, UP_SHAPE,Color_foreground},
899         {"textsc",        inh_family, inh_series,
900                           SMALLCAPS_SHAPE, Color_foreground},
901         {"textsf",        SANS_FAMILY, inh_series,
902                           inh_shape, Color_foreground},
903         {"textsl",        inh_family, inh_series,
904                           SLANTED_SHAPE, Color_foreground},
905         {"texttt",        TYPEWRITER_FAMILY, inh_series,
906                           inh_shape, Color_foreground},
907         {"textup",        inh_family, inh_series,
908                           UP_SHAPE, Color_foreground},
909
910         // TIPA support
911         {"textipa",       inh_family, inh_series,
912                           inh_shape, Color_foreground},
913
914         // mhchem support
915         {"ce",            inh_family, inh_series,
916                           inh_shape, Color_foreground},
917         {"cf",            inh_family, inh_series,
918                           inh_shape, Color_foreground},
919
920         // LyX internal usage
921         {"lyxtex",        inh_family, inh_series,
922                           UP_SHAPE, Color_latex},
923         // FIXME: The following two don't work on OS X, since the Symbol font
924         //        uses a different encoding, and is therefore disabled in
925         //        FontLoader::available().
926         {"lyxsymbol",     SYMBOL_FAMILY, inh_series,
927                           inh_shape, Color_math},
928         {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
929                           inh_shape, Color_math},
930         {"lyxblacktext",  ROMAN_FAMILY, MEDIUM_SERIES,
931                           UP_SHAPE, Color_foreground},
932         {"lyxnochange",   inh_family, inh_series,
933                           inh_shape, Color_foreground},
934         {"lyxfakebb",     TYPEWRITER_FAMILY, BOLD_SERIES,
935                           UP_SHAPE, Color_math},
936         {"lyxfakecal",    SANS_FAMILY, MEDIUM_SERIES,
937                           ITALIC_SHAPE, Color_math},
938         {"lyxfakefrak",   ROMAN_FAMILY, BOLD_SERIES,
939                           ITALIC_SHAPE, Color_math}
940 };
941
942
943 fontinfo * lookupFont(string const & name)
944 {
945         //lyxerr << "searching font '" << name << "'" << endl;
946         int const n = sizeof(fontinfos) / sizeof(fontinfo);
947         for (int i = 0; i < n; ++i)
948                 if (fontinfos[i].cmd_ == name) {
949                         //lyxerr << "found '" << i << "'" << endl;
950                         return fontinfos + i;
951                 }
952         return 0;
953 }
954
955
956 fontinfo * searchFont(string const & name)
957 {
958         fontinfo * f = lookupFont(name);
959         return f ? f : fontinfos;
960         // this should be mathnormal
961         //return searchFont("mathnormal");
962 }
963
964
965 bool isFontName(string const & name)
966 {
967         return lookupFont(name);
968 }
969
970
971 bool isMathFont(string const & name)
972 {
973         fontinfo * f = lookupFont(name);
974         return f && f->color_ == Color_math;
975 }
976
977
978 bool isTextFont(string const & name)
979 {
980         fontinfo * f = lookupFont(name);
981         return f && f->color_ == Color_foreground;
982 }
983
984
985 FontInfo getFont(string const & name)
986 {
987         FontInfo font;
988         augmentFont(font, name);
989         return font;
990 }
991
992
993 void fakeFont(string const & orig, string const & fake)
994 {
995         fontinfo * forig = searchFont(orig);
996         fontinfo * ffake = searchFont(fake);
997         if (forig && ffake) {
998                 forig->family_ = ffake->family_;
999                 forig->series_ = ffake->series_;
1000                 forig->shape_  = ffake->shape_;
1001                 forig->color_  = ffake->color_;
1002         } else {
1003                 lyxerr << "Can't fake font '" << orig << "' with '"
1004                        << fake << "'" << endl;
1005         }
1006 }
1007
1008
1009 void augmentFont(FontInfo & font, string const & name)
1010 {
1011         static bool initialized = false;
1012         if (!initialized) {
1013                 initialized = true;
1014                 // fake fonts if necessary
1015                 if (!theFontLoader().available(getFont("mathfrak")))
1016                         fakeFont("mathfrak", "lyxfakefrak");
1017                 if (!theFontLoader().available(getFont("mathcal")))
1018                         fakeFont("mathcal", "lyxfakecal");
1019         }
1020         fontinfo * info = searchFont(name);
1021         if (info->family_ != inh_family)
1022                 font.setFamily(info->family_);
1023         if (info->series_ != inh_series)
1024                 font.setSeries(info->series_);
1025         if (info->shape_ != inh_shape)
1026                 font.setShape(info->shape_);
1027         if (info->color_ != Color_none)
1028                 font.setColor(info->color_);
1029 }
1030
1031
1032 bool isAlphaSymbol(MathAtom const & at)
1033 {
1034         if (at->asCharInset() ||
1035             (at->asSymbolInset() &&
1036              at->asSymbolInset()->isOrdAlpha()))
1037                 return true;
1038
1039         if (at->asFontInset()) {
1040                 MathData const & ar = at->asFontInset()->cell(0);
1041                 for (size_t i = 0; i < ar.size(); ++i) {
1042                         if (!(ar[i]->asCharInset() ||
1043                               (ar[i]->asSymbolInset() &&
1044                                ar[i]->asSymbolInset()->isOrdAlpha())))
1045                                 return false;
1046                 }
1047                 return true;
1048         }
1049         return false;
1050 }
1051
1052
1053 docstring asString(MathData const & ar)
1054 {
1055         odocstringstream os;
1056         otexrowstream ots(os);
1057         TeXMathStream ws(ots);
1058         ws << ar;
1059         return os.str();
1060 }
1061
1062
1063 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1064 {
1065         // If the QUIET flag is set, we are going to parse for either
1066         // a paste operation or a macro definition. We try to do the
1067         // right thing in all cases.
1068
1069         bool quiet = pf & Parse::QUIET;
1070         bool macro = pf & Parse::MACRODEF;
1071         if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1072                 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1073 }
1074
1075
1076 docstring asString(InsetMath const & inset)
1077 {
1078         odocstringstream os;
1079         otexrowstream ots(os);
1080         TeXMathStream ws(ots);
1081         inset.write(ws);
1082         return os.str();
1083 }
1084
1085
1086 docstring asString(MathAtom const & at)
1087 {
1088         odocstringstream os;
1089         otexrowstream ots(os);
1090         TeXMathStream ws(ots);
1091         at->write(ws);
1092         return os.str();
1093 }
1094
1095
1096 int axis_height(MetricsBase & mb)
1097 {
1098         Changer dummy = mb.changeFontSet("mathnormal");
1099         return theFontMetrics(mb.font).ascent('-') - 1;
1100 }
1101
1102
1103 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1104 {
1105         MathWordList const & words = mathedWordList();
1106         MathWordList::const_iterator it = words.find(word);
1107         if (it != words.end()) {
1108                 string const req = it->second.required;
1109                 if (!req.empty())
1110                         features.require(req);
1111         }
1112 }
1113
1114
1115 } // namespace lyx