]> git.lyx.org Git - lyx.git/blob - src/mathed/support.C
move more stuff to math_hash
[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 MathIsAlphaFont(MathTextCodes x)
20 {
21         return LM_TC_VAR <= x && x <= LM_TC_TEXTRM;
22 }
23
24
25 bool MathIsBinary(MathTextCodes x)
26 {
27         return x == LM_TC_BOP;
28 }
29
30
31 bool MathIsSymbol(MathTextCodes x)
32 {
33         return x == LM_TC_SYMB || x == LM_TC_BSYM;
34 }
35      
36
37
38 ///
39 class Matrix {
40 public:
41         ///
42         typedef float matriz_data[2][2];
43         ///
44         Matrix();
45         ///
46         void rotate(int);
47         ///
48         void escalate(float, float);
49         ///
50         void transform(float, float, float &, float &);
51 private:
52         ///
53         matriz_data m_;
54         ///
55         void multiply(matriz_data & a);
56 };
57
58 Matrix::Matrix()
59 {
60         m_[0][0] = 1;
61         m_[0][1] = 0;
62         m_[1][0] = 0;
63         m_[1][1] = 1;
64 }
65
66 void Matrix::rotate(int code)
67 {
68         matriz_data r;
69         r[0][0] = 1;
70         r[0][1] = 0;
71         r[1][0] = 0;
72         r[1][1] = 1;
73         float const cs = (code & 1) ? 0 : (1 - code);
74         float const sn = (code & 1) ? (2 - code) : 0;
75         r[0][0] = cs;
76         r[0][1] = sn;
77         r[1][0] = -r[0][1];
78         r[1][1] = r[0][0];
79         multiply(r);
80 }
81
82 void Matrix::escalate(float x, float y)
83 {
84         matriz_data s;
85         s[0][0] = x;
86         s[0][1] = 0;
87         s[1][0] = 0;
88         s[1][1] = y;
89         multiply(s);
90 }
91
92 void Matrix::multiply(matriz_data & a)
93 {
94         matriz_data c;
95         c[0][0] = a[0][0] * m_[0][0] + a[0][1] * m_[1][0];
96         c[1][0] = a[1][0] * m_[0][0] + a[1][1] * m_[1][0];
97         c[0][1] = a[0][0] * m_[0][1] + a[0][1] * m_[1][1];
98         c[1][1] = a[1][0] * m_[0][1] + a[1][1] * m_[1][1];
99         m_[0][0] = c[0][0];     
100         m_[0][1] = c[0][1];     
101         m_[1][0] = c[1][0];     
102         m_[1][1] = c[1][1];     
103 }
104
105 void Matrix::transform(float xp, float yp, float & x, float & y)
106 {
107         x = m_[0][0] * xp + m_[0][1] * yp;
108         y = m_[1][0] * xp + m_[1][1] * yp;
109 }
110
111
112 namespace {
113
114 LyXFont           * Math_Fonts = 0;
115
116 void mathed_init_fonts()
117 {
118         Math_Fonts = new LyXFont[8]; //DEC cxx cannot initialize all fonts
119         //at once (JMarc) rc
120
121         for (int i = 0 ; i < 8 ; ++i) {
122                 Math_Fonts[i] = LyXFont(LyXFont::ALL_SANE);
123         }
124
125         Math_Fonts[0].setShape(LyXFont::ITALIC_SHAPE);
126
127         Math_Fonts[1].setFamily(LyXFont::SYMBOL_FAMILY);
128
129         Math_Fonts[2].setFamily(LyXFont::SYMBOL_FAMILY);
130         Math_Fonts[2].setShape(LyXFont::ITALIC_SHAPE);
131
132         Math_Fonts[3].setSeries(LyXFont::BOLD_SERIES);
133
134         Math_Fonts[4].setFamily(LyXFont::SANS_FAMILY);
135         Math_Fonts[4].setShape(LyXFont::ITALIC_SHAPE);
136
137         Math_Fonts[5].setFamily(LyXFont::TYPEWRITER_FAMILY);
138
139         Math_Fonts[6].setFamily(LyXFont::ROMAN_FAMILY);
140
141         Math_Fonts[7].setFamily(LyXFont::SANS_FAMILY);
142 }
143
144 } // namespace
145
146
147 LyXFont WhichFont(MathTextCodes type, MathStyles size)
148 {
149         LyXFont f;
150         
151         if (!Math_Fonts)
152                 mathed_init_fonts();
153
154         switch (type) {
155         case LM_TC_SYMB:        
156         case LM_TC_BSYM:        
157                 f = Math_Fonts[2];
158                 break;
159
160         case LM_TC_VAR:
161         case LM_TC_IT:
162                 f = Math_Fonts[0];
163                 break;
164
165         case LM_TC_BF:
166                 f = Math_Fonts[3];
167                 break;
168
169         case LM_TC_SF:
170                 f = Math_Fonts[7];
171                 break;
172
173         case LM_TC_CAL:
174                 f = Math_Fonts[4];
175                 break;
176
177         case LM_TC_TT:
178                 f = Math_Fonts[5];
179                 break;
180
181         case LM_TC_SPECIAL: //f = Math_Fonts[0]; break;
182         case LM_TC_TEXTRM:
183         case LM_TC_TEX:
184         case LM_TC_RM:
185                 f = Math_Fonts[6];
186                 break;
187
188         default:
189                 f = Math_Fonts[1];
190                 break;
191         }
192
193         switch (size) {
194         case LM_ST_DISPLAY:
195                 if (type == LM_TC_BSYM) {
196                         f.incSize();
197                         f.incSize();
198                 }
199                 break;
200
201         case LM_ST_TEXT:
202                 break;
203
204         case LM_ST_SCRIPT:
205                 f.decSize();
206                 f.decSize();
207                 break;
208
209         case LM_ST_SCRIPTSCRIPT:
210                 f.decSize();
211                 f.decSize();
212                 f.decSize();
213                 break;
214
215         default:
216                 lyxerr << "Math Error: wrong font size: " << size << endl;
217                 break;
218         }
219
220         if (type != LM_TC_TEXTRM)
221                 f.setColor(LColor::math);
222
223         if (type == LM_TC_TEX)
224                 f.setColor(LColor::latex);
225
226         return f;
227 }
228
229 char const * math_font_name[] = {
230         "mathrm",
231         "mathcal",
232         "mathbf",
233         "mathsf",
234         "mathtt",
235         "mathit",
236         "textrm"
237 };
238
239
240 namespace {
241
242 /* 
243  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
244  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4= square polyline
245  */
246
247
248 float const parenthHigh[] = {
249         2.0, 13.0,
250         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
251         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
252         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
253         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
254         0.9840, 0.9986,
255         0.0 
256 };
257
258
259 float const parenth[] = {
260         2.0, 13.0,
261         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
262         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
263         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
264         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
265         0.9930, 0.9919,
266         0.0   
267 };
268
269
270 float const brace[] = {
271         2.0, 21.0,
272         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
273         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
274         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
275         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
276         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
277         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
278         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
279         0.0
280 };
281
282
283 // Is this correct? (Lgb)
284 float const arrow[] = {
285         4, 7,
286         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
287         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
288         0.9500, 0.7500,
289         3, 0.5000, 0.1500, 0.5000, 0.9500,
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.3500, 0.5000, 0.3500, 0.9500,
301         3, 0.6500, 0.5000, 0.6500, 0.9500,
302         0.0
303 };
304
305
306 float const udarrow[] = {
307         2, 3,
308         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
309         2, 3,
310         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,  
311         1, 0.5, 0.2,  0.5, 0.8,
312         0.0 
313 };
314
315
316 float const Udarrow[] = {
317         2, 3,
318         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
319         2, 3,
320         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,  
321         1, 0.35, 0.2, 0.35, 0.8,
322         1, 0.65, 0.2, 0.65, 0.8,
323         0.0 
324 };
325
326
327 float const brack[] = {
328         2.0, 4,
329         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
330         0.0
331 };
332
333
334 float const corner[] = {
335         2.0, 3,
336         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
337         0.0
338 };
339
340
341 float const angle[] = {
342         2.0, 3,
343         1, 0,  0.05, 0.5,  1, 1,
344         0.0
345 };
346
347
348 float const slash[] = {
349         1, 0.95, 0.05,  0.05, 0.95, 
350         0.0
351 };
352
353
354 float const hline[] = {
355         1, 0.05, 0.5,  0.95, 0.5, 
356         0.0
357 };
358
359
360 float const hline2[] = {
361    1, 0.1, 0.5,  0.3, 0.5,
362    1, 0.7, 0.5,  0.9, 0.5,
363    0.0
364 }; 
365
366
367 float const hline3[] = {
368         1, 0.1, 0,  0.15, 0,
369         1, 0.475, 0,  0.525, 0,
370         1, 0.85, 0,  0.9, 0,  
371         0.0
372 };
373
374
375 float const dline3[] = {
376         1, 0.1, 0.1,  0.15, 0.15,
377         1, 0.475, 0.475,  0.525, 0.525,
378         1, 0.85, 0.85,  0.9, 0.9,
379         0.0
380 };     
381
382
383 float const hlinesmall[] = {
384         1, 0.4, 0.5,  0.6, 0.5, 
385         0.0
386 };
387
388
389 float const vert[] = {
390         1, 0.5, 0.05,  0.5, 0.95, 
391         0.0
392 };
393
394
395 float const  Vert[] = {
396         1, 0.3, 0.05,  0.3, 0.95, 
397         1, 0.7, 0.05,  0.7, 0.95,
398         0.0
399 };
400
401
402 float const tilde[] = {
403         2.0, 4,
404         0.05, 0.8,  0.25, 0.2,  0.75, 0.8,  0.95, 0.2,
405         0.0
406 };
407
408
409 struct math_deco_struct {
410         int code;
411         float const * data;
412         int angle;
413 };
414
415 math_deco_struct math_deco_table[] = {   
416         // Decorations
417         { LM_widehat,       &angle[0],      3 },
418         { LM_widetilde,     &tilde[0],      0 },
419         { LM_underline,     &hline[0],      0 },
420         { LM_overline,      &hline[0],      0 },
421         { LM_underbrace,    &brace[0],      1 },
422         { LM_overbrace,     &brace[0],      3 },
423         { LM_overleftarrow, &arrow[0],      1 },
424         { LM_overightarrow, &arrow[0],      3 },
425                                             
426         // Delimiters                       
427         { '(',              &parenth[0],    0 },
428         { ')',              &parenth[0],    2 },
429         { '{',              &brace[0],      0 },
430         { '}',              &brace[0],      2 },
431         { '[',              &brack[0],      0 },
432         { ']',              &brack[0],      2 },
433         { '|',              &vert[0],       0 },
434         { '/',              &slash[0],      0 },
435         { LM_Vert,          &Vert[0],       0 },
436         { LM_backslash,     &slash[0],      1 },
437         { LM_langle,        &angle[0],      0 },
438         { LM_lceil,         &corner[0],     0 }, 
439         { LM_lfloor,        &corner[0],     1 },  
440         { LM_rangle,        &angle[0],      2 }, 
441         { LM_rceil,         &corner[0],     3 }, 
442         { LM_rfloor,        &corner[0],     2 },
443         { LM_downarrow,     &arrow[0],      2 },
444         { LM_Downarrow,     &Arrow[0],      2 }, 
445         { LM_uparrow,       &arrow[0],      0 },
446         { LM_Uparrow,       &Arrow[0],      0 },
447         { LM_updownarrow,   &udarrow[0],    0 },
448         { LM_Updownarrow,   &Udarrow[0],    0 },         
449                                             
450         // Accents                          
451         { LM_ddot,          &hline2[0],     0 },
452         { LM_hat,           &angle[0],      3 },
453         { LM_grave,         &slash[0],      1 },
454         { LM_acute,         &slash[0],      0 },
455         { LM_tilde,         &tilde[0],      0 },
456         { LM_bar,           &hline[0],      0 },
457         { LM_dot,           &hlinesmall[0], 0 },
458         { LM_check,         &angle[0],      1 },
459         { LM_breve,         &parenth[0],    1 },
460         { LM_vec,           &arrow[0],      3 },
461         { LM_not,           &slash[0],      0 },  
462                                             
463         // Dots                             
464         { LM_ldots,         &hline3[0],     0 }, 
465         { LM_cdots,         &hline3[0],     0 },
466         { LM_vdots,         &hline3[0],     1 },
467         { LM_ddots,         &dline3[0],     0 }
468 };
469
470
471 struct math_deco_compare {
472         /// for use by sort and lower_bound
473         inline
474         int operator()(math_deco_struct const & a,
475                        math_deco_struct const & b) const {
476                 return a.code < b.code;
477         }
478 };
479
480
481 int const math_deco_table_size =
482 sizeof(math_deco_table) /sizeof(math_deco_struct);
483
484
485 class init_deco_table {
486 public:
487         init_deco_table() {
488                 if (!init) {
489                         sort(math_deco_table,
490                              math_deco_table + math_deco_table_size,
491                              math_deco_compare());
492                         init_deco_table::init = true;
493                 }
494         }
495 private:
496         static bool init;
497 };
498
499
500 bool init_deco_table::init = false;
501 static init_deco_table idt;
502
503 } // namespace anon
504
505 void mathed_char_dim(MathTextCodes type, MathStyles size, unsigned char c,
506         int & asc, int & des, int & wid)
507 {
508         LyXFont const font = WhichFont(type, size);
509         des = lyxfont::descent(c, font);
510         asc = lyxfont::ascent(c, font);
511         wid = mathed_char_width(type, size, c);
512 }
513
514 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c,
515         int & asc, int & des)
516 {
517         LyXFont const font = WhichFont(type, size);
518         des = lyxfont::descent(c, font);
519         asc = lyxfont::ascent(c, font);
520         return asc + des;
521 }
522
523
524 int mathed_char_height(MathTextCodes type, MathStyles size, unsigned char c)
525 {
526         int asc;
527         int des;
528         return mathed_char_height(type, size, c, asc, des);
529 }
530
531 int mathed_char_ascent(MathTextCodes type, MathStyles size, unsigned char c)
532 {
533         LyXFont const font = WhichFont(type, size);
534         return lyxfont::ascent(c, font);
535 }
536
537 int mathed_char_descent(MathTextCodes type, MathStyles size, unsigned char c)
538 {
539         LyXFont const font = WhichFont(type, size);
540         return lyxfont::descent(c, font);
541 }
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
734 void math_font_max_dim(MathTextCodes code, MathStyles siz, int & asc, int & des)
735 {
736         LyXFont font = WhichFont(code, siz);
737         asc = lyxfont::maxAscent(font);
738         des = lyxfont::maxDescent(font);
739 }
740
741 char const * latex_mathspace[] = {
742         "!", ",", ":", ";", "quad", "qquad"
743 };