]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
new parser
[lyx.git] / src / mathed / support.C
1 #include <config.h>
2
3 #include <algorithm>
4
5 #include "mathed/support.h"
6 #include "lyxfont.h"
7 #include "font.h"
8 #include "math_defs.h"
9 #include "math_parser.h"
10 #include "Painter.h"
11 #include "debug.h"
12
13 using std::sort;
14 using std::lower_bound;
15 using std::endl;
16 using std::max;
17
18
19 bool isBinaryOp(char c)
20 {
21         return 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           * Math_Fonts = 0;
102
103 void mathed_init_fonts()
104 {
105         Math_Fonts = new LyXFont[8]; //DEC cxx cannot initialize all fonts
106         //at once (JMarc) rc
107
108         for (int i = 0 ; i < 8 ; ++i) {
109                 Math_Fonts[i] = LyXFont(LyXFont::ALL_SANE);
110         }
111
112         Math_Fonts[0].setShape(LyXFont::ITALIC_SHAPE);
113
114         Math_Fonts[1].setFamily(LyXFont::SYMBOL_FAMILY);
115
116         Math_Fonts[2].setFamily(LyXFont::SYMBOL_FAMILY);
117         Math_Fonts[2].setShape(LyXFont::ITALIC_SHAPE);
118
119         Math_Fonts[3].setSeries(LyXFont::BOLD_SERIES);
120
121         Math_Fonts[4].setFamily(LyXFont::SANS_FAMILY);
122         Math_Fonts[4].setShape(LyXFont::ITALIC_SHAPE);
123
124         Math_Fonts[5].setFamily(LyXFont::TYPEWRITER_FAMILY);
125
126         Math_Fonts[6].setFamily(LyXFont::ROMAN_FAMILY);
127
128         Math_Fonts[7].setFamily(LyXFont::SANS_FAMILY);
129 }
130
131 } // namespace
132
133
134 LyXFont WhichFont(MathTextCodes type, MathStyles size)
135 {
136         LyXFont f;
137         
138         if (!Math_Fonts)
139                 mathed_init_fonts();
140
141         switch (type) {
142         case LM_TC_SYMB:        
143         case LM_TC_BSYM:        
144                 f = Math_Fonts[2];
145                 break;
146
147         case LM_TC_VAR:
148         case LM_TC_IT:
149                 f = Math_Fonts[0];
150                 break;
151
152         case LM_TC_BF:
153                 f = Math_Fonts[3];
154                 break;
155
156         case LM_TC_SF:
157                 f = Math_Fonts[7];
158                 break;
159
160         case LM_TC_CAL:
161                 f = Math_Fonts[4];
162                 break;
163
164         case LM_TC_TT:
165                 f = Math_Fonts[5];
166                 break;
167
168         case LM_TC_SPECIAL: //f = Math_Fonts[0]; break;
169         case LM_TC_TEXTRM:
170         case LM_TC_TEX:
171         case LM_TC_RM:
172                 f = Math_Fonts[6];
173                 break;
174
175         default:
176                 f = Math_Fonts[1];
177                 break;
178         }
179
180         switch (size) {
181         case LM_ST_DISPLAY:
182                 if (type == LM_TC_BSYM) {
183                         f.incSize();
184                         f.incSize();
185                 }
186                 break;
187
188         case LM_ST_TEXT:
189                 break;
190
191         case LM_ST_SCRIPT:
192                 f.decSize();
193                 f.decSize();
194                 break;
195
196         case LM_ST_SCRIPTSCRIPT:
197                 f.decSize();
198                 f.decSize();
199                 f.decSize();
200                 break;
201
202         default:
203                 lyxerr << "Math Error: wrong font size: " << size << endl;
204                 break;
205         }
206
207         if (type != LM_TC_TEXTRM)
208                 f.setColor(LColor::math);
209
210         if (type == LM_TC_TEX)
211                 f.setColor(LColor::latex);
212
213         return f;
214 }
215
216 char const * math_font_name[] = {
217         "mathrm",
218         "mathcal",
219         "mathbf",
220         "mathsf",
221         "mathtt",
222         "mathit",
223         "textrm"
224 };
225
226
227 namespace {
228
229 /* 
230  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
231  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
232  */
233
234
235 float const parenthHigh[] = {
236         2.0, 13.0,
237         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
238         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
239         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
240         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
241         0.9840, 0.9986,
242         0.0 
243 };
244
245
246 float const parenth[] = {
247         2.0, 13.0,
248         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
249         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
250         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
251         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
252         0.9930, 0.9919,
253         0.0   
254 };
255
256
257 float const brace[] = {
258         2.0, 21.0,
259         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
260         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
261         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
262         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
263         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
264         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
265         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
266         0.0
267 };
268
269
270 // Is this correct? (Lgb)
271 float const arrow[] = {
272         4, 7,
273         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
274         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
275         0.9500, 0.7500,
276         3, 0.5000, 0.1500, 0.5000, 0.9500,
277         0.0 
278 };
279
280
281 // Is this correct? (Lgb)
282 float const Arrow[] = {
283         4, 7,
284         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
285         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
286         0.9500, 0.7500,
287         3, 0.3500, 0.5000, 0.3500, 0.9500,
288         3, 0.6500, 0.5000, 0.6500, 0.9500,
289         0.0
290 };
291
292
293 float const udarrow[] = {
294         2, 3,
295         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
296         2, 3,
297         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,  
298         1, 0.5, 0.2,  0.5, 0.8,
299         0.0 
300 };
301
302
303 float const Udarrow[] = {
304         2, 3,
305         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
306         2, 3,
307         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,  
308         1, 0.35, 0.2, 0.35, 0.8,
309         1, 0.65, 0.2, 0.65, 0.8,
310         0.0 
311 };
312
313
314 float const brack[] = {
315         2.0, 4,
316         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
317         0.0
318 };
319
320
321 float const corner[] = {
322         2.0, 3,
323         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
324         0.0
325 };
326
327
328 float const angle[] = {
329         2.0, 3,
330         1, 0,  0.05, 0.5,  1, 1,
331         0.0
332 };
333
334
335 float const slash[] = {
336         1, 0.95, 0.05,  0.05, 0.95, 
337         0.0
338 };
339
340
341 float const hline[] = {
342         1, 0.05, 0.5,  0.95, 0.5, 
343         0.0
344 };
345
346
347 float const hline2[] = {
348    1, 0.1, 0.5,  0.3, 0.5,
349    1, 0.7, 0.5,  0.9, 0.5,
350    0.0
351 }; 
352
353
354 float const hline3[] = {
355         1, 0.1, 0,  0.15, 0,
356         1, 0.475, 0,  0.525, 0,
357         1, 0.85, 0,  0.9, 0,  
358         0.0
359 };
360
361
362 float const dline3[] = {
363         1, 0.1, 0.1,  0.15, 0.15,
364         1, 0.475, 0.475,  0.525, 0.525,
365         1, 0.85, 0.85,  0.9, 0.9,
366         0.0
367 };     
368
369
370 float const hlinesmall[] = {
371         1, 0.4, 0.5,  0.6, 0.5, 
372         0.0
373 };
374
375
376 float const vert[] = {
377         1, 0.5, 0.05,  0.5, 0.95, 
378         0.0
379 };
380
381
382 float const  Vert[] = {
383         1, 0.3, 0.05,  0.3, 0.95, 
384         1, 0.7, 0.05,  0.7, 0.95,
385         0.0
386 };
387
388
389 float const tilde[] = {
390         2.0, 4,
391         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
392         0.0
393 };
394
395
396 struct deco_struct {
397         int code;
398         float const * data;
399         int angle;
400 };
401
402 deco_struct deco_table[] = {   
403         // Decorations
404         { LM_widehat,       &angle[0],      3 },
405         { LM_widetilde,     &tilde[0],      0 },
406         { LM_underline,     &hline[0],      0 },
407         { LM_overline,      &hline[0],      0 },
408         { LM_underbrace,    &brace[0],      1 },
409         { LM_overbrace,     &brace[0],      3 },
410         { LM_overleftarrow, &arrow[0],      1 },
411         { LM_overightarrow, &arrow[0],      3 },
412                                             
413         // Delimiters                       
414         { '(',              &parenth[0],    0 },
415         { ')',              &parenth[0],    2 },
416         { '{',              &brace[0],      0 },
417         { '}',              &brace[0],      2 },
418         { '[',              &brack[0],      0 },
419         { ']',              &brack[0],      2 },
420         { '|',              &vert[0],       0 },
421         { '/',              &slash[0],      0 },
422         { LM_Vert,          &Vert[0],       0 },
423         { '\\',             &slash[0],      1 },
424         { LM_langle,        &angle[0],      0 },
425         { LM_lceil,         &corner[0],     0 }, 
426         { LM_lfloor,        &corner[0],     1 },  
427         { LM_rangle,        &angle[0],      2 }, 
428         { LM_rceil,         &corner[0],     3 }, 
429         { LM_rfloor,        &corner[0],     2 },
430         { LM_downarrow,     &arrow[0],      2 },
431         { LM_Downarrow,     &Arrow[0],      2 }, 
432         { LM_uparrow,       &arrow[0],      0 },
433         { LM_Uparrow,       &Arrow[0],      0 },
434         { LM_updownarrow,   &udarrow[0],    0 },
435         { LM_Updownarrow,   &Udarrow[0],    0 },         
436                                             
437         // Accents                          
438         { LM_ddot,          &hline2[0],     0 },
439         { LM_hat,           &angle[0],      3 },
440         { LM_grave,         &slash[0],      1 },
441         { LM_acute,         &slash[0],      0 },
442         { LM_tilde,         &tilde[0],      0 },
443         { LM_bar,           &hline[0],      0 },
444         { LM_dot,           &hlinesmall[0], 0 },
445         { LM_check,         &angle[0],      1 },
446         { LM_breve,         &parenth[0],    1 },
447         { LM_vec,           &arrow[0],      3 },
448         { LM_not,           &slash[0],      0 },  
449                                             
450         // Dots                             
451         { LM_ldots,         &hline3[0],     0 }, 
452         { LM_cdots,         &hline3[0],     0 },
453         { LM_vdots,         &hline3[0],     1 },
454         { LM_ddots,         &dline3[0],     0 }
455 };
456
457
458 struct deco_compare {
459         /// for use by sort and lower_bound
460         int operator()(deco_struct const & a, deco_struct const & b) const
461         {
462                 return a.code < b.code;
463         }
464 };
465
466
467 int const deco_table_size =
468         sizeof(deco_table) / sizeof(deco_struct);
469
470
471 // sort the table on startup
472 struct init_deco_table {
473         init_deco_table() {
474                         std::sort(deco_table,
475                              deco_table + deco_table_size,
476                              deco_compare());
477         }
478 };
479
480 static init_deco_table dummy;
481
482
483 deco_struct const * search_deco(int code)
484 {
485         const deco_struct search_elem = { code, 0, 0 };
486         
487         deco_struct const * res =
488                 lower_bound(deco_table, deco_table + deco_table_size, search_elem,
489                         deco_compare());
490         if (res != deco_table + deco_table_size &&
491             res->code == code)
492                 return res;
493         return 0;
494 }
495
496
497 } // namespace anon
498
499
500 void mathed_char_dim(MathTextCodes type, MathStyles size, unsigned char c,
501         int & asc, int & des, int & wid)
502 {
503         LyXFont const font = WhichFont(type, size);
504         des = lyxfont::descent(c, font);
505         asc = lyxfont::ascent(c, font);
506         wid = mathed_char_width(type, size, c);
507 }
508
509
510 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c,
511         int & asc, int & des)
512 {
513         LyXFont const font = WhichFont(type, size);
514         des = lyxfont::descent(c, font);
515         asc = lyxfont::ascent(c, font);
516         return asc + des;
517 }
518
519
520 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c)
521 {
522         int asc;
523         int des;
524         return mathed_char_height(type, size, c, asc, des);
525 }
526
527 int mathed_char_ascent(MathTextCodes type, MathStyles size, unsigned char c)
528 {
529         LyXFont const font = WhichFont(type, size);
530         return lyxfont::ascent(c, font);
531 }
532
533 int mathed_char_descent(MathTextCodes type, MathStyles size, unsigned char c)
534 {
535         LyXFont const font = WhichFont(type, size);
536         return lyxfont::descent(c, font);
537 }
538
539 int mathed_char_width(MathTextCodes type, MathStyles size, unsigned char c)
540 {
541         LyXFont const font = WhichFont(type, size);
542         if (isBinaryOp(c))
543                 return lyxfont::width(c, font) + 2 * lyxfont::width(' ', font);
544         else
545                 return lyxfont::width(c, font);
546 }
547
548
549 void mathed_string_dim(MathTextCodes type, MathStyles size, string const & s,
550                          int & asc, int & des, int & wid)
551 {
552         mathed_string_height(type, size, s, asc, des);
553         wid = mathed_string_width(type, size, s);
554 }
555
556 int mathed_string_height(MathTextCodes type, MathStyles size, string const & s,
557                          int & asc, int & des)
558 {
559         LyXFont const font = WhichFont(type, size);
560         asc = des = 0;
561         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
562                 des = max(des, lyxfont::descent(*it, font));
563                 asc = max(asc, lyxfont::ascent(*it, font));
564         }
565         return asc + des;
566 }
567
568 int mathed_string_width(MathTextCodes type, MathStyles size, string const & s)
569 {
570         return lyxfont::width(s, WhichFont(type, size));
571 }
572
573
574 void mathed_draw_deco(Painter & pain, int x, int y, int w, int h,
575         latexkeys const * l)
576 {
577         Matrix mt;
578         Matrix sqmt;
579         int i = 0;
580         string name = l->name;
581         int code = (name.size() > 1) ? l->id : name[0];
582
583         if (name == ".") {
584                 pain.line(x + w/2, y, x + w/2, y + h,
585                           LColor::mathcursor, Painter::line_onoffdash);
586                 return;
587         }       
588         
589         deco_struct const * mds = search_deco(code);
590         if (!mds) {
591                 lyxerr << "Deco was not found. Programming error?\n";
592                 lyxerr << "name: '" << l->name << "', code: " << code << "\n";
593                 return;
594         }
595         
596         int const r = mds->angle;
597         float const * d = mds->data;
598         
599         if (h > 70 && (mds->code == int('(') || mds->code == int(')')))
600                 d = parenthHigh;
601         
602         mt.rotate(r);
603         mt.escalate(w, h);
604         
605         int const n = (w < h) ? w : h;
606
607         sqmt.rotate(r);
608         sqmt.escalate(n, n);
609
610         if (r > 0 && r < 3)
611                 y += h;
612
613         if (r >= 2)
614                 x += w;   
615
616         do {
617                 float xx;
618                 float yy;
619                 float x2;
620                 float y2;
621
622                 code = int(d[i++]);
623                 switch (code) {
624                 case 0: break;
625                 case 1: 
626                 case 3:
627                 {
628                         xx = d[i++]; yy = d[i++];
629                         x2 = d[i++]; y2 = d[i++];
630                         if (code == 3) 
631                                 sqmt.transform(xx, yy, xx, yy);
632                         else
633                                 mt.transform(xx, yy, xx, yy);
634                         mt.transform(x2, y2, x2, y2);
635                         pain.line(x + int(xx), y + int(yy),
636                                   x + int(x2), y + int(y2),
637                                   LColor::mathline);
638                         break;
639                 }        
640                 case 2: 
641                 case 4:
642                 {
643                         int xp[32];
644                         int yp[32];
645                         int const n = int(d[i++]);
646                         for (int j = 0; j < n; ++j) {
647                                 xx = d[i++]; yy = d[i++];
648 //           lyxerr << " " << xx << " " << yy << " ";
649                                 if (code == 4) 
650                                         sqmt.transform(xx, yy, xx, yy);
651                                 else
652                                         mt.transform(xx, yy, xx, yy);
653                                 xp[j] = x + int(xx);
654                                 yp[j] = y + int(yy);
655                                 //  lyxerr << "P[" << j " " << xx << " " << yy << " " << x << " " << y << "]";
656                         }
657                         pain.lines(xp, yp, n, LColor::mathline);
658                 }
659                 }
660         } while (code);
661 }
662
663
664 // In a near future maybe we use a better fonts renderer
665 void drawStr(Painter & pain, MathTextCodes type, MathStyles siz,
666         int x, int y, string const & s)
667 {
668         pain.text(x, y, s, WhichFont(type, siz));
669 }
670
671
672 void drawChar
673         (Painter & pain, MathTextCodes type, MathStyles siz, int x, int y, char c)
674 {
675         string s;
676         if (isBinaryOp(c))
677                 s += ' ';
678         s += c;
679         if (isBinaryOp(c))
680                 s += ' ';
681         drawStr(pain, type, siz, x, y, s);
682 }
683
684 // decrease math size for super- and subscripts
685 MathStyles smallerStyleScript(MathStyles st)
686 {
687         switch (st) {
688                 case LM_ST_DISPLAY:
689                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
690                 default:            st = LM_ST_SCRIPTSCRIPT;
691         }
692         return st;
693 }
694
695 // decrease math size for fractions
696 MathStyles smallerStyleFrac(MathStyles st)
697 {
698         switch (st) {
699                 case LM_ST_DISPLAY: st = LM_ST_TEXT; break;
700                 case LM_ST_TEXT:    st = LM_ST_SCRIPT; break;
701                 default:            st = LM_ST_SCRIPTSCRIPT;
702         }
703         return st;
704 }
705
706
707 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
708 {
709         LyXFont font = WhichFont(code, siz);
710         asc = lyxfont::maxAscent(font);
711         des = lyxfont::maxDescent(font);
712 }
713
714 char const * latex_mathspace[] = {
715         "!", ",", ":", ";", "quad", "qquad"
716 };