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