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