]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
rename commandtags.h to lfuns.h and renumber/cleanup. Rebuild the tree !
[lyx.git] / src / mathed / math_support.C
1
2 #include <config.h>
3
4 #include "math_support.h"
5 #include "lyxfont.h"
6 #include "math_cursor.h"
7 #include "math_inset.h"
8 #include "math_parser.h"
9 #include "math_metricsinfo.h"
10 #include "frontends/Painter.h"
11 #include "frontends/font_metrics.h"
12 #include "frontends/lyx_gui.h"
13 #include "debug.h"
14 #include "lfuns.h"
15 #include "dimension.h"
16
17 #include <map>
18
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         {"dots",           hline3,     0 },
309         {"ldots",          hline3,     0 },
310         {"cdots",          hline3,     0 },
311         {"vdots",          hline3,     1 },
312         {"ddots",          dline3,     0 },
313         {"dotsb",          hline3,     0 },
314         {"dotsc",          hline3,     0 },
315         {"dotsi",          hline3,     0 },
316         {"dotsm",          hline3,     0 },
317         {"dotso",          hline3,     0 }
318 };
319
320
321 std::map<string, deco_struct> deco_list;
322
323 // sort the table on startup
324 struct init_deco_table {
325         init_deco_table() {
326                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
327                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
328                         deco_struct d;
329                         d.data  = p->data;
330                         d.angle = p->angle;
331                         deco_list[p->name]= d;
332                 }
333         }
334 };
335
336 static init_deco_table dummy;
337
338
339 deco_struct const * search_deco(string const & name)
340 {
341         std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
342         return (p == deco_list.end()) ? 0 : &(p->second);
343 }
344
345
346 } // namespace anon
347
348
349 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
350 {
351         dim.d = font_metrics::descent(c, font);
352         dim.a = font_metrics::ascent(c, font);
353         dim.w = mathed_char_width(font, c);
354 }
355
356
357 int mathed_char_ascent(LyXFont const & font, unsigned char c)
358 {
359         return font_metrics::ascent(c, font);
360 }
361
362
363 int mathed_char_descent(LyXFont const & font, unsigned char c)
364 {
365         return font_metrics::descent(c, font);
366 }
367
368
369 int mathed_char_width(LyXFont const & font, unsigned char c)
370 {
371         return font_metrics::width(c, font);
372 }
373
374
375 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
376 {
377 #if 1
378         dim.a = 0;
379         dim.d = 0;
380         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
381                 dim.a = max(dim.a, font_metrics::ascent(*it, font));
382                 dim.d = max(dim.d, font_metrics::descent(*it, font));
383         }
384 #else
385         dim.a = font_metrics::maxAscent(font);
386         dim.d = font_metrics::maxDescent(font);
387 #endif
388         dim.w = font_metrics::width(s, font);
389 }
390
391
392 int mathed_string_width(LyXFont const & font, string const & s)
393 {
394         return font_metrics::width(s, font);
395 }
396
397
398 void mathed_draw_deco(MathPainterInfo & pi, int x, int y, int w, int h,
399         const string & name)
400 {
401         if (name == ".") {
402                 pi.pain.line(x + w/2, y, x + w/2, y + h,
403                           LColor::mathcursor, Painter::line_onoffdash);
404                 return;
405         }
406
407         deco_struct const * mds = search_deco(name);
408         if (!mds) {
409                 lyxerr << "Deco was not found. Programming error?\n";
410                 lyxerr << "name: '" << name << "'\n";
411                 return;
412         }
413
414         int const n = (w < h) ? w : h;
415         int const r = mds->angle;
416         double const * d = mds->data;
417
418         if (h > 70 && (name == "(" || name == ")"))
419                 d = parenthHigh;
420
421         Matrix mt(r, w, h);
422         Matrix sqmt(r, n, n);
423
424         if (r > 0 && r < 3)
425                 y += h;
426
427         if (r >= 2)
428                 x += w;
429
430         for (int i = 0; d[i]; ) {
431                 int code = int(d[i++]);
432                 if (code & 1) {  // code == 1 || code == 3
433                         double xx = d[i++];
434                         double yy = d[i++];
435                         double x2 = d[i++];
436                         double y2 = d[i++];
437                         if (code == 3)
438                                 sqmt.transform(xx, yy);
439                         else
440                                 mt.transform(xx, yy);
441                         mt.transform(x2, y2);
442                         pi.pain.line(
443                                 int(x + xx + 0.5), int(y + yy + 0.5),
444                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
445                                 LColor::math);
446                 }       else {
447                         int xp[32];
448                         int yp[32];
449                         int const n = int(d[i++]);
450                         for (int j = 0; j < n; ++j) {
451                                 double xx = d[i++];
452                                 double yy = d[i++];
453 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
454                                 if (code == 4)
455                                         sqmt.transform(xx, yy);
456                                 else
457                                         mt.transform(xx, yy);
458                                 xp[j] = int(x + xx + 0.5);
459                                 yp[j] = int(y + yy + 0.5);
460                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
461                         }
462                         pi.pain.lines(xp, yp, n, LColor::math);
463                 }
464         }
465 }
466
467
468 void mathed_draw_framebox(MathPainterInfo & pi, int x, int y, MathInset const * p)
469 {
470         if (mathcursor && mathcursor->isInside(p))
471                 pi.pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
472                         LColor::mathframe);
473 }
474
475
476 // In the future maybe we use a better fonts renderer
477 void drawStr(MathPainterInfo & pi, LyXFont const & font,
478         int x, int y, string const & str)
479 {
480         pi.pain.text(x, y, str, font);
481 }
482
483
484 void drawStrRed(MathPainterInfo & pi, int x, int y, string const & str)
485 {
486         LyXFont f = pi.base.font;
487         f.setColor(LColor::latex);
488         pi.pain.text(x, y, str, f);
489 }
490
491
492 void drawStrBlack(MathPainterInfo & pi, int x, int y, string const & str)
493 {
494         LyXFont f = pi.base.font;
495         f.setColor(LColor::black);
496         pi.pain.text(x, y, str, f);
497 }
498
499
500 void drawChar(MathPainterInfo & pi, LyXFont const & font, int x, int y, char c)
501 {
502         pi.pain.text(x, y, c, font);
503 }
504
505
506 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
507 {
508         asc = font_metrics::maxAscent(font);
509         des = font_metrics::maxDescent(font);
510 }
511
512
513 struct fontinfo {
514         string cmd_;
515         LyXFont::FONT_FAMILY family_;
516         LyXFont::FONT_SERIES series_;
517         LyXFont::FONT_SHAPE  shape_;
518         LColor::color        color_;
519 };
520
521
522 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
523 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
524 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE;
525
526
527 // mathnormal should be the first, otherwise the fallback further down
528 // does not work
529 fontinfo fontinfos[] = {
530         {"mathnormal",
531                 inh_family, LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::math},
532         {"mathbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
533         {"mathcal",LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::math},
534         {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::math},
535         {"mathrm", LyXFont::ROMAN_FAMILY, inh_series, inh_shape, LColor::math},
536         {"mathsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::math},
537         {"mathbb", LyXFont::MSB_FAMILY, inh_series, inh_shape, LColor::math},
538         {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::math},
539         {"cmex",   LyXFont::CMEX_FAMILY, inh_series, inh_shape, LColor::none},
540         {"cmm",    LyXFont::CMM_FAMILY, inh_series, inh_shape, LColor::none},
541         {"cmr",    LyXFont::CMR_FAMILY, inh_series, inh_shape, LColor::none},
542         {"cmsy",   LyXFont::CMSY_FAMILY, inh_series, inh_shape, LColor::none},
543         {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series, inh_shape, LColor::none},
544         {"msa",    LyXFont::MSA_FAMILY, inh_series, inh_shape, LColor::none},
545         {"msb",    LyXFont::MSB_FAMILY, inh_series, inh_shape, LColor::none},
546         {"wasy",   LyXFont::WASY_FAMILY, inh_series, inh_shape, LColor::none},
547         {"text",   inh_family, inh_series, inh_shape, LColor::black},
548         {"textbf", inh_family, LyXFont::BOLD_SERIES, inh_shape, LColor::black},
549         {"textit", inh_family, inh_series, LyXFont::ITALIC_SHAPE, LColor::black},
550         {"textmd", inh_family, LyXFont::MEDIUM_SERIES, inh_shape, LColor::black},
551         {"textnormal", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
552         {"textrm", LyXFont::ROMAN_FAMILY, inh_series,LyXFont::UP_SHAPE,LColor::black},
553         {"textsc", inh_family, inh_series, LyXFont::SMALLCAPS_SHAPE, LColor::black},
554         {"textsf", LyXFont::SANS_FAMILY, inh_series, inh_shape, LColor::black},
555         {"textsl", inh_family, inh_series, LyXFont::SLANTED_SHAPE, LColor::black},
556         {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::black},
557         {"textup", inh_family, inh_series, LyXFont::UP_SHAPE, LColor::black},
558
559         // TIPA support
560         {"textipa",   inh_family, inh_series, inh_shape, LColor::black},
561
562         {"lyxtex", inh_family, inh_series, inh_shape, LColor::latex},
563         {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series, inh_shape, LColor::latex},
564         {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series, inh_shape, LColor::math},
565         {"lyxboldsymbol",
566                 LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES, inh_shape, LColor::math},
567         {"lyxitsymbol", LyXFont::SYMBOL_FAMILY,
568                 inh_series, LyXFont::ITALIC_SHAPE, LColor::math},
569         {"lyxblacktext", LyXFont::ROMAN_FAMILY,
570                 LyXFont::MEDIUM_SERIES, LyXFont::UP_SHAPE, LColor::black},
571         {"lyxnochange", inh_family, inh_series, inh_shape, LColor::black},
572
573         {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
574                 LyXFont::UP_SHAPE, LColor::math},
575         {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
576                 LyXFont::ITALIC_SHAPE, LColor::math},
577         {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
578                 LyXFont::ITALIC_SHAPE, LColor::math}
579 };
580
581
582 fontinfo * lookupFont(string const & name)
583 {
584         //lyxerr << "searching font '" << name << "'\n";
585         int const n = sizeof(fontinfos) / sizeof(fontinfo);
586         for (int i = 0; i < n; ++i)
587                 if (fontinfos[i].cmd_ == name) {
588                         //lyxerr << "found '" << i << "'\n";
589                         return fontinfos + i;
590                 }
591         return 0;
592 }
593
594
595 fontinfo * searchFont(string const & name)
596 {
597         fontinfo * f = lookupFont(name);
598         return f ? f : fontinfos;
599         // this should be mathnormal
600         //return searchFont("mathnormal");
601 }
602
603
604 bool isFontName(string const & name)
605 {
606         return lookupFont(name);
607 }
608
609
610 LyXFont getFont(string const & name)
611 {
612         LyXFont font;
613         augmentFont(font, name);
614         return font;
615 }
616
617
618 void fakeFont(string const & orig, string const & fake)
619 {
620         fontinfo * forig = searchFont(orig);
621         fontinfo * ffake = searchFont(fake);
622         if (forig && ffake) {
623                 forig->family_ = ffake->family_;
624                 forig->series_ = ffake->series_;
625                 forig->shape_  = ffake->shape_;
626                 forig->color_  = ffake->color_;
627         } else {
628                 lyxerr << "Can't fake font '" << orig << "' with '" << fake << "'\n";
629         }
630 }
631
632
633 void augmentFont(LyXFont & font, string const & name)
634 {
635         static bool initialized = false;
636         if (!initialized) {
637                 initialized = true;
638                 // fake fonts if necessary
639                 if (!lyx_gui::font_available(getFont("mathfrak")))
640                         fakeFont("mathfrak", "lyxfakefrak");
641                 if (!lyx_gui::font_available(getFont("mathcal")))
642                         fakeFont("mathcal", "lyxfakecal");
643         }
644         fontinfo * info = searchFont(name);
645         if (info->family_ != inh_family)
646                 font.setFamily(info->family_);
647         if (info->series_ != inh_series)
648                 font.setSeries(info->series_);
649         if (info->shape_ != inh_shape)
650                 font.setShape(info->shape_);
651         if (info->color_ != LColor::none)
652                 font.setColor(info->color_);
653 }