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