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