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