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