]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
oh well
[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 "FontLoader.h"
8 #include "font.h"
9 #include "math_cursor.h"
10 #include "math_defs.h"
11 #include "math_inset.h"
12 #include "math_parser.h"
13 #include "Painter.h"
14 #include "debug.h"
15 #include "commandtags.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 namespace {
56
57 LyXFont * MathFonts = 0;
58 bool font_available[LM_FONT_END];
59 bool font_available_initialized[LM_FONT_END];
60
61 enum MathFont {
62         FONT_IT,
63         FONT_SYMBOL,
64         FONT_SYMBOLI,
65         FONT_BF,
66         FONT_TT,
67         FONT_RM,
68         FONT_SF,
69         FONT_CMR,
70         FONT_CMSY,
71         FONT_CMM,
72         FONT_CMEX,
73         FONT_MSA,
74         FONT_MSB,
75         FONT_EUFRAK,
76         FONT_FAKEBB,
77         FONT_FAKECAL,
78         FONT_FAKEFRAK,
79         FONT_NUM
80 };
81
82 void mathed_init_fonts()
83 {
84         MathFonts = new LyXFont[FONT_NUM];
85
86         MathFonts[FONT_IT].setShape(LyXFont::ITALIC_SHAPE);
87
88         MathFonts[FONT_SYMBOL].setFamily(LyXFont::SYMBOL_FAMILY);
89
90         MathFonts[FONT_SYMBOLI].setFamily(LyXFont::SYMBOL_FAMILY);
91         MathFonts[FONT_SYMBOLI].setShape(LyXFont::ITALIC_SHAPE);
92
93         MathFonts[FONT_BF].setSeries(LyXFont::BOLD_SERIES);
94
95         MathFonts[FONT_TT].setFamily(LyXFont::TYPEWRITER_FAMILY);
96         MathFonts[FONT_RM].setFamily(LyXFont::ROMAN_FAMILY);
97         MathFonts[FONT_SF].setFamily(LyXFont::SANS_FAMILY);
98
99         MathFonts[FONT_CMR].setFamily(LyXFont::CMR_FAMILY);
100         MathFonts[FONT_CMSY].setFamily(LyXFont::CMSY_FAMILY);
101         MathFonts[FONT_CMM].setFamily(LyXFont::CMM_FAMILY);
102         MathFonts[FONT_CMEX].setFamily(LyXFont::CMEX_FAMILY);
103         MathFonts[FONT_MSA].setFamily(LyXFont::MSA_FAMILY);
104         MathFonts[FONT_MSB].setFamily(LyXFont::MSB_FAMILY);
105         MathFonts[FONT_EUFRAK].setFamily(LyXFont::EUFRAK_FAMILY);
106
107         MathFonts[FONT_FAKEBB].setFamily(LyXFont::TYPEWRITER_FAMILY);
108         MathFonts[FONT_FAKEBB].setSeries(LyXFont::BOLD_SERIES);
109
110         MathFonts[FONT_FAKECAL].setFamily(LyXFont::SANS_FAMILY);
111         MathFonts[FONT_FAKECAL].setShape(LyXFont::ITALIC_SHAPE);
112
113         MathFonts[FONT_FAKEFRAK].setFamily(LyXFont::SANS_FAMILY);
114         MathFonts[FONT_FAKEFRAK].setSeries(LyXFont::BOLD_SERIES);
115
116         for (int i = 0; i < LM_FONT_END; ++i)
117                 font_available_initialized[i] = false;
118 }
119
120
121 LyXFont const & whichFontBaseIntern(MathTextCodes type)
122 {
123         if (!MathFonts)
124                 mathed_init_fonts();
125
126         switch (type) {
127         case LM_TC_SYMB:
128         case LM_TC_BOLDSYMB:
129                 return MathFonts[FONT_SYMBOLI];
130
131         case LM_TC_VAR:
132         case LM_TC_IT:
133                 return MathFonts[FONT_IT];
134
135         case LM_TC_BF:
136                 return MathFonts[FONT_BF];
137
138         case LM_TC_BB:
139                 return MathFonts[FONT_MSB];
140
141         case LM_TC_CAL:
142                 return MathFonts[FONT_CMSY];
143
144         case LM_TC_TT:
145                 return MathFonts[FONT_TT];
146
147         case LM_TC_BOX:
148         case LM_TC_TEXTRM:
149         case LM_TC_CONST:
150         case LM_TC_TEX:
151         case LM_TC_RM:
152                 return MathFonts[FONT_RM];
153
154         case LM_TC_SF:
155                 return MathFonts[FONT_SF];
156
157         case LM_TC_CMR:
158                 return MathFonts[FONT_CMR];
159
160         case LM_TC_CMSY:
161                 return MathFonts[FONT_CMSY];
162
163         case LM_TC_CMM:
164                 return MathFonts[FONT_CMM];
165
166         case LM_TC_CMEX:
167                 return MathFonts[FONT_CMEX];
168
169         case LM_TC_MSA:
170                 return MathFonts[FONT_MSA];
171
172         case LM_TC_MSB:
173                 return MathFonts[FONT_MSB];
174
175         case LM_TC_EUFRAK:
176                 return MathFonts[FONT_EUFRAK];
177
178         default:
179                 break;
180         }
181         return MathFonts[1];
182 }
183
184
185 LyXFont const & whichFontBase(MathTextCodes type)
186 {
187         if (!MathFonts)
188                 mathed_init_fonts();
189
190         switch (type) {
191         case LM_TC_BB:
192                 if (math_font_available(LM_TC_MSB))
193                         return MathFonts[FONT_MSB];
194                 else
195                         return MathFonts[FONT_FAKEBB];
196
197         case LM_TC_CAL:
198                 if (math_font_available(LM_TC_CMSY))
199                         return MathFonts[FONT_CMSY];
200                 else
201                         return MathFonts[FONT_FAKECAL];
202
203         case LM_TC_EUFRAK:
204                 if (math_font_available(LM_TC_EUFRAK))
205                         return MathFonts[FONT_EUFRAK];
206                 else
207                         return MathFonts[FONT_FAKEFRAK];
208
209         default:
210                 break;
211         }
212         return whichFontBaseIntern(type);
213 }
214
215 } // namespace
216
217
218 void whichFont(LyXFont & f, MathTextCodes type, MathMetricsInfo const & size)
219 {
220         f = whichFontBase(type);
221         // use actual size
222         f.setSize(size.font.size());
223
224         switch (size.style) {
225         case LM_ST_DISPLAY:
226                 if (type == LM_TC_BOLDSYMB || type == LM_TC_CMEX) {
227                         f.incSize();
228                         f.incSize();
229                 }
230                 break;
231
232         case LM_ST_TEXT:
233                 break;
234
235         case LM_ST_SCRIPT:
236                 f.decSize();
237                 f.decSize();
238                 break;
239
240         case LM_ST_SCRIPTSCRIPT:
241                 f.decSize();
242                 f.decSize();
243                 f.decSize();
244                 break;
245
246         default:
247                 lyxerr << "Math Error: wrong font size: " << size.style << endl;
248                 break;
249         }
250
251         if (type != LM_TC_TEXTRM && type != LM_TC_BOX)
252                 f.setColor(LColor::math);
253
254         if (type == LM_TC_TEX)
255                 f.setColor(LColor::latex);
256 }
257
258
259 bool math_font_available(MathTextCodes type)
260 {
261         if (!font_available_initialized[type]) {
262                 font_available_initialized[type] = true;
263                 font_available[type] = fontloader.available(whichFontBaseIntern(type));
264                 if (!font_available[type])
265                         lyxerr[Debug::FONT] << "Math font " << type << " not available.\n";
266         }
267         return font_available[type];
268 }
269
270
271 namespace {
272
273 /*
274  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
275  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
276  */
277
278
279 double const parenthHigh[] = {
280         2, 13,
281         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
282         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
283         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
284         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
285         0.9840, 0.9986,
286         0
287 };
288
289
290 double const parenth[] = {
291         2, 13,
292         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
293         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
294         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
295         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
296         0.9930, 0.9919,
297         0
298 };
299
300
301 double const brace[] = {
302         2, 21,
303         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
304         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
305         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
306         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
307         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
308         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
309         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
310         0
311 };
312
313
314 double const arrow[] = {
315         4, 7,
316         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
317         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
318         0.9500, 0.7500,
319         3, 0.5000, 0.1500, 0.5000, 0.9500,
320         0
321 };
322
323
324 double const Arrow[] = {
325         4, 7,
326         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
327         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
328         0.9500, 0.7500,
329         3, 0.3500, 0.5000, 0.3500, 0.9500,
330         3, 0.6500, 0.5000, 0.6500, 0.9500,
331         0
332 };
333
334
335 double const udarrow[] = {
336         2, 3,
337         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
338         2, 3,
339         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
340         1, 0.5, 0.2,  0.5, 0.8,
341         0
342 };
343
344
345 double const Udarrow[] = {
346         2, 3,
347         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
348         2, 3,
349         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
350         1, 0.35, 0.2, 0.35, 0.8,
351         1, 0.65, 0.2, 0.65, 0.8,
352         0
353 };
354
355
356 double const brack[] = {
357         2, 4,
358         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
359         0
360 };
361
362
363 double const corner[] = {
364         2, 3,
365         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
366         0
367 };
368
369
370 double const angle[] = {
371         2, 3,
372         1, 0,  0.05, 0.5,  1, 1,
373         0
374 };
375
376
377 double const slash[] = {
378         1, 0.95, 0.05, 0.05, 0.95,
379         0
380 };
381
382
383 double const hline[] = {
384         1, 0.00, 0.5, 1.0, 0.5,
385         0
386 };
387
388
389 double const ddot[] = {
390         1, 0.2, 0.5,  0.3, 0.5,
391         1, 0.7, 0.5,  0.8, 0.5,
392         0
393 };
394
395
396 double const dddot[] = {
397         1, 0.1, 0.5,  0.2, 0.5,
398         1, 0.45, 0.5, 0.55, 0.5,
399         1, 0.8, 0.5,  0.9, 0.5,
400         0
401 };
402
403
404 double const hline3[] = {
405         1, 0.1,   0,  0.15,  0,
406         1, 0.475, 0,  0.525, 0,
407         1, 0.85,  0,  0.9,   0,
408         0
409 };
410
411
412 double const dline3[] = {
413         1, 0.1,   0.1,   0.15,  0.15,
414         1, 0.475, 0.475, 0.525, 0.525,
415         1, 0.85,  0.85,  0.9,   0.9,
416         0
417 };
418
419
420 double const hlinesmall[] = {
421         1, 0.4, 0.5, 0.6, 0.5,
422         0
423 };
424
425
426 double const vert[] = {
427         1, 0.5, 0.05,  0.5, 0.95,
428         0
429 };
430
431
432 double const  Vert[] = {
433         1, 0.3, 0.05,  0.3, 0.95,
434         1, 0.7, 0.05,  0.7, 0.95,
435         0
436 };
437
438
439 double const ring[] = {
440         2, 5,
441         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
442         0
443 };
444
445
446 double const tilde[] = {
447         2, 4,
448         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
449         0
450 };
451
452
453 struct deco_struct {
454         double const * data;
455         int angle;
456 };
457
458 struct named_deco_struct {
459         char const * name;
460         double const * data;
461         int angle;
462 };
463
464 named_deco_struct deco_table[] = {
465         // Decorations
466         {"widehat",        angle,      3 },
467         {"widetilde",      tilde,      0 },
468         {"underbar",       hline,      0 },
469         {"underline",      hline,      0 },
470         {"overline",       hline,      0 },
471         {"underbrace",     brace,      1 },
472         {"overbrace",      brace,      3 },
473         {"overleftarrow",  arrow,      1 },
474         {"overrightarrow", arrow,      3 },
475         {"overleftrightarrow", udarrow, 1 },
476         {"xleftarrow",     arrow,      1 },
477         {"xrightarrow",    arrow,      3 },
478         {"underleftarrow", arrow,      1 },
479         {"underrightarrow", arrow,     3 },
480         {"underleftrightarrow",udarrow, 1 },
481
482         // Delimiters
483         {"(",              parenth,    0 },
484         {")",              parenth,    2 },
485         {"{",              brace,      0 },
486         {"}",              brace,      2 },
487         {"[",              brack,      0 },
488         {"]",              brack,      2 },
489         {"|",              vert,       0 },
490         {"/",              slash,      0 },
491         {"vert",           vert,       0 },
492         {"Vert",           Vert,       0 },
493         {"'",              slash,      1 },
494         {"backslash",      slash,      1 },
495         {"langle",         angle,      0 },
496         {"lceil",          corner,     0 },
497         {"lfloor",         corner,     1 },
498         {"rangle",         angle,      2 },
499         {"rceil",          corner,     3 },
500         {"rfloor",         corner,     2 },
501         {"downarrow",      arrow,      2 },
502         {"Downarrow",      Arrow,      2 },
503         {"uparrow",        arrow,      0 },
504         {"Uparrow",        Arrow,      0 },
505         {"updownarrow",    udarrow,    0 },
506         {"Updownarrow",    Udarrow,    0 },
507
508         // Accents
509         {"ddot",           ddot,       0 },
510         {"dddot",          dddot,      0 },
511         {"hat",            angle,      3 },
512         {"grave",          slash,      1 },
513         {"acute",          slash,      0 },
514         {"tilde",          tilde,      0 },
515         {"bar",            hline,      0 },
516         {"dot",            hlinesmall, 0 },
517         {"check",          angle,      1 },
518         {"breve",          parenth,    1 },
519         {"vec",            arrow,      3 },
520         {"not",            slash,      0 },
521         {"mathring",       ring,       0 },
522
523         // Dots
524         {"ldots",          hline3,     0 },
525         {"cdots",          hline3,     0 },
526         {"vdots",          hline3,     1 },
527         {"ddots",          dline3,     0 }
528 };
529
530
531 map<string, deco_struct> deco_list;
532
533 // sort the table on startup
534 struct init_deco_table {
535         init_deco_table() {
536                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
537                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
538                         deco_struct d;
539                         d.data  = p->data;
540                         d.angle = p->angle;
541                         deco_list[p->name]= d;
542                 }
543         }
544 };
545
546 static init_deco_table dummy;
547
548
549 deco_struct const * search_deco(string const & name)
550 {
551         map<string, deco_struct>::const_iterator p = deco_list.find(name);
552         return (p == deco_list.end()) ? 0 : &(p->second);
553 }
554
555
556 } // namespace anon
557
558
559 void mathed_char_dim(LyXFont const & font,
560         unsigned char c, int & asc, int & des, int & wid)
561 {
562         des = lyxfont::descent(c, font);
563         asc = lyxfont::ascent(c, font);
564         wid = mathed_char_width(font, c);
565 }
566
567
568 int mathed_char_ascent(LyXFont const & font, unsigned char c)
569 {
570         return lyxfont::ascent(c, font);
571 }
572
573
574 int mathed_char_descent(LyXFont const & font, unsigned char c)
575 {
576         return lyxfont::descent(c, font);
577 }
578
579
580 int mathed_char_width(LyXFont const & font, unsigned char c)
581 {
582         return lyxfont::width(c, font);
583 }
584
585
586 void mathed_string_dim(LyXFont const & font,
587         string const & s, int & asc, int & des, int & wid)
588 {
589         asc = des = 0;
590         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
591                 des = max(des, lyxfont::descent(*it, font));
592                 asc = max(asc, lyxfont::ascent(*it, font));
593         }
594         wid = lyxfont::width(s, font);
595 }
596
597
598 int mathed_string_width(LyXFont const & font, string const & s)
599 {
600         return lyxfont::width(s, font);
601 }
602
603
604 int mathed_string_ascent(LyXFont const & font, string const & s)
605 {
606         int asc = 0;
607         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
608                 asc = max(asc, lyxfont::ascent(*it, font));
609         return asc;
610 }
611
612
613 int mathed_string_descent(LyXFont const & font, string const & s)
614 {
615         int des = 0;
616         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
617                 des = max(des, lyxfont::descent(*it, font));
618         return des;
619 }
620
621
622
623 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
624         const string & name)
625 {
626         if (name == ".") {
627                 pain.line(x + w/2, y, x + w/2, y + h,
628                           LColor::mathcursor, Painter::line_onoffdash);
629                 return;
630         }
631
632         deco_struct const * mds = search_deco(name);
633         if (!mds) {
634                 lyxerr << "Deco was not found. Programming error?\n";
635                 lyxerr << "name: '" << name << "'\n";
636                 return;
637         }
638
639         int const n = (w < h) ? w : h;
640         int const r = mds->angle;
641         double const * d = mds->data;
642
643         if (h > 70 && (name == "(" || name == ")"))
644                 d = parenthHigh;
645
646         Matrix mt(r, w, h);
647         Matrix sqmt(r, n, n);
648
649         if (r > 0 && r < 3)
650                 y += h;
651
652         if (r >= 2)
653                 x += w;
654
655         for (int i = 0; d[i];) {
656                 int code = int(d[i++]);
657                 if (code & 1) {  // code == 1 || code == 3
658                         double xx = d[i++];
659                         double yy = d[i++];
660                         double x2 = d[i++];
661                         double y2 = d[i++];
662                         if (code == 3)
663                                 sqmt.transform(xx, yy);
664                         else
665                                 mt.transform(xx, yy);
666                         mt.transform(x2, y2);
667                         pain.line(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
668                                         LColor::math);
669                 }       else {
670                         int xp[32];
671                         int yp[32];
672                         int const n = int(d[i++]);
673                         for (int j = 0; j < n; ++j) {
674                                 double xx = d[i++];
675                                 double yy = d[i++];
676 //           lyxerr << " " << xx << " " << yy << " ";
677                                 if (code == 4)
678                                         sqmt.transform(xx, yy);
679                                 else
680                                         mt.transform(xx, yy);
681                                 xp[j] = x + int(xx);
682                                 yp[j] = y + int(yy);
683                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
684                         }
685                         pain.lines(xp, yp, n, LColor::math);
686                 }
687         }
688 }
689
690
691 void mathed_draw_framebox(Painter & pain, int x, int y, MathInset const * p)
692 {
693         if (mathcursor && mathcursor->isInside(p))
694                 pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
695                         LColor::mathframe);
696 }
697
698
699 // In the future maybe we use a better fonts renderer
700 void drawStr(Painter & pain, LyXFont const & font,
701         int x, int y, string const & str)
702 {
703         pain.text(x, y, str, font);
704 }
705
706
707 void drawChar(Painter & pain, LyXFont const & font, int x, int y, char c)
708 {
709         pain.text(x, y, c, font);
710 }
711
712
713 // decrease math size for super- and subscripts
714 void smallerStyleScript(MathMetricsInfo & st)
715 {
716         switch (st.style) {
717                 case LM_ST_DISPLAY:
718                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
719                 default:            st.style = LM_ST_SCRIPTSCRIPT;
720         }
721 }
722
723
724 // decrease math size for fractions
725 void smallerStyleFrac(MathMetricsInfo & st)
726 {
727         switch (st.style) {
728                 case LM_ST_DISPLAY: st.style = LM_ST_TEXT; break;
729                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
730                 default:            st.style = LM_ST_SCRIPTSCRIPT;
731         }
732 }
733
734
735 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
736 {
737         asc = lyxfont::maxAscent(font);
738         des = lyxfont::maxDescent(font);
739 }
740
741
742 char const * math_font_name(MathTextCodes code)
743 {
744         static char const * theFontNames[] = {
745                 "mathrm",
746                 "mathcal",
747                 "mathfrak",
748                 "mathbf",
749                 "mathbb",
750                 "mathsf",
751                 "mathtt",
752                 "mathit",
753                 "textrm"
754         };
755
756         if (code >= LM_TC_RM && code <= LM_TC_TEXTRM)
757                 return theFontNames[code - LM_TC_RM];
758         return 0;
759 }
760
761 string convertDelimToLatexName(string const & name)
762 {
763         if (name == "(")
764                 return name;
765         if (name == "[")
766                 return name;
767         if (name == ".")
768                 return name;
769         if (name == ")")
770                 return name;
771         if (name == "]")
772                 return name;
773         if (name == "/")
774                 return name;
775         if (name == "|")
776                 return name;
777         return "\\" + name + " ";
778 }