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