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