]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
overightarrow -> overrightarrow
[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 float matriz_data[2][2];
30         ///
31         Matrix();
32         ///
33         void rotate(int);
34         ///
35         void escalate(float, float);
36         ///
37         void transform(float, float, float &, float &);
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         float const cs = (code & 1) ? 0 : (1 - code);
61         float 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(float x, float 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(float xp, float yp, float & x, float & 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 float 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 float 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 float 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 float 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 float 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 float 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 float 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 float 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 float 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 float const angle[] = {
388         2.0, 3,
389         1, 0,  0.05, 0.5,  1, 1,
390         0.0
391 };
392
393
394 float const slash[] = {
395         1, 0.95, 0.05,  0.05, 0.95, 
396         0.0
397 };
398
399
400 float const hline[] = {
401         1, 0.05, 0.5,  0.95, 0.5, 
402         0.0
403 };
404
405
406 float 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 float 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 float 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 float const hlinesmall[] = {
430         1, 0.4, 0.5,  0.6, 0.5, 
431         0.0
432 };
433
434
435 float const vert[] = {
436         1, 0.5, 0.05,  0.5, 0.95, 
437         0.0
438 };
439
440
441 float 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 float 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         float const * data;
457         int angle;
458 };
459
460 struct named_deco_struct {
461         char const * name;
462         float 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         {"langle",       angle,      0 },
489         {"lceil",        corner,     0 }, 
490         {"lfloor",       corner,     1 },  
491         {"rangle",       angle,      2 }, 
492         {"rceil",        corner,     3 }, 
493         {"rfloor",       corner,     2 },
494         {"downarrow",    arrow,      2 },
495         {"Downarrow",    Arrow,      2 }, 
496         {"uparrow",      arrow,      0 },
497         {"Uparrow",      Arrow,      0 },
498         {"updownarrow",  udarrow,    0 },
499         {"Updownarrow",  Udarrow,    0 },        
500                                                           
501         // Accents
502         {"ddot",         hline2,     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(MathTextCodes type, MathStyles size, unsigned char c,
551         int & asc, int & des, int & wid)
552 {
553         LyXFont const font = whichFont(type, size);
554         des = lyxfont::descent(c, font);
555         asc = lyxfont::ascent(c, font);
556         wid = mathed_char_width(type, size, c);
557 }
558
559
560 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c,
561         int & asc, int & des)
562 {
563         LyXFont const font = whichFont(type, size);
564         des = lyxfont::descent(c, font);
565         asc = lyxfont::ascent(c, font);
566         return asc + des;
567 }
568
569
570 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c)
571 {
572         int asc;
573         int des;
574         return mathed_char_height(type, size, c, asc, des);
575 }
576
577
578 int mathed_char_ascent(MathTextCodes type, MathStyles size, unsigned char c)
579 {
580         LyXFont const font = whichFont(type, size);
581         return lyxfont::ascent(c, font);
582 }
583
584
585 int mathed_char_descent(MathTextCodes type, MathStyles size, unsigned char c)
586 {
587         LyXFont const font = whichFont(type, size);
588         return lyxfont::descent(c, font);
589 }
590
591
592 int mathed_char_width(MathTextCodes type, MathStyles size, unsigned char c)
593 {
594         LyXFont const font = whichFont(type, size);
595         LyXFont const f1 = whichFont(LM_TC_TEXTRM, size);
596 #warning why f1 is used ?
597         if (isBinaryOp(c, type))
598                 return lyxfont::width(c, font) + 2 * lyxfont::width(' ', f1);
599         else
600                 return lyxfont::width(c, font);
601 }
602
603
604 void mathed_string_dim(MathTextCodes type, MathStyles size, string const & s,
605                          int & asc, int & des, int & wid)
606 {
607         mathed_string_height(type, size, s, asc, des);
608         wid = mathed_string_width(type, size, s);
609 }
610
611
612 int mathed_string_height(MathTextCodes type, MathStyles size, string const & s,
613                          int & asc, int & des)
614 {
615         LyXFont const font = whichFont(type, size);
616         asc = des = 0;
617         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
618                 des = max(des, lyxfont::descent(*it, font));
619                 asc = max(asc, lyxfont::ascent(*it, font));
620         }
621         return asc + des;
622 }
623
624
625 int mathed_string_width(MathTextCodes type, MathStyles size, string const & s)
626 {
627         return lyxfont::width(s, whichFont(type, size));
628 }
629
630
631 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
632         const string & name)
633 {
634         Matrix mt;
635         Matrix sqmt;
636         int i = 0;
637
638         if (name == ".") {
639                 pain.line(x + w/2, y, x + w/2, y + h,
640                           LColor::mathcursor, Painter::line_onoffdash);
641                 return;
642         }       
643         
644         deco_struct const * mds = search_deco(name);
645         if (!mds) {
646                 lyxerr << "Deco was not found. Programming error?\n";
647                 lyxerr << "name: '" << name << "\n";
648                 return;
649         }
650         
651         int const r = mds->angle;
652         float const * d = mds->data;
653         
654         if (h > 70 && (name == "(" || name == ")"))
655                 d = parenthHigh;
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         int code;
672         do {
673                 float xx;
674                 float yy;
675                 float x2;
676                 float y2;
677
678                 code = int(d[i++]);
679                 switch (code) {
680                 case 0: break;
681                 case 1: 
682                 case 3:
683                 {
684                         xx = d[i++]; yy = d[i++];
685                         x2 = d[i++]; y2 = d[i++];
686                         if (code == 3) 
687                                 sqmt.transform(xx, yy, xx, yy);
688                         else
689                                 mt.transform(xx, yy, xx, yy);
690                         mt.transform(x2, y2, x2, y2);
691                         pain.line(x + int(xx), y + int(yy),
692                                   x + int(x2), y + int(y2),
693                                   LColor::mathline);
694                         break;
695                 }        
696                 case 2: 
697                 case 4:
698                 {
699                         int xp[32];
700                         int yp[32];
701                         int const n = int(d[i++]);
702                         for (int j = 0; j < n; ++j) {
703                                 xx = d[i++]; yy = d[i++];
704 //           lyxerr << " " << xx << " " << yy << " ";
705                                 if (code == 4) 
706                                         sqmt.transform(xx, yy, xx, yy);
707                                 else
708                                         mt.transform(xx, yy, xx, yy);
709                                 xp[j] = x + int(xx);
710                                 yp[j] = y + int(yy);
711                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
712                         }
713                         pain.lines(xp, yp, n, LColor::mathline);
714                 }
715                 }
716         } while (code);
717 }
718
719
720 // In the future maybe we use a better fonts renderer
721 void drawStr(Painter & pain, MathTextCodes type, MathStyles siz,
722         int x, int y, string const & s)
723 {
724         pain.text(x, y, s, whichFont(type, siz));
725 }
726
727
728 void drawChar
729         (Painter & pain, MathTextCodes type, MathStyles siz, int x, int y, char c)
730 {
731         string s;
732         if (isBinaryOp(c, type))
733                 s += ' ';
734         s += c;
735         if (isBinaryOp(c, type))
736                 s += ' ';
737         drawStr(pain, type, siz, x, y, s);
738 }
739
740
741 // decrease math size for super- and subscripts
742 MathStyles smallerStyleScript(MathStyles st)
743 {
744         switch (st) {
745                 case LM_ST_DISPLAY:
746                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
747                 default:            st = LM_ST_SCRIPTSCRIPT;
748         }
749         return st;
750 }
751
752
753 // decrease math size for fractions
754 MathStyles smallerStyleFrac(MathStyles st)
755 {
756         switch (st) {
757                 case LM_ST_DISPLAY: st = LM_ST_TEXT; break;
758                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
759                 default:            st = LM_ST_SCRIPTSCRIPT;
760         }
761         return st;
762 }
763
764
765 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
766 {
767         LyXFont font = whichFont(code, siz);
768         asc = lyxfont::maxAscent(font);
769         des = lyxfont::maxDescent(font);
770 }
771
772
773 char const * latex_mathspace[] = {
774         "!", ",", ":", ";", "quad", "qquad"
775 };