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