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