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