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