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