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