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