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