]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
brush off the decoration drawing code a bit
[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         Matrix(int, double, double);
30         ///
31         void transform(double &, double &);
32 private:
33         ///
34         double m_[2][2];
35 };
36
37
38 Matrix::Matrix(int code, double x, double y)
39 {
40         double const cs = (code & 1) ? 0 : (1 - code);
41         double const sn = (code & 1) ? (2 - code) : 0;
42         m_[0][0] =  cs * x;
43         m_[0][1] =  sn * x;
44         m_[1][0] = -sn * y;
45         m_[1][1] =  cs * y;
46 }
47
48
49 void Matrix::transform(double & x, double & y)
50 {
51         double xx = m_[0][0] * x + m_[0][1] * y;
52         double yy = m_[1][0] * x + m_[1][1] * y;
53         x = xx;
54         y = yy;
55 }
56
57
58 namespace {
59
60 LyXFont * MathFonts = 0;
61 bool font_available[LM_FONT_END];
62 bool font_available_initialized[LM_FONT_END];
63
64 enum MathFont {
65         FONT_IT,
66         FONT_SYMBOL,
67         FONT_SYMBOLI,
68         FONT_BF,
69         FONT_BB,
70         FONT_CAL,
71         FONT_TT,
72         FONT_RM,
73         FONT_SF,
74         FONT_CMR,
75         FONT_CMSY,
76         FONT_CMM,
77         FONT_CMEX,
78         FONT_MSA,
79         FONT_MSB,
80         FONT_NUM
81 };
82
83 void mathed_init_fonts()
84 {
85         MathFonts = new LyXFont[FONT_NUM]; //DEC cxx cannot initialize all fonts
86         //at once (JMarc) rc
87
88         for (int i = 0 ; i < FONT_NUM ; ++i) {
89                 MathFonts[i] = LyXFont(LyXFont::ALL_SANE);
90         }
91
92         MathFonts[FONT_IT].setShape(LyXFont::ITALIC_SHAPE);
93
94         MathFonts[FONT_SYMBOL].setFamily(LyXFont::SYMBOL_FAMILY);
95
96         MathFonts[FONT_SYMBOLI].setFamily(LyXFont::SYMBOL_FAMILY);
97         MathFonts[FONT_SYMBOLI].setShape(LyXFont::ITALIC_SHAPE);
98
99         MathFonts[FONT_BF].setSeries(LyXFont::BOLD_SERIES);
100
101         MathFonts[FONT_BB].setSeries(LyXFont::BOLD_SERIES);
102         MathFonts[FONT_BB].setFamily(LyXFont::TYPEWRITER_FAMILY);
103
104         MathFonts[FONT_CAL].setFamily(LyXFont::SANS_FAMILY);
105         MathFonts[FONT_CAL].setShape(LyXFont::ITALIC_SHAPE);
106
107         MathFonts[FONT_TT].setFamily(LyXFont::TYPEWRITER_FAMILY);
108
109         MathFonts[FONT_RM].setFamily(LyXFont::ROMAN_FAMILY);
110
111         MathFonts[FONT_SF].setFamily(LyXFont::SANS_FAMILY);
112
113         MathFonts[FONT_CMR].setFamily(LyXFont::CMR_FAMILY);
114         MathFonts[FONT_CMSY].setFamily(LyXFont::CMSY_FAMILY);
115         MathFonts[FONT_CMM].setFamily(LyXFont::CMM_FAMILY);
116         MathFonts[FONT_CMEX].setFamily(LyXFont::CMEX_FAMILY);
117         MathFonts[FONT_MSA].setFamily(LyXFont::MSA_FAMILY);
118         MathFonts[FONT_MSB].setFamily(LyXFont::MSB_FAMILY);
119
120         for (int i = 0; i < LM_FONT_END; ++i)
121                 font_available_initialized[i] = false;
122 }
123
124
125 LyXFont const & whichFontBase(MathTextCodes type)
126 {
127         if (!MathFonts)
128                 mathed_init_fonts();
129
130         switch (type) {
131         case LM_TC_SYMB:        
132         case LM_TC_BOLDSYMB:    
133                 return MathFonts[FONT_SYMBOLI];
134
135         case LM_TC_VAR:
136         case LM_TC_IT:
137                 return MathFonts[FONT_IT];
138
139         case LM_TC_BF:
140                 return MathFonts[FONT_BF];
141
142         case LM_TC_BB:
143                 if (math_font_available(LM_TC_MSB))
144                         return MathFonts[FONT_MSB];
145                 else
146                         return MathFonts[FONT_BB];
147
148         case LM_TC_CAL:
149                 if (math_font_available(LM_TC_CMSY))
150                         return MathFonts[FONT_CMSY];
151                 else
152                         return MathFonts[FONT_CAL];
153
154         case LM_TC_TT:
155                 return MathFonts[FONT_TT];
156
157         case LM_TC_TEXTRM:
158         case LM_TC_CONST:
159         case LM_TC_TEX:
160         case LM_TC_RM:
161                 return MathFonts[FONT_RM];
162
163         case LM_TC_SF:
164                 return MathFonts[FONT_SF];
165
166         case LM_TC_CMR:
167                 return MathFonts[FONT_CMR];
168
169         case LM_TC_CMSY:
170                 return MathFonts[FONT_CMSY];
171
172         case LM_TC_CMM:
173                 return MathFonts[FONT_CMM];
174
175         case LM_TC_CMEX:
176                 return MathFonts[FONT_CMEX];
177
178         case LM_TC_MSA:
179                 return MathFonts[FONT_MSA];
180
181         case LM_TC_MSB:
182                 return MathFonts[FONT_MSB];
183
184         default:
185                 break;
186         }
187         return MathFonts[1];
188 }
189
190
191 LyXFont whichFont(MathTextCodes type, MathStyles size)
192 {
193         LyXFont f = whichFontBase(type);
194
195         switch (size) {
196         case LM_ST_DISPLAY:
197                 if (type == LM_TC_BOLDSYMB || type == LM_TC_CMEX) {
198                         f.incSize();
199                         f.incSize();
200                 }
201                 break;
202
203         case LM_ST_TEXT:
204                 break;
205
206         case LM_ST_SCRIPT:
207                 f.decSize();
208                 f.decSize();
209                 break;
210
211         case LM_ST_SCRIPTSCRIPT:
212                 f.decSize();
213                 f.decSize();
214                 f.decSize();
215                 break;
216
217         default:
218                 lyxerr << "Math Error: wrong font size: " << size << endl;
219                 break;
220         }
221
222         if (type != LM_TC_TEXTRM)
223                 f.setColor(LColor::math);
224
225         if (type == LM_TC_TEX)
226                 f.setColor(LColor::latex);
227
228         return f;
229 }
230
231 } // namespace
232
233
234 bool math_font_available(MathTextCodes type)
235 {
236         if (!font_available_initialized[type]) {
237                 font_available_initialized[type] = true;
238                 font_available[type] = 
239                         fontloader.available(whichFontBase(type));
240         }
241         return font_available[type];
242 }
243
244
245 namespace {
246
247 /* 
248  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
249  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
250  */
251
252
253 double const parenthHigh[] = {
254         2.0, 13.0,
255         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
256         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
257         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
258         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
259         0.9840, 0.9986,
260         0.0 
261 };
262
263
264 double const parenth[] = {
265         2.0, 13.0,
266         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
267         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
268         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
269         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
270         0.9930, 0.9919,
271         0.0   
272 };
273
274
275 double const brace[] = {
276         2.0, 21.0,
277         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
278         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
279         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
280         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
281         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
282         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
283         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
284         0.0
285 };
286
287
288 // Is this correct? (Lgb)
289 double const arrow[] = {
290         4, 7,
291         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
292         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
293         0.9500, 0.7500,
294         3, 0.5000, 0.1500, 0.5000, 0.9500,
295         0.0 
296 };
297
298
299 // Is this correct? (Lgb)
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.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.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.0 
329 };
330
331
332 double const brack[] = {
333         2.0, 4,
334         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
335         0.0
336 };
337
338
339 double const corner[] = {
340         2.0, 3,
341         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
342         0.0
343 };
344
345
346 double const angle[] = {
347         2.0, 3,
348         1, 0,  0.05, 0.5,  1, 1,
349         0.0
350 };
351
352
353 double const slash[] = {
354         1, 0.95, 0.05,  0.05, 0.95, 
355         0.0
356 };
357
358
359 double const hline[] = {
360         1, 0.05, 0.5,  0.95, 0.5, 
361         0.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.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.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.0
385 };     
386
387
388 double const hlinesmall[] = {
389         1, 0.4, 0.5,  0.6, 0.5, 
390         0.0
391 };
392
393
394 double const vert[] = {
395         1, 0.5, 0.05,  0.5, 0.95, 
396         0.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.0
404 };
405
406
407 double const tilde[] = {
408         2.0, 4,
409         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
410         0.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, MathStyles size, unsigned char c,
511         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, MathStyles size, unsigned char c,
521         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, MathStyles size, unsigned char c)
531 {
532         int asc;
533         int des;
534         return mathed_char_height(type, size, c, asc, des);
535 }
536
537
538 int mathed_char_ascent(MathTextCodes type, MathStyles size, unsigned char c)
539 {
540         LyXFont const font = whichFont(type, size);
541         return lyxfont::ascent(c, font);
542 }
543
544
545 int mathed_char_descent(MathTextCodes type, MathStyles size, unsigned char c)
546 {
547         LyXFont const font = whichFont(type, size);
548         return lyxfont::descent(c, font);
549 }
550
551
552 int mathed_char_width(MathTextCodes type, MathStyles size, unsigned char c)
553 {
554         LyXFont const font = whichFont(type, size);
555         LyXFont const f1 = whichFont(LM_TC_TEXTRM, size);
556 #warning why f1 is used ?
557         if (isBinaryOp(c, type))
558                 return lyxfont::width(c, font) + 2 * lyxfont::width(' ', f1);
559         else
560                 return lyxfont::width(c, font);
561 }
562
563
564 void mathed_string_dim(MathTextCodes type, MathStyles size, string const & s,
565                          int & asc, int & des, int & wid)
566 {
567         mathed_string_height(type, size, s, asc, des);
568         wid = mathed_string_width(type, size, s);
569 }
570
571
572 int mathed_string_height(MathTextCodes type, MathStyles size, string const & s,
573                          int & asc, int & des)
574 {
575         LyXFont const font = whichFont(type, size);
576         asc = des = 0;
577         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
578                 des = max(des, lyxfont::descent(*it, font));
579                 asc = max(asc, lyxfont::ascent(*it, font));
580         }
581         return asc + des;
582 }
583
584
585 int mathed_string_width(MathTextCodes type, MathStyles size, string const & s)
586 {
587         return lyxfont::width(s, whichFont(type, size));
588 }
589
590
591 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
592         const string & name)
593 {
594         if (name == ".") {
595                 pain.line(x + w/2, y, x + w/2, y + h,
596                           LColor::mathcursor, Painter::line_onoffdash);
597                 return;
598         }       
599         
600         deco_struct const * mds = search_deco(name);
601         if (!mds) {
602                 lyxerr << "Deco was not found. Programming error?\n";
603                 lyxerr << "name: '" << name << "'\n";
604                 return;
605         }
606         
607         int const n = (w < h) ? w : h;
608         int const r = mds->angle;
609         double const * d = mds->data;
610         
611         if (h > 70 && (name == "(" || name == ")"))
612                 d = parenthHigh;
613         
614         Matrix mt(r, w, h);
615         Matrix sqmt(r, n, n);
616
617         if (r > 0 && r < 3)
618                 y += h;
619
620         if (r >= 2)
621                 x += w;   
622
623         for (int i = 0; d[i]; ) {
624                 int code = int(d[i++]);
625                 if (code & 1) {  // code == 1 || code == 3
626                         double xx = d[i++];
627                         double yy = d[i++];
628                         double x2 = d[i++];
629                         double y2 = d[i++];
630                         if (code == 3) 
631                                 sqmt.transform(xx, yy);
632                         else
633                                 mt.transform(xx, yy);
634                         mt.transform(x2, y2);
635                         pain.line(x + int(xx), y + int(yy), x + int(x2), y + int(y2),
636                                         LColor::mathline);
637                 }       else {
638                         int xp[32];
639                         int yp[32];
640                         int const n = int(d[i++]);
641                         for (int j = 0; j < n; ++j) {
642                                 double xx = d[i++];
643                                 double yy = d[i++];
644 //           lyxerr << " " << xx << " " << yy << " ";
645                                 if (code == 4) 
646                                         sqmt.transform(xx, yy);
647                                 else
648                                         mt.transform(xx, yy);
649                                 xp[j] = x + int(xx);
650                                 yp[j] = y + int(yy);
651                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
652                         }
653                         pain.lines(xp, yp, n, LColor::mathline);
654                 }
655         }
656 }
657
658
659 // In the future maybe we use a better fonts renderer
660 void drawStr(Painter & pain, MathTextCodes type, MathStyles siz,
661         int x, int y, string const & s)
662 {
663         pain.text(x, y, s, whichFont(type, siz));
664 }
665
666
667 void drawChar
668         (Painter & pain, MathTextCodes type, MathStyles siz, int x, int y, char c)
669 {
670         string s;
671         if (isBinaryOp(c, type))
672                 s += ' ';
673         s += c;
674         if (isBinaryOp(c, type))
675                 s += ' ';
676         drawStr(pain, type, siz, x, y, s);
677 }
678
679
680 // decrease math size for super- and subscripts
681 MathStyles smallerStyleScript(MathStyles st)
682 {
683         switch (st) {
684                 case LM_ST_DISPLAY:
685                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
686                 default:            st = LM_ST_SCRIPTSCRIPT;
687         }
688         return st;
689 }
690
691
692 // decrease math size for fractions
693 MathStyles smallerStyleFrac(MathStyles st)
694 {
695         switch (st) {
696                 case LM_ST_DISPLAY: st = LM_ST_TEXT; break;
697                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
698                 default:            st = LM_ST_SCRIPTSCRIPT;
699         }
700         return st;
701 }
702
703
704 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
705 {
706         LyXFont font = whichFont(code, siz);
707         asc = lyxfont::maxAscent(font);
708         des = lyxfont::maxDescent(font);
709 }
710
711
712 char const * latex_mathspace[] = {
713         "!", ",", ":", ";", "quad", "qquad"
714 };