]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.C
This commit introduces the FontLoader interface class. In the future, I intend to...
[lyx.git] / src / mathed / MathSupport.C
1 /**
2  * \file MathSupport.C
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 #include "MathData.h"
16 #include "InsetMath.h"
17 #include "MathMLStream.h"
18 #include "MathParser.h"
19
20 #include "debug.h"
21 #include "LColor.h"
22
23 #include "frontends/Application.h"
24 #include "frontends/Painter.h"
25 #include "frontends/font_metrics.h"
26 #include "frontends/FontLoader.h"
27
28 #include <map>
29 #include <sstream>
30
31 using lyx::docstring;
32 using lyx::frontend::Painter;
33
34 using std::string;
35 using std::max;
36 using std::endl;
37
38
39 ///
40 class Matrix {
41 public:
42         ///
43         Matrix(int, double, double);
44         ///
45         void transform(double &, double &);
46 private:
47         ///
48         double m_[2][2];
49 };
50
51
52 Matrix::Matrix(int code, double x, double y)
53 {
54         double const cs = (code & 1) ? 0 : (1 - code);
55         double const sn = (code & 1) ? (2 - code) : 0;
56         m_[0][0] =  cs * x;
57         m_[0][1] =  sn * x;
58         m_[1][0] = -sn * y;
59         m_[1][1] =  cs * y;
60 }
61
62
63 void Matrix::transform(double & x, double & y)
64 {
65         double xx = m_[0][0] * x + m_[0][1] * y;
66         double yy = m_[1][0] * x + m_[1][1] * y;
67         x = xx;
68         y = yy;
69 }
70
71
72
73 namespace {
74
75 /*
76  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
78  */
79
80
81 double const parenthHigh[] = {
82         2, 13,
83         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
87         0.9840, 0.9986,
88         0
89 };
90
91
92 double const parenth[] = {
93         2, 13,
94         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
98         0.9930, 0.9919,
99         0
100 };
101
102
103 double const brace[] = {
104         2, 21,
105         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
112         0
113 };
114
115
116 double const arrow[] = {
117         4, 7,
118         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
120         0.9500, 0.7500,
121         3, 0.5000, 0.1500, 0.5000, 0.9500,
122         0
123 };
124
125
126 double const Arrow[] = {
127         4, 7,
128         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
130         0.9500, 0.7500,
131         3, 0.3500, 0.5000, 0.3500, 0.9500,
132         3, 0.6500, 0.5000, 0.6500, 0.9500,
133         0
134 };
135
136
137 double const udarrow[] = {
138         2, 3,
139         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
140         2, 3,
141         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
142         1, 0.5, 0.2,  0.5, 0.8,
143         0
144 };
145
146
147 double const Udarrow[] = {
148         2, 3,
149         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
150         2, 3,
151         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
152         1, 0.35, 0.2, 0.35, 0.8,
153         1, 0.65, 0.2, 0.65, 0.8,
154         0
155 };
156
157
158 double const brack[] = {
159         2, 4,
160         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
161         0
162 };
163
164
165 double const corner[] = {
166         2, 3,
167         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
168         0
169 };
170
171
172 double const angle[] = {
173         2, 3,
174         1, 0,  0.05, 0.5,  1, 1,
175         0
176 };
177
178
179 double const slash[] = {
180         1, 0.95, 0.05, 0.05, 0.95,
181         0
182 };
183
184
185 double const hline[] = {
186         1, 0.00, 0.5, 1.0, 0.5,
187         0
188 };
189
190
191 double const ddot[] = {
192         1, 0.2, 0.5,  0.3, 0.5,
193         1, 0.7, 0.5,  0.8, 0.5,
194         0
195 };
196
197
198 double const dddot[] = {
199         1, 0.1, 0.5,  0.2, 0.5,
200         1, 0.45, 0.5, 0.55, 0.5,
201         1, 0.8, 0.5,  0.9, 0.5,
202         0
203 };
204
205
206 double const hline3[] = {
207         1, 0.1,   0,  0.15,  0,
208         1, 0.475, 0,  0.525, 0,
209         1, 0.85,  0,  0.9,   0,
210         0
211 };
212
213
214 double const dline3[] = {
215         1, 0.1,   0.1,   0.15,  0.15,
216         1, 0.475, 0.475, 0.525, 0.525,
217         1, 0.85,  0.85,  0.9,   0.9,
218         0
219 };
220
221
222 double const hlinesmall[] = {
223         1, 0.4, 0.5, 0.6, 0.5,
224         0
225 };
226
227
228 double const ring[] = {
229         2, 5,
230         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
231         0
232 };
233
234
235 double const vert[] = {
236         1, 0.5, 0.05,  0.5, 0.95,
237         0
238 };
239
240
241 double const  Vert[] = {
242         1, 0.3, 0.05,  0.3, 0.95,
243         1, 0.7, 0.05,  0.7, 0.95,
244         0
245 };
246
247
248 double const tilde[] = {
249         2, 4,
250         0.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 0.2,
251         0
252 };
253
254
255 struct deco_struct {
256         double const * data;
257         int angle;
258 };
259
260 struct named_deco_struct {
261         char const * name;
262         double const * data;
263         int angle;
264 };
265
266 named_deco_struct deco_table[] = {
267         // Decorations
268         {"widehat",             angle,    3 },
269         {"widetilde",           tilde,    0 },
270         {"underbar",            hline,    0 },
271         {"underline",           hline,    0 },
272         {"overline",            hline,    0 },
273         {"underbrace",          brace,    1 },
274         {"overbrace",           brace,    3 },
275         {"overleftarrow",       arrow,    1 },
276         {"overrightarrow",      arrow,    3 },
277         {"overleftrightarrow",  udarrow,  1 },
278         {"xleftarrow",          arrow,    1 },
279         {"xrightarrow",         arrow,    3 },
280         {"underleftarrow",      arrow,    1 },
281         {"underrightarrow",     arrow,    3 },
282         {"underleftrightarrow", udarrow,  1 },
283
284         // Delimiters
285         {"(",              parenth,    0 },
286         {")",              parenth,    2 },
287         {"{",              brace,      0 },
288         {"}",              brace,      2 },
289         {"lbrace",         brace,      0 },
290         {"rbrace",         brace,      2 },
291         {"[",              brack,      0 },
292         {"]",              brack,      2 },
293         {"|",              vert,       0 },
294         {"/",              slash,      0 },
295         {"vert",           vert,       0 },
296         {"Vert",           Vert,       0 },
297         {"'",              slash,      1 },
298         {"backslash",      slash,      1 },
299         {"langle",         angle,      0 },
300         {"lceil",          corner,     0 },
301         {"lfloor",         corner,     1 },
302         {"rangle",         angle,      2 },
303         {"rceil",          corner,     3 },
304         {"rfloor",         corner,     2 },
305         {"downarrow",      arrow,      2 },
306         {"Downarrow",      Arrow,      2 },
307         {"uparrow",        arrow,      0 },
308         {"Uparrow",        Arrow,      0 },
309         {"updownarrow",    udarrow,    0 },
310         {"Updownarrow",    Udarrow,    0 },
311
312         // Accents
313         {"ddot",           ddot,       0 },
314         {"dddot",          dddot,      0 },
315         {"hat",            angle,      3 },
316         {"grave",          slash,      1 },
317         {"acute",          slash,      0 },
318         {"tilde",          tilde,      0 },
319         {"bar",            hline,      0 },
320         {"dot",            hlinesmall, 0 },
321         {"check",          angle,      1 },
322         {"breve",          parenth,    1 },
323         {"vec",            arrow,      3 },
324         {"mathring",       ring,       0 },
325
326         // Dots
327         {"dots",           hline3,     0 },
328         {"ldots",          hline3,     0 },
329         {"cdots",          hline3,     0 },
330         {"vdots",          hline3,     1 },
331         {"ddots",          dline3,     0 },
332         {"dotsb",          hline3,     0 },
333         {"dotsc",          hline3,     0 },
334         {"dotsi",          hline3,     0 },
335         {"dotsm",          hline3,     0 },
336         {"dotso",          hline3,     0 }
337 };
338
339
340 std::map<string, deco_struct> deco_list;
341
342 // sort the table on startup
343 class init_deco_table {
344 public:
345         init_deco_table() {
346                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
347                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
348                         deco_struct d;
349                         d.data  = p->data;
350                         d.angle = p->angle;
351                         deco_list[p->name]= d;
352                 }
353         }
354 };
355
356 static init_deco_table dummy;
357
358
359 deco_struct const * search_deco(string const & name)
360 {
361         std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
362         return (p == deco_list.end()) ? 0 : &(p->second);
363 }
364
365
366 } // namespace anon
367
368
369 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
370 {
371         dim.des = font_metrics::descent(c, font);
372         dim.asc = font_metrics::ascent(c, font);
373         dim.wid = mathed_char_width(font, c);
374 }
375
376
377 int mathed_char_ascent(LyXFont const & font, unsigned char c)
378 {
379         return font_metrics::ascent(c, font);
380 }
381
382
383 int mathed_char_descent(LyXFont const & font, unsigned char c)
384 {
385         return font_metrics::descent(c, font);
386 }
387
388
389 int mathed_char_width(LyXFont const & font, unsigned char c)
390 {
391         return font_metrics::width(c, font);
392 }
393
394
395 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
396 {
397 #if 1
398         dim.asc = 0;
399         dim.des = 0;
400         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
401                 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
402                 dim.des = max(dim.des, font_metrics::descent(*it, font));
403         }
404 #else
405         dim.asc = font_metrics::maxAscent(font);
406         dim.des = font_metrics::maxDescent(font);
407 #endif
408         docstring ds(s.begin(), s.end());
409         dim.wid = font_metrics::width(ds, font);
410 }
411
412
413 int mathed_string_width(LyXFont const & font, string const & s)
414 {
415         docstring ds(s.begin(), s.end());
416         return font_metrics::width(ds, font);
417 }
418
419
420 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
421         string const & name)
422 {
423         if (name == ".") {
424                 pi.pain.line(x + w/2, y, x + w/2, y + h,
425                           LColor::cursor, Painter::line_onoffdash);
426                 return;
427         }
428
429         deco_struct const * mds = search_deco(name);
430         if (!mds) {
431                 lyxerr << "Deco was not found. Programming error?" << endl;
432                 lyxerr << "name: '" << name << "'" << endl;
433                 return;
434         }
435
436         int const n = (w < h) ? w : h;
437         int const r = mds->angle;
438         double const * d = mds->data;
439
440         if (h > 70 && (name == "(" || name == ")"))
441                 d = parenthHigh;
442
443         Matrix mt(r, w, h);
444         Matrix sqmt(r, n, n);
445
446         if (r > 0 && r < 3)
447                 y += h;
448
449         if (r >= 2)
450                 x += w;
451
452         for (int i = 0; d[i]; ) {
453                 int code = int(d[i++]);
454                 if (code & 1) {  // code == 1 || code == 3
455                         double xx = d[i++];
456                         double yy = d[i++];
457                         double x2 = d[i++];
458                         double y2 = d[i++];
459                         if (code == 3)
460                                 sqmt.transform(xx, yy);
461                         else
462                                 mt.transform(xx, yy);
463                         mt.transform(x2, y2);
464                         pi.pain.line(
465                                 int(x + xx + 0.5), int(y + yy + 0.5),
466                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
467                                 LColor::math);
468                 } else {
469                         int xp[32];
470                         int yp[32];
471                         int const n = int(d[i++]);
472                         for (int j = 0; j < n; ++j) {
473                                 double xx = d[i++];
474                                 double yy = d[i++];
475 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
476                                 if (code == 4)
477                                         sqmt.transform(xx, yy);
478                                 else
479                                         mt.transform(xx, yy);
480                                 xp[j] = int(x + xx + 0.5);
481                                 yp[j] = int(y + yy + 0.5);
482                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
483                         }
484                         pi.pain.lines(xp, yp, n, LColor::math);
485                 }
486         }
487 }
488
489
490 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
491 {
492         LyXFont f = pi.base.font;
493         f.setColor(LColor::latex);
494         docstring dstr(str.begin(), str.end());
495         pi.pain.text(x, y, dstr, f);
496 }
497
498
499 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
500 {
501         LyXFont f = pi.base.font;
502         f.setColor(LColor::foreground);
503         docstring dstr(str.begin(), str.end());
504         pi.pain.text(x, y, dstr, f);
505 }
506
507
508 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
509 {
510         asc = font_metrics::maxAscent(font);
511         des = font_metrics::maxDescent(font);
512 }
513
514
515 struct fontinfo {
516         string cmd_;
517         LyXFont::FONT_FAMILY family_;
518         LyXFont::FONT_SERIES series_;
519         LyXFont::FONT_SHAPE  shape_;
520         LColor::color        color_;
521 };
522
523
524 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
525 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
526 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE;
527
528
529 // mathnormal should be the first, otherwise the fallback further down
530 // does not work
531 fontinfo fontinfos[] = {
532         // math fonts
533         {"mathnormal",    LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
534                           LyXFont::ITALIC_SHAPE, LColor::math},
535         {"mathbf",        inh_family, LyXFont::BOLD_SERIES,
536                           inh_shape, LColor::math},
537         {"mathcal",       LyXFont::CMSY_FAMILY, inh_series,
538                           inh_shape, LColor::math},
539         {"mathfrak",      LyXFont::EUFRAK_FAMILY, inh_series,
540                           inh_shape, LColor::math},
541         {"mathrm",        LyXFont::ROMAN_FAMILY, inh_series,
542                           LyXFont::UP_SHAPE, LColor::math},
543         {"mathsf",        LyXFont::SANS_FAMILY, inh_series,
544                           inh_shape, LColor::math},
545         {"mathbb",        LyXFont::MSB_FAMILY, inh_series,
546                           inh_shape, LColor::math},
547         {"mathtt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
548                           inh_shape, LColor::math},
549         {"mathit",        inh_family, inh_series,
550                           LyXFont::ITALIC_SHAPE, LColor::math},
551         {"cmex",          LyXFont::CMEX_FAMILY, inh_series,
552                           inh_shape, LColor::math},
553         {"cmm",           LyXFont::CMM_FAMILY, inh_series,
554                           inh_shape, LColor::math},
555         {"cmr",           LyXFont::CMR_FAMILY, inh_series,
556                           inh_shape, LColor::math},
557         {"cmsy",          LyXFont::CMSY_FAMILY, inh_series,
558                           inh_shape, LColor::math},
559         {"eufrak",        LyXFont::EUFRAK_FAMILY, inh_series,
560                           inh_shape, LColor::math},
561         {"msa",           LyXFont::MSA_FAMILY, inh_series,
562                           inh_shape, LColor::math},
563         {"msb",           LyXFont::MSB_FAMILY, inh_series,
564                           inh_shape, LColor::math},
565         {"wasy",          LyXFont::WASY_FAMILY, inh_series,
566                           inh_shape, LColor::none},
567
568         // Text fonts
569         {"text",          inh_family, inh_series,
570                           inh_shape, LColor::foreground},
571         {"textbf",        inh_family, LyXFont::BOLD_SERIES,
572                           inh_shape, LColor::foreground},
573         {"textit",        inh_family, inh_series,
574                           LyXFont::ITALIC_SHAPE, LColor::foreground},
575         {"textmd",        inh_family, LyXFont::MEDIUM_SERIES,
576                           inh_shape, LColor::foreground},
577         {"textnormal",    inh_family, inh_series,
578                           LyXFont::UP_SHAPE, LColor::foreground},
579         {"textrm",        LyXFont::ROMAN_FAMILY,
580                           inh_series, LyXFont::UP_SHAPE,LColor::foreground},
581         {"textsc",        inh_family, inh_series,
582                           LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
583         {"textsf",        LyXFont::SANS_FAMILY, inh_series,
584                           inh_shape, LColor::foreground},
585         {"textsl",        inh_family, inh_series,
586                           LyXFont::SLANTED_SHAPE, LColor::foreground},
587         {"texttt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
588                           inh_shape, LColor::foreground},
589         {"textup",        inh_family, inh_series,
590                           LyXFont::UP_SHAPE, LColor::foreground},
591
592         // TIPA support
593         {"textipa",       inh_family, inh_series,
594                           inh_shape, LColor::foreground},
595
596         // LyX internal usage
597         {"lyxtex",        inh_family, inh_series,
598                           LyXFont::UP_SHAPE, LColor::latex},
599         {"lyxsymbol",     LyXFont::SYMBOL_FAMILY, inh_series,
600                           inh_shape, LColor::math},
601         {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
602                           inh_shape, LColor::math},
603         {"lyxblacktext",  LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
604                           LyXFont::UP_SHAPE, LColor::foreground},
605         {"lyxnochange",   inh_family, inh_series,
606                           inh_shape, LColor::foreground},
607         {"lyxfakebb",     LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
608                           LyXFont::UP_SHAPE, LColor::math},
609         {"lyxfakecal",    LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
610                           LyXFont::ITALIC_SHAPE, LColor::math},
611         {"lyxfakefrak",   LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
612                           LyXFont::ITALIC_SHAPE, LColor::math}
613 };
614
615
616 fontinfo * lookupFont(string const & name)
617 {
618         //lyxerr << "searching font '" << name << "'" << endl;
619         int const n = sizeof(fontinfos) / sizeof(fontinfo);
620         for (int i = 0; i < n; ++i)
621                 if (fontinfos[i].cmd_ == name) {
622                         //lyxerr << "found '" << i << "'" << endl;
623                         return fontinfos + i;
624                 }
625         return 0;
626 }
627
628
629 fontinfo * searchFont(string const & name)
630 {
631         fontinfo * f = lookupFont(name);
632         return f ? f : fontinfos;
633         // this should be mathnormal
634         //return searchFont("mathnormal");
635 }
636
637
638 bool isFontName(string const & name)
639 {
640         return lookupFont(name);
641 }
642
643
644 LyXFont getFont(string const & name)
645 {
646         LyXFont font;
647         augmentFont(font, name);
648         return font;
649 }
650
651
652 void fakeFont(string const & orig, string const & fake)
653 {
654         fontinfo * forig = searchFont(orig);
655         fontinfo * ffake = searchFont(fake);
656         if (forig && ffake) {
657                 forig->family_ = ffake->family_;
658                 forig->series_ = ffake->series_;
659                 forig->shape_  = ffake->shape_;
660                 forig->color_  = ffake->color_;
661         } else {
662                 lyxerr << "Can't fake font '" << orig << "' with '"
663                        << fake << "'" << endl;
664         }
665 }
666
667
668 void augmentFont(LyXFont & font, string const & name)
669 {
670         static bool initialized = false;
671         if (!initialized) {
672                 initialized = true;
673                 // fake fonts if necessary
674                 if (!theApp->fontLoader().available(getFont("mathfrak")))
675                         fakeFont("mathfrak", "lyxfakefrak");
676                 if (!theApp->fontLoader().available(getFont("mathcal")))
677                         fakeFont("mathcal", "lyxfakecal");
678         }
679         fontinfo * info = searchFont(name);
680         if (info->family_ != inh_family)
681                 font.setFamily(info->family_);
682         if (info->series_ != inh_series)
683                 font.setSeries(info->series_);
684         if (info->shape_ != inh_shape)
685                 font.setShape(info->shape_);
686         if (info->color_ != LColor::none)
687                 font.setColor(info->color_);
688 }
689
690
691 string asString(MathArray const & ar)
692 {
693         std::ostringstream os;
694         WriteStream ws(os);
695         ws << ar;
696         return os.str();
697 }
698
699
700 void asArray(string const & str, MathArray & ar)
701 {
702         mathed_parse_cell(ar, str);
703 }
704
705
706 string asString(InsetMath const & inset)
707 {
708         std::ostringstream os;
709         WriteStream ws(os);
710         inset.write(ws);
711         return os.str();
712 }
713
714
715 string asString(MathAtom const & at)
716 {
717         std::ostringstream os;
718         WriteStream ws(os);
719         at->write(ws);
720         return os.str();
721 }