]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.cpp
Fix small glitch with \underXXXarrow and \overXXXarrow
[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.0634, 0.6379, 0.2183, 0.7667,
107         0.3380, 0.8286, 0.5141, 0.8874, 0.7324, 0.9422,
108         0.9930, 0.9929,
109         0
110 };
111
112
113 double const breve[] = {
114         2, 8,
115         0.100, 0.400,  0.125, 0.550,  0.200, 0.700,  0.400, 0.800,
116         0.600, 0.800,  0.800, 0.700,  0.875, 0.550,  0.900, 0.400,
117         0
118 };
119
120
121 double const brace[] = {
122         2, 21,
123         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
124         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
125         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
126         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
127         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
128         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
129         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
130         0
131 };
132
133
134 double const mapsto[] = {
135         2, 3,
136         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
137         1, 0.015, 0.475, 0.945, 0.475,
138         1, 0.015, 0.015, 0.015, 0.985,
139         0
140 };
141
142
143 double const lhook[] = {
144         2, 3,
145         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
146         1, 0.015, 0.475, 0.7, 0.475,
147         2, 5,
148         0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
149         0.825, 0.35, 0.7, 0.475,
150         0
151 };
152
153
154 double const rhook[] = {
155         2, 3,
156         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
157         1, 0.3, 0.475, 0.985, 0.475,
158         2, 5,
159         0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
160         0.175, 0.35, 0.3, 0.475,
161         0
162 };
163
164
165 double const LRArrow[] = {
166         2, 3,
167         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
168         2, 3,
169         0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
170         1, 0.2, 0.8, 0.8, 0.8,
171         1, 0.2, 0.2, 0.8, 0.2,
172         0
173 };
174
175
176 double const LArrow[] = {
177         2, 3,
178         0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
179         1, 0.2, 0.8, 0.985, 0.8,
180         1, 0.2, 0.2, 0.985, 0.2,
181         0
182 };
183
184
185 double const lharpoondown[] = {
186         2, 2,
187         0.015, 0.5, 0.25, 0.985,
188         1, 0.02, 0.475, 0.985, 0.475,
189         0
190 };
191
192
193 double const lharpoonup[] = {
194         2, 2,
195         0.25, 0.015, 0.015, 0.5,
196         1, 0.02, 0.525, 0.985, 0.525,
197         0
198 };
199
200
201 double const lrharpoons[] = {
202         2, 2,
203         0.25, 0.015, 0.015, 0.225,
204         1, 0.02, 0.23, 0.985, 0.23,
205         2, 2,
206         0.75, 0.985, 0.985, 0.775,
207         1, 0.02, 0.7, 0.980, 0.7,
208         0
209 };
210
211
212 double const rlharpoons[] = {
213         2, 2,
214         0.75, 0.015, 0.985, 0.225,
215         1, 0.02, 0.23, 0.985, 0.23,
216         2, 2,
217         0.25, 0.985, 0.015, 0.775,
218         1, 0.02, 0.7, 0.980, 0.7,
219         0
220 };
221
222
223 double const vec[] = {
224         4, 7,
225         0.2000, 0.5000, 0.3000, 0.4000, 0.4000, 0.2500,
226         0.5000, 0.0000, 0.6000, 0.2500, 0.7000, 0.4000,
227         0.8000, 0.5000,
228         3, 0.5000, 0.1000, 0.5000, 0.9500,
229         0
230 };
231
232
233 double const arrow[] = {
234         4, 7,
235         0.0500, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
236         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
237         0.9500, 0.7500,
238         3, 0.5000, 0.1500, 0.5000, 1.0000,
239         0
240 };
241
242
243 double const Arrow[] = {
244         4, 7,
245         0.0150, 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.3500, 0.5000, 0.3500, 0.9500,
249         3, 0.6500, 0.5000, 0.6500, 0.9500,
250         0
251 };
252
253
254 double const udarrow[] = {
255         2, 3,
256         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
257         2, 3,
258         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
259         1, 0.5, 0.1,  0.5, 0.9,
260         0
261 };
262
263
264 double const Udarrow[] = {
265         2, 3,
266         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
267         2, 3,
268         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
269         1, 0.35, 0.2, 0.35, 0.8,
270         1, 0.65, 0.2, 0.65, 0.8,
271         0
272 };
273
274
275 double const brack[] = {
276         2, 4,
277         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
278         0
279 };
280
281
282 double const dbrack[] = {
283         2, 4,
284         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
285         2, 2,
286         0.50, 0.05,  0.50, 0.95,
287         0
288 };
289
290
291 double const corner[] = {
292         2, 3,
293         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
294         0
295 };
296
297
298 double const angle[] = {
299         2, 3,
300         0.9, 0.05,  0.05, 0.5,  0.9, 0.95,
301         0
302 };
303
304
305 double const slash[] = {
306         1, 0.95, 0.05, 0.05, 0.95,
307         0
308 };
309
310
311 double const hline[] = {
312         1, 0.00, 0.5, 1.0, 0.5,
313         0
314 };
315
316
317 double const dot[] = {
318 //      1, 0.5, 0.2, 0.5, 0.2,
319 //      1, 0.4, 0.4, 0.6, 0.4,
320 //      1, 0.5, 0.5, 0.5, 0.5,
321         5, 0.4, 0.5, 0.6, 0.5,
322         0
323 };
324
325
326 double const ddot[] = {
327         5, 0.1, 0.5, 0.3, 0.5,
328         5, 0.6, 0.5, 0.8, 0.5,
329         0
330 };
331
332
333 double const dddot[] = {
334         5, 0.0, 0.5, 0.2, 0.5,
335         5, 0.4, 0.5, 0.6, 0.5,
336         5, 0.8, 0.5, 1.0, 0.5,
337         0
338 };
339
340
341 double const ddddot[] = {
342         5, -0.2, 0.5, 0.0, 0.5,
343         5,  0.2, 0.5, 0.4, 0.5,
344         5,  0.6, 0.5, 0.8, 0.5,
345         5,  1.0, 0.5, 1.2, 0.5,
346         0
347 };
348
349
350 double const hline3[] = {
351         1, 0.1,   0,  0.15,  0,
352         1, 0.475, 0,  0.525, 0,
353         1, 0.85,  0,  0.9,   0,
354         0
355 };
356
357
358 double const dline3[] = {
359         1, 0.1,   0.1,   0.15,  0.15,
360         1, 0.475, 0.475, 0.525, 0.525,
361         1, 0.85,  0.85,  0.9,   0.9,
362         0
363 };
364
365
366 double const ring[] = {
367         2, 13,
368         0.5000, 0.7750,  0.6375, 0.7375,  0.7375, 0.6375,  0.7750, 0.5000,
369         0.7375, 0.3625,  0.6375, 0.2625,  0.5000, 0.2250,  0.3625, 0.2625,
370         0.2625, 0.3625,  0.2250, 0.5000,  0.2625, 0.6375,  0.3625, 0.7375,
371         0.5000, 0.7750,
372         0
373 };
374
375
376 double const vert[] = {
377         1, 0.5, 0.05,  0.5, 0.95,
378         0
379 };
380
381
382 double const  Vert[] = {
383         1, 0.3, 0.05,  0.3, 0.95,
384         1, 0.7, 0.05,  0.7, 0.95,
385         0
386 };
387
388
389 double const tilde[] = {
390         2, 10,
391         0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
392         0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
393         0
394 };
395
396
397 struct deco_struct {
398         double const * data;
399         int angle;
400 };
401
402 struct named_deco_struct {
403         char const * name;
404         double const * data;
405         int angle;
406 };
407
408 named_deco_struct deco_table[] = {
409         // Decorations
410         {"widehat",             angle,        3 },
411         {"widetilde",           tilde,        0 },
412         {"underbar",            hline,        0 },
413         {"underline",           hline,        0 },
414         {"overline",            hline,        0 },
415         {"underbrace",          brace,        1 },
416         {"overbrace",           brace,        3 },
417         {"overleftarrow",       arrow,        1 },
418         {"overrightarrow",      arrow,        3 },
419         {"overleftrightarrow",  udarrow,      1 },
420         {"xhookleftarrow",      lhook,        0 },
421         {"xhookrightarrow",     rhook,        0 },
422         {"xleftarrow",          arrow,        1 },
423         {"xLeftarrow",          LArrow,       0 },
424         {"xleftharpoondown",    lharpoondown, 0 },
425         {"xleftharpoonup",      lharpoonup,   0 },
426         {"xleftrightharpoons",  lrharpoons,   0 },
427         {"xleftrightarrow",     udarrow,      1 },
428         {"xLeftrightarrow",     LRArrow,      0 },
429         {"xmapsto",             mapsto,       0 },
430         {"xrightarrow",         arrow,        3 },
431         {"xRightarrow",         LArrow,       2 },
432         {"xrightharpoondown",   lharpoonup,   2 },
433         {"xrightharpoonup",     lharpoondown, 2 },
434         {"xrightleftharpoons",  rlharpoons,   0 },
435         {"underleftarrow",      arrow,        1 },
436         {"underrightarrow",     arrow,        3 },
437         {"underleftrightarrow", udarrow,      1 },
438         {"undertilde",          tilde,        0 },
439         {"utilde",              tilde,        0 },
440
441         // Delimiters
442         {"(",              parenth,    0 },
443         {")",              parenth,    2 },
444         {"{",              brace,      0 },
445         {"}",              brace,      2 },
446         {"lbrace",         brace,      0 },
447         {"rbrace",         brace,      2 },
448         {"[",              brack,      0 },
449         {"]",              brack,      2 },
450         {"llbracket",      dbrack,     0 },
451         {"rrbracket",      dbrack,     2 },
452         {"|",              vert,       0 },
453         {"/",              slash,      0 },
454         {"slash",          slash,      0 },
455         {"vert",           vert,       0 },
456         {"lvert",          vert,       0 },
457         {"rvert",          vert,       0 },
458         {"Vert",           Vert,       0 },
459         {"lVert",          Vert,       0 },
460         {"rVert",          Vert,       0 },
461         {"'",              slash,      1 },
462         {"<",              angle,      0 },
463         {">",              angle,      2 },
464         {"\\",             slash,      1 },
465         {"backslash",      slash,      1 },
466         {"langle",         angle,      0 },
467         {"lceil",          corner,     0 },
468         {"lfloor",         corner,     1 },
469         {"rangle",         angle,      2 },
470         {"rceil",          corner,     3 },
471         {"rfloor",         corner,     2 },
472         {"downarrow",      arrow,      2 },
473         {"Downarrow",      Arrow,      2 },
474         {"uparrow",        arrow,      0 },
475         {"Uparrow",        Arrow,      0 },
476         {"updownarrow",    udarrow,    0 },
477         {"Updownarrow",    Udarrow,    0 },
478
479         // Accents
480         {"ddot",           ddot,       0 },
481         {"dddot",          dddot,      0 },
482         {"ddddot",         ddddot,     0 },
483         {"hat",            angle,      3 },
484         {"grave",          slash,      1 },
485         {"acute",          slash,      0 },
486         {"tilde",          tilde,      0 },
487         {"bar",            hline,      0 },
488         {"dot",            dot,        0 },
489         {"check",          angle,      1 },
490         {"breve",          breve,      0 },
491         {"vec",            vec,        3 },
492         {"mathring",       ring,       0 },
493
494         // Dots
495         {"dots",           hline3,     0 },
496         {"ldots",          hline3,     0 },
497         {"cdots",          hline3,     0 },
498         {"vdots",          hline3,     1 },
499         {"ddots",          dline3,     0 },
500         {"adots",          dline3,     1 },
501         {"iddots",         dline3,     1 },
502         {"dotsb",          hline3,     0 },
503         {"dotsc",          hline3,     0 },
504         {"dotsi",          hline3,     0 },
505         {"dotsm",          hline3,     0 },
506         {"dotso",          hline3,     0 }
507 };
508
509
510 map<docstring, deco_struct> deco_list;
511
512 // sort the table on startup
513 class init_deco_table {
514 public:
515         init_deco_table() {
516                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
517                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
518                         deco_struct d;
519                         d.data  = p->data;
520                         d.angle = p->angle;
521                         deco_list[from_ascii(p->name)] = d;
522                 }
523         }
524 };
525
526 static init_deco_table dummy_deco_table;
527
528
529 deco_struct const * search_deco(docstring const & name)
530 {
531         map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
532         return p == deco_list.end() ? 0 : &(p->second);
533 }
534
535
536 } // namespace
537
538
539 int mathed_font_em(FontInfo const & font)
540 {
541         return theFontMetrics(font).em();
542 }
543
544
545 int mathed_font_x_height(FontInfo const & font)
546 {
547         return theFontMetrics(font).xHeight();
548 }
549
550 /* The math units. Quoting TeX by Topic, p.205:
551  *
552  * Spacing around mathematical objects is measured in mu units. A mu
553  * is 1/18th part of \fontdimen6 of the font in family 2 in the
554  * current style, the ‘quad’ value of the symbol font.
555  *
556  * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
557  * inserted around (binary) relations, except where these are preceded
558  * or followed by other relations or punctuation, and except if they
559  * follow an open, or precede a close symbol.
560  *
561  * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
562  * is put around binary operators.
563  *
564  * A \thinmuskip (default value in plain TeX: 3mu) follows after
565  * punctuation, and is put around inner objects, except where these
566  * are followed by a close or preceded by an open symbol, and except
567  * if the other object is a large operator or a binary relation.
568  *
569  * See the file MathClass.cpp for a formal implementation of the rules
570  * above.
571  */
572
573 int mathed_mu(FontInfo const & font, double mu)
574 {
575         MetricsBase mb(nullptr, font);
576         return mb.inPixels(Length(mu, Length::MU));
577 }
578
579 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
580 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
581 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
582
583
584 int mathed_char_width(FontInfo const & font, char_type c)
585 {
586         return theFontMetrics(font).width(c);
587 }
588
589
590 int mathed_char_kerning(FontInfo const & font, char_type c)
591 {
592         frontend::FontMetrics const & fm = theFontMetrics(font);
593         return max(0, fm.rbearing(c) - fm.width(c));
594 }
595
596
597 double mathed_char_slope(MetricsBase const & mb, char_type c)
598 {
599         bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
600         if (slanted && mb.fontname == "mathnormal")
601                 return theFontMetrics(mb.font).italicSlope();
602         return 0.0;
603 }
604
605
606 void mathed_string_dim(FontInfo const & font,
607                        docstring const & s,
608                        Dimension & dim)
609 {
610         frontend::FontMetrics const & fm = theFontMetrics(font);
611         dim.asc = 0;
612         dim.des = 0;
613         for (char_type const c : s) {
614                 dim.asc = max(dim.asc, fm.ascent(c));
615                 dim.des = max(dim.des, fm.descent(c));
616         }
617         dim.wid = fm.width(s);
618 }
619
620
621 int mathed_string_width(FontInfo const & font, docstring const & s)
622 {
623         return theFontMetrics(font).width(s);
624 }
625
626
627 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
628         docstring const & name)
629 {
630         int const lw = pi.base.solidLineThickness();
631
632         if (name == ".") {
633                 pi.pain.line(x + w/2, y, x + w/2, y + h,
634                           Color_cursor, Painter::line_onoffdash, lw);
635                 return;
636         }
637
638         deco_struct const * mds = search_deco(name);
639         if (!mds) {
640                 lyxerr << "Deco was not found. Programming error?" << endl;
641                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
642                 return;
643         }
644
645         int const n = (w < h) ? w : h;
646         int const r = mds->angle;
647         double const * d = mds->data;
648
649         if (h > 70 && (name == "(" || name == ")"))
650                 d = parenthHigh;
651
652         Matrix mt(r, w, h);
653         Matrix sqmt(r, n, n);
654
655         if (r > 0 && r < 3)
656                 y += h;
657
658         if (r >= 2)
659                 x += w;
660
661         for (int i = 0; d[i]; ) {
662                 int code = int(d[i++]);
663                 if (code & 1) {  // code == 1 || code == 3 || code == 5
664                         double xx = d[i++];
665                         double yy = d[i++];
666                         double x2 = d[i++];
667                         double y2 = d[i++];
668                         if (code == 3)
669                                 sqmt.transform(xx, yy);
670                         else
671                                 mt.transform(xx, yy);
672                         mt.transform(x2, y2);
673                         pi.pain.line(
674                                 int(x + xx + 0.5), int(y + yy + 0.5),
675                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
676                                 pi.base.font.color(), Painter::line_solid, lw);
677                         if (code == 5) {  // thicker, but rounded
678                                 double const xa = x + xx + 0.5;
679                                 double const xb = x + x2 + 0.5;
680                                 double const ya = y + yy + 0.5;
681                                 double const yb = y + y2 + 0.5;
682                                 pi.pain.line(int(xa + 1), int(ya - 1),
683                                              int(xb - 1), int(yb - 1),
684                                              pi.base.font.color(),
685                                              Painter::line_solid, lw);
686                                 pi.pain.line(int(xa + 1), int(ya + 1),
687                                              int(xb - 1), int(yb + 1),
688                                              pi.base.font.color(),
689                                              Painter::line_solid, lw);
690                                 for (int k = 2; xa + k <= xb - k; k++) {
691                                         pi.pain.line(int(xa + k), int(ya - k),
692                                                      int(xb - k), int(yb - k),
693                                                      pi.base.font.color(),
694                                                      Painter::line_solid, lw);
695                                         pi.pain.line(int(xa + k), int(ya + k),
696                                                      int(xb - k), int(yb + k),
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