]> git.lyx.org Git - features.git/blob - src/mathed/math_support.C
dont use pragma impementation and interface anymore
[features.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 "commandtags.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 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 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 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
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 0.1500,
105         0
106 };
107
108
109 double const Arrow[] = {
110
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 0.5000,
115 0.5000,
116         0
117 };
118
119
120 double const udarrow[] = {
121 3,
122         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
123 3,
124         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
125 1,
126         0
127 };
128
129
130 double const Udarrow[] = {
131 3,
132         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
133 3,
134         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
135 1,
136 1,
137         0
138 };
139
140
141 double const brack[] = {
142 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 3,
150         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
151         0
152 };
153
154
155 double const angle[] = {
156 3,
157 1,
158         0
159 };
160
161
162 double const slash[] = {
163 1,
164         0
165 };
166
167
168 double const hline[] = {
169 1,
170         0
171 };
172
173
174 double const ddot[] = {
175 1,
176 1,
177         0
178 };
179
180
181 double const dddot[] = {
182 1,
183 1,
184 1,
185         0
186 };
187
188
189 double const hline3[] = {
190 1,
191 1,
192 1,
193         0
194 };
195
196
197 double const dline3[] = {
198 1,
199 1,
200 1,
201         0
202 };
203
204
205 double const hlinesmall[] = {
206 1,
207         0
208 };
209
210
211 double const ring[] = {
212 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,
220         0
221 };
222
223
224 double const  Vert[] = {
225 1,
226 1,
227         0
228 };
229
230
231 double const tilde[] = {
232 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 }