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