]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
fix delimiter handling for \, |, and /
[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         {"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         Matrix mt;
636         Matrix sqmt;
637         int i = 0;
638
639         if (name == ".") {
640                 pain.line(x + w/2, y, x + w/2, y + h,
641                           LColor::mathcursor, Painter::line_onoffdash);
642                 return;
643         }       
644         
645         deco_struct const * mds = search_deco(name);
646         if (!mds) {
647                 lyxerr << "Deco was not found. Programming error?\n";
648                 lyxerr << "name: '" << name << "'\n";
649                 return;
650         }
651         
652         int const r = mds->angle;
653         float const * d = mds->data;
654         
655         if (h > 70 && (name == "(" || name == ")"))
656                 d = parenthHigh;
657         
658         mt.rotate(r);
659         mt.escalate(w, h);
660         
661         int const n = (w < h) ? w : h;
662
663         sqmt.rotate(r);
664         sqmt.escalate(n, n);
665
666         if (r > 0 && r < 3)
667                 y += h;
668
669         if (r >= 2)
670                 x += w;   
671
672         int code;
673         do {
674                 float xx;
675                 float yy;
676                 float x2;
677                 float y2;
678
679                 code = int(d[i++]);
680                 switch (code) {
681                 case 0: break;
682                 case 1: 
683                 case 3:
684                 {
685                         xx = d[i++]; yy = d[i++];
686                         x2 = d[i++]; y2 = d[i++];
687                         if (code == 3) 
688                                 sqmt.transform(xx, yy, xx, yy);
689                         else
690                                 mt.transform(xx, yy, xx, yy);
691                         mt.transform(x2, y2, x2, y2);
692                         pain.line(x + int(xx), y + int(yy),
693                                   x + int(x2), y + int(y2),
694                                   LColor::mathline);
695                         break;
696                 }        
697                 case 2: 
698                 case 4:
699                 {
700                         int xp[32];
701                         int yp[32];
702                         int const n = int(d[i++]);
703                         for (int j = 0; j < n; ++j) {
704                                 xx = d[i++]; yy = d[i++];
705 //           lyxerr << " " << xx << " " << yy << " ";
706                                 if (code == 4) 
707                                         sqmt.transform(xx, yy, xx, yy);
708                                 else
709                                         mt.transform(xx, yy, xx, yy);
710                                 xp[j] = x + int(xx);
711                                 yp[j] = y + int(yy);
712                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
713                         }
714                         pain.lines(xp, yp, n, LColor::mathline);
715                 }
716                 }
717         } while (code);
718 }
719
720
721 // In the future maybe we use a better fonts renderer
722 void drawStr(Painter & pain, MathTextCodes type, MathStyles siz,
723         int x, int y, string const & s)
724 {
725         pain.text(x, y, s, whichFont(type, siz));
726 }
727
728
729 void drawChar
730         (Painter & pain, MathTextCodes type, MathStyles siz, int x, int y, char c)
731 {
732         string s;
733         if (isBinaryOp(c, type))
734                 s += ' ';
735         s += c;
736         if (isBinaryOp(c, type))
737                 s += ' ';
738         drawStr(pain, type, siz, x, y, s);
739 }
740
741
742 // decrease math size for super- and subscripts
743 MathStyles smallerStyleScript(MathStyles st)
744 {
745         switch (st) {
746                 case LM_ST_DISPLAY:
747                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
748                 default:            st = LM_ST_SCRIPTSCRIPT;
749         }
750         return st;
751 }
752
753
754 // decrease math size for fractions
755 MathStyles smallerStyleFrac(MathStyles st)
756 {
757         switch (st) {
758                 case LM_ST_DISPLAY: st = LM_ST_TEXT; break;
759                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
760                 default:            st = LM_ST_SCRIPTSCRIPT;
761         }
762         return st;
763 }
764
765
766 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
767 {
768         LyXFont font = whichFont(code, siz);
769         asc = lyxfont::maxAscent(font);
770         des = lyxfont::maxDescent(font);
771 }
772
773
774 char const * latex_mathspace[] = {
775         "!", ",", ":", ";", "quad", "qquad"
776 };