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