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