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