]> git.lyx.org Git - lyx.git/blob - src/mathed/math_support.C
Compile fix.
[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 tilde[] = {
440         2, 4,
441         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
442         0
443 };
444
445
446 struct deco_struct {
447         double const * data;
448         int angle;
449 };
450
451 struct named_deco_struct {
452         char const * name;
453         double const * data;
454         int angle;
455 };
456
457 named_deco_struct deco_table[] = {
458         // Decorations
459         {"widehat",        angle,      3 },
460         {"widetilde",      tilde,      0 },
461         {"underbar",       hline,      0 },
462         {"underline",      hline,      0 },
463         {"overline",       hline,      0 },
464         {"underbrace",     brace,      1 },
465         {"overbrace",      brace,      3 },
466         {"overleftarrow",  arrow,      1 },
467         {"overrightarrow", arrow,      3 },
468         {"overleftrightarrow", udarrow, 1 },
469         {"xleftarrow",     arrow,      1 },
470         {"xrightarrow",    arrow,      3 },
471         {"underleftarrow", arrow,      1 },
472         {"underrightarrow", arrow,     3 },
473         {"underleftrightarrow",udarrow, 1 },
474
475         // Delimiters
476         {"(",              parenth,    0 },
477         {")",              parenth,    2 },
478         {"{",              brace,      0 },
479         {"}",              brace,      2 },
480         {"[",              brack,      0 },
481         {"]",              brack,      2 },
482         {"|",              vert,       0 },
483         {"/",              slash,      0 },
484         {"Vert",           Vert,       0 },
485         {"'",              slash,      1 },
486         {"backslash",      slash,      1 },
487         {"langle",         angle,      0 },
488         {"lceil",          corner,     0 },
489         {"lfloor",         corner,     1 },
490         {"rangle",         angle,      2 },
491         {"rceil",          corner,     3 },
492         {"rfloor",         corner,     2 },
493         {"downarrow",      arrow,      2 },
494         {"Downarrow",      Arrow,      2 },
495         {"uparrow",        arrow,      0 },
496         {"Uparrow",        Arrow,      0 },
497         {"updownarrow",    udarrow,    0 },
498         {"Updownarrow",    Udarrow,    0 },     
499         
500         // Accents
501         {"ddot",           ddot,       0 },
502         {"dddot",          dddot,      0 },
503         {"hat",            angle,      3 },
504         {"grave",          slash,      1 },
505         {"acute",          slash,      0 },
506         {"tilde",          tilde,      0 },
507         {"bar",            hline,      0 },
508         {"dot",            hlinesmall, 0 },
509         {"check",          angle,      1 },
510         {"breve",          parenth,    1 },
511         {"vec",            arrow,      3 },
512         {"not",            slash,      0 },
513         
514         // Dots
515         {"ldots",          hline3,     0 },
516         {"cdots",          hline3,     0 },
517         {"vdots",          hline3,     1 },
518         {"ddots",          dline3,     0 }
519 };
520
521
522 map<string, deco_struct> deco_list;
523
524 // sort the table on startup
525 struct init_deco_table {
526         init_deco_table() {
527                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
528                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
529                         deco_struct d;
530                         d.data  = p->data;
531                         d.angle = p->angle;
532                         deco_list[p->name]= d;
533                 }
534         }
535 };
536
537 static init_deco_table dummy;
538
539
540 deco_struct const * search_deco(string const & name)
541 {
542         map<string, deco_struct>::const_iterator p = deco_list.find(name);
543         return (p == deco_list.end()) ? 0 : &(p->second);
544 }
545
546
547 } // namespace anon
548
549
550 void mathed_char_dim(LyXFont const & font,
551         unsigned char c, int & asc, int & des, int & wid)
552 {
553         des = lyxfont::descent(c, font);
554         asc = lyxfont::ascent(c, font);
555         wid = mathed_char_width(font, c);
556 }
557
558
559 int mathed_char_ascent(LyXFont const & font, unsigned char c)
560 {
561         return lyxfont::ascent(c, font);
562 }
563
564
565 int mathed_char_descent(LyXFont const & font, unsigned char c)
566 {
567         return lyxfont::descent(c, font);
568 }
569
570
571 int mathed_char_width(LyXFont const & font, unsigned char c)
572 {
573         return lyxfont::width(c, font);
574 }
575
576
577 void mathed_string_dim(LyXFont const & font,
578         string const & s, int & asc, int & des, int & wid)
579 {
580         asc = des = 0;
581         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
582                 des = max(des, lyxfont::descent(*it, font));
583                 asc = max(asc, lyxfont::ascent(*it, font));
584         }
585         wid = lyxfont::width(s, font);
586 }
587
588
589 int mathed_string_width(LyXFont const & font, string const & s)
590 {
591         return lyxfont::width(s, font);
592 }
593
594
595 int mathed_string_ascent(LyXFont const & font, string const & s)
596 {
597         int asc = 0;
598         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
599                 asc = max(asc, lyxfont::ascent(*it, font));
600         return asc;
601 }
602
603
604 int mathed_string_descent(LyXFont const & font, string const & s)
605 {
606         int des = 0;
607         for (string::const_iterator it = s.begin(); it != s.end(); ++it)
608                 des = max(des, lyxfont::descent(*it, font));
609         return des;
610 }
611
612
613
614 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
615         const string & name)
616 {
617         if (name == ".") {
618                 pain.line(x + w/2, y, x + w/2, y + h,
619                           LColor::mathcursor, Painter::line_onoffdash);
620                 return;
621         }       
622         
623         deco_struct const * mds = search_deco(name);
624         if (!mds) {
625                 lyxerr << "Deco was not found. Programming error?\n";
626                 lyxerr << "name: '" << name << "'\n";
627                 return;
628         }
629         
630         int const n = (w < h) ? w : h;
631         int const r = mds->angle;
632         double const * d = mds->data;
633         
634         if (h > 70 && (name == "(" || name == ")"))
635                 d = parenthHigh;
636         
637         Matrix mt(r, w, h);
638         Matrix sqmt(r, n, n);
639
640         if (r > 0 && r < 3)
641                 y += h;
642
643         if (r >= 2)
644                 x += w;
645
646         for (int i = 0; d[i];) {
647                 int code = int(d[i++]);
648                 if (code & 1) {  // code == 1 || code == 3
649                         double xx = d[i++];
650                         double yy = d[i++];
651                         double x2 = d[i++];
652                         double y2 = d[i++];
653                         if (code == 3)
654                                 sqmt.transform(xx, yy);
655                         else
656                                 mt.transform(xx, yy);
657                         mt.transform(x2, y2);
658                         pain.line(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
659                                         LColor::math);
660                 }       else {
661                         int xp[32];
662                         int yp[32];
663                         int const n = int(d[i++]);
664                         for (int j = 0; j < n; ++j) {
665                                 double xx = d[i++];
666                                 double yy = d[i++];
667 //           lyxerr << " " << xx << " " << yy << " ";
668                                 if (code == 4)
669                                         sqmt.transform(xx, yy);
670                                 else
671                                         mt.transform(xx, yy);
672                                 xp[j] = x + int(xx);
673                                 yp[j] = y + int(yy);
674                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
675                         }
676                         pain.lines(xp, yp, n, LColor::math);
677                 }
678         }
679 }
680
681
682 void mathed_draw_framebox(Painter & pain, int x, int y, MathInset const * p)
683 {
684         if (mathcursor && mathcursor->isInside(p))
685                 pain.rectangle(x, y - p->ascent(), p->width(), p->height(),
686                         LColor::mathframe);
687 }
688
689
690 // In the future maybe we use a better fonts renderer
691 void drawStr(Painter & pain, LyXFont const & font,
692         int x, int y, string const & str)
693 {
694         pain.text(x, y, str, font);
695 }
696
697
698 void drawChar(Painter & pain, LyXFont const & font, int x, int y, char c)
699 {
700         pain.text(x, y, c, font);
701 }
702
703
704 // decrease math size for super- and subscripts
705 void smallerStyleScript(MathMetricsInfo & st)
706 {
707         switch (st.style) {
708                 case LM_ST_DISPLAY:
709                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
710                 default:            st.style = LM_ST_SCRIPTSCRIPT;
711         }
712 }
713
714
715 // decrease math size for fractions
716 void smallerStyleFrac(MathMetricsInfo & st)
717 {
718         switch (st.style) {
719                 case LM_ST_DISPLAY: st.style = LM_ST_TEXT; break;
720                 case LM_ST_TEXT:    st.style = LM_ST_SCRIPT; break;
721                 default:            st.style = LM_ST_SCRIPTSCRIPT;
722         }
723 }
724
725
726 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
727 {
728         asc = lyxfont::maxAscent(font);
729         des = lyxfont::maxDescent(font);
730 }
731
732
733 char const * latex_mathspace[] = {
734         "!", ",", ":", ";", "quad", "qquad"
735 };
736
737
738
739 char const * math_font_name(MathTextCodes code)
740 {
741         static char const * theFontNames[] = {
742                 "mathrm",
743                 "mathcal",
744                 "mathfrak",
745                 "mathbf",
746                 "mathbb",
747                 "mathsf",
748                 "mathtt",
749                 "mathit",
750                 "textrm"
751         };
752
753         if (code >= LM_TC_RM && code <= LM_TC_TEXTRM) 
754                 return theFontNames[code - LM_TC_RM];
755         return 0;
756 }
757
758 string convertDelimToLatexName(string const & name)
759 {
760         if (name == "(")
761                 return name;
762         if (name == "[")
763                 return name;
764         if (name == ".")
765                 return name;
766         if (name == ")")
767                 return name;
768         if (name == "]")
769                 return name;
770         if (name == "/")
771                 return name;
772         if (name == "|")
773                 return name;
774         return "\\" + name + " ";
775 }
776
777