]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.C
This commit is a big rework of the FontLoader/FontMetrics interaction. Only Qt4 for...
[lyx.git] / src / mathed / MathSupport.C
1 /**
2  * \file MathSupport.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "MathSupport.h"
15 #include "MathData.h"
16 #include "InsetMath.h"
17 #include "MathMLStream.h"
18 #include "MathParser.h"
19
20 #include "debug.h"
21 #include "LColor.h"
22
23 #include "frontends/Application.h"
24 #include "frontends/FontLoader.h"
25 #include "frontends/FontMetrics.h"
26 #include "frontends/Painter.h"
27
28 #include <map>
29 #include <sstream>
30
31 using lyx::docstring;
32 using lyx::frontend::Painter;
33
34 using std::string;
35 using std::max;
36 using std::endl;
37
38
39 ///
40 class Matrix {
41 public:
42         ///
43         Matrix(int, double, double);
44         ///
45         void transform(double &, double &);
46 private:
47         ///
48         double m_[2][2];
49 };
50
51
52 Matrix::Matrix(int code, double x, double y)
53 {
54         double const cs = (code & 1) ? 0 : (1 - code);
55         double const sn = (code & 1) ? (2 - code) : 0;
56         m_[0][0] =  cs * x;
57         m_[0][1] =  sn * x;
58         m_[1][0] = -sn * y;
59         m_[1][1] =  cs * y;
60 }
61
62
63 void Matrix::transform(double & x, double & y)
64 {
65         double xx = m_[0][0] * x + m_[0][1] * y;
66         double yy = m_[1][0] * x + m_[1][1] * y;
67         x = xx;
68         y = yy;
69 }
70
71
72
73 namespace {
74
75 /*
76  * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77  * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
78  */
79
80
81 double const parenthHigh[] = {
82         2, 13,
83         0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84         0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85         0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86         0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
87         0.9840, 0.9986,
88         0
89 };
90
91
92 double const parenth[] = {
93         2, 13,
94         0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95         0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96         0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97         0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
98         0.9930, 0.9919,
99         0
100 };
101
102
103 double const brace[] = {
104         2, 21,
105         0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106         0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107         0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108         0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109         0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110         0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111         0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
112         0
113 };
114
115
116 double const arrow[] = {
117         4, 7,
118         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
120         0.9500, 0.7500,
121         3, 0.5000, 0.1500, 0.5000, 0.9500,
122         0
123 };
124
125
126 double const Arrow[] = {
127         4, 7,
128         0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129         0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
130         0.9500, 0.7500,
131         3, 0.3500, 0.5000, 0.3500, 0.9500,
132         3, 0.6500, 0.5000, 0.6500, 0.9500,
133         0
134 };
135
136
137 double const udarrow[] = {
138         2, 3,
139         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
140         2, 3,
141         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
142         1, 0.5, 0.2,  0.5, 0.8,
143         0
144 };
145
146
147 double const Udarrow[] = {
148         2, 3,
149         0.015, 0.25,  0.5, 0.05, 0.95, 0.25,
150         2, 3,
151         0.015, 0.75,  0.5, 0.95, 0.95, 0.75,
152         1, 0.35, 0.2, 0.35, 0.8,
153         1, 0.65, 0.2, 0.65, 0.8,
154         0
155 };
156
157
158 double const brack[] = {
159         2, 4,
160         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,  0.95, 0.95,
161         0
162 };
163
164
165 double const corner[] = {
166         2, 3,
167         0.95, 0.05,  0.05, 0.05,  0.05, 0.95,
168         0
169 };
170
171
172 double const angle[] = {
173         2, 3,
174         1, 0,  0.05, 0.5,  1, 1,
175         0
176 };
177
178
179 double const slash[] = {
180         1, 0.95, 0.05, 0.05, 0.95,
181         0
182 };
183
184
185 double const hline[] = {
186         1, 0.00, 0.5, 1.0, 0.5,
187         0
188 };
189
190
191 double const ddot[] = {
192         1, 0.2, 0.5,  0.3, 0.5,
193         1, 0.7, 0.5,  0.8, 0.5,
194         0
195 };
196
197
198 double const dddot[] = {
199         1, 0.1, 0.5,  0.2, 0.5,
200         1, 0.45, 0.5, 0.55, 0.5,
201         1, 0.8, 0.5,  0.9, 0.5,
202         0
203 };
204
205
206 double const hline3[] = {
207         1, 0.1,   0,  0.15,  0,
208         1, 0.475, 0,  0.525, 0,
209         1, 0.85,  0,  0.9,   0,
210         0
211 };
212
213
214 double const dline3[] = {
215         1, 0.1,   0.1,   0.15,  0.15,
216         1, 0.475, 0.475, 0.525, 0.525,
217         1, 0.85,  0.85,  0.9,   0.9,
218         0
219 };
220
221
222 double const hlinesmall[] = {
223         1, 0.4, 0.5, 0.6, 0.5,
224         0
225 };
226
227
228 double const ring[] = {
229         2, 5,
230         0.5, 0.8,  0.8, 0.5,  0.5, 0.2,  0.2, 0.5,  0.5, 0.8,
231         0
232 };
233
234
235 double const vert[] = {
236         1, 0.5, 0.05,  0.5, 0.95,
237         0
238 };
239
240
241 double const  Vert[] = {
242         1, 0.3, 0.05,  0.3, 0.95,
243         1, 0.7, 0.05,  0.7, 0.95,
244         0
245 };
246
247
248 double const tilde[] = {
249         2, 4,
250         0.00, 0.8,  0.25, 0.2,  0.75, 0.8,  1.00, 0.2,
251         0
252 };
253
254
255 struct deco_struct {
256         double const * data;
257         int angle;
258 };
259
260 struct named_deco_struct {
261         char const * name;
262         double const * data;
263         int angle;
264 };
265
266 named_deco_struct deco_table[] = {
267         // Decorations
268         {"widehat",             angle,    3 },
269         {"widetilde",           tilde,    0 },
270         {"underbar",            hline,    0 },
271         {"underline",           hline,    0 },
272         {"overline",            hline,    0 },
273         {"underbrace",          brace,    1 },
274         {"overbrace",           brace,    3 },
275         {"overleftarrow",       arrow,    1 },
276         {"overrightarrow",      arrow,    3 },
277         {"overleftrightarrow",  udarrow,  1 },
278         {"xleftarrow",          arrow,    1 },
279         {"xrightarrow",         arrow,    3 },
280         {"underleftarrow",      arrow,    1 },
281         {"underrightarrow",     arrow,    3 },
282         {"underleftrightarrow", udarrow,  1 },
283
284         // Delimiters
285         {"(",              parenth,    0 },
286         {")",              parenth,    2 },
287         {"{",              brace,      0 },
288         {"}",              brace,      2 },
289         {"lbrace",         brace,      0 },
290         {"rbrace",         brace,      2 },
291         {"[",              brack,      0 },
292         {"]",              brack,      2 },
293         {"|",              vert,       0 },
294         {"/",              slash,      0 },
295         {"vert",           vert,       0 },
296         {"Vert",           Vert,       0 },
297         {"'",              slash,      1 },
298         {"backslash",      slash,      1 },
299         {"langle",         angle,      0 },
300         {"lceil",          corner,     0 },
301         {"lfloor",         corner,     1 },
302         {"rangle",         angle,      2 },
303         {"rceil",          corner,     3 },
304         {"rfloor",         corner,     2 },
305         {"downarrow",      arrow,      2 },
306         {"Downarrow",      Arrow,      2 },
307         {"uparrow",        arrow,      0 },
308         {"Uparrow",        Arrow,      0 },
309         {"updownarrow",    udarrow,    0 },
310         {"Updownarrow",    Udarrow,    0 },
311
312         // Accents
313         {"ddot",           ddot,       0 },
314         {"dddot",          dddot,      0 },
315         {"hat",            angle,      3 },
316         {"grave",          slash,      1 },
317         {"acute",          slash,      0 },
318         {"tilde",          tilde,      0 },
319         {"bar",            hline,      0 },
320         {"dot",            hlinesmall, 0 },
321         {"check",          angle,      1 },
322         {"breve",          parenth,    1 },
323         {"vec",            arrow,      3 },
324         {"mathring",       ring,       0 },
325
326         // Dots
327         {"dots",           hline3,     0 },
328         {"ldots",          hline3,     0 },
329         {"cdots",          hline3,     0 },
330         {"vdots",          hline3,     1 },
331         {"ddots",          dline3,     0 },
332         {"dotsb",          hline3,     0 },
333         {"dotsc",          hline3,     0 },
334         {"dotsi",          hline3,     0 },
335         {"dotsm",          hline3,     0 },
336         {"dotso",          hline3,     0 }
337 };
338
339
340 std::map<string, deco_struct> deco_list;
341
342 // sort the table on startup
343 class init_deco_table {
344 public:
345         init_deco_table() {
346                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
347                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
348                         deco_struct d;
349                         d.data  = p->data;
350                         d.angle = p->angle;
351                         deco_list[p->name]= d;
352                 }
353         }
354 };
355
356 static init_deco_table dummy;
357
358
359 deco_struct const * search_deco(string const & name)
360 {
361         std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
362         return (p == deco_list.end()) ? 0 : &(p->second);
363 }
364
365
366 } // namespace anon
367
368
369 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
370 {
371         lyx::frontend::FontMetrics const & fm =
372                 theApp->fontLoader().metrics(font);
373         dim.des = fm.descent(c);
374         dim.asc = fm.ascent(c);
375         dim.wid = fm.width(c);
376 }
377
378
379 int mathed_char_width(LyXFont const & font, unsigned char c)
380 {
381         return theApp->fontLoader().metrics(font).width(c);
382 }
383
384
385 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
386 {
387         lyx::frontend::FontMetrics const & fm =
388                 theApp->fontLoader().metrics(font);
389 #if 1
390         dim.asc = 0;
391         dim.des = 0;
392         for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
393                 dim.asc = max(dim.asc, fm.ascent(*it));
394                 dim.des = max(dim.des, fm.descent(*it));
395         }
396 #else
397         dim.asc = fm.maxAscent();
398         dim.des = fm.maxDescent();
399 #endif
400         docstring ds(s.begin(), s.end());
401         dim.wid = fm.width(ds);
402 }
403
404
405 int mathed_string_width(LyXFont const & font, string const & s)
406 {
407         docstring ds(s.begin(), s.end());
408         return theApp->fontLoader().metrics(font).width(ds);
409 }
410
411
412 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
413         string const & name)
414 {
415         if (name == ".") {
416                 pi.pain.line(x + w/2, y, x + w/2, y + h,
417                           LColor::cursor, Painter::line_onoffdash);
418                 return;
419         }
420
421         deco_struct const * mds = search_deco(name);
422         if (!mds) {
423                 lyxerr << "Deco was not found. Programming error?" << endl;
424                 lyxerr << "name: '" << name << "'" << endl;
425                 return;
426         }
427
428         int const n = (w < h) ? w : h;
429         int const r = mds->angle;
430         double const * d = mds->data;
431
432         if (h > 70 && (name == "(" || name == ")"))
433                 d = parenthHigh;
434
435         Matrix mt(r, w, h);
436         Matrix sqmt(r, n, n);
437
438         if (r > 0 && r < 3)
439                 y += h;
440
441         if (r >= 2)
442                 x += w;
443
444         for (int i = 0; d[i]; ) {
445                 int code = int(d[i++]);
446                 if (code & 1) {  // code == 1 || code == 3
447                         double xx = d[i++];
448                         double yy = d[i++];
449                         double x2 = d[i++];
450                         double y2 = d[i++];
451                         if (code == 3)
452                                 sqmt.transform(xx, yy);
453                         else
454                                 mt.transform(xx, yy);
455                         mt.transform(x2, y2);
456                         pi.pain.line(
457                                 int(x + xx + 0.5), int(y + yy + 0.5),
458                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
459                                 LColor::math);
460                 } else {
461                         int xp[32];
462                         int yp[32];
463                         int const n = int(d[i++]);
464                         for (int j = 0; j < n; ++j) {
465                                 double xx = d[i++];
466                                 double yy = d[i++];
467 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
468                                 if (code == 4)
469                                         sqmt.transform(xx, yy);
470                                 else
471                                         mt.transform(xx, yy);
472                                 xp[j] = int(x + xx + 0.5);
473                                 yp[j] = int(y + yy + 0.5);
474                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
475                         }
476                         pi.pain.lines(xp, yp, n, LColor::math);
477                 }
478         }
479 }
480
481
482 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
483 {
484         LyXFont f = pi.base.font;
485         f.setColor(LColor::latex);
486         docstring dstr(str.begin(), str.end());
487         pi.pain.text(x, y, dstr, f);
488 }
489
490
491 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
492 {
493         LyXFont f = pi.base.font;
494         f.setColor(LColor::foreground);
495         docstring dstr(str.begin(), str.end());
496         pi.pain.text(x, y, dstr, f);
497 }
498
499
500 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
501 {
502         lyx::frontend::FontMetrics const & fm =
503                 theApp->fontLoader().metrics(font);
504         asc = fm.maxAscent();
505         des = fm.maxDescent();
506 }
507
508
509 struct fontinfo {
510         string cmd_;
511         LyXFont::FONT_FAMILY family_;
512         LyXFont::FONT_SERIES series_;
513         LyXFont::FONT_SHAPE  shape_;
514         LColor::color        color_;
515 };
516
517
518 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
519 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
520 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE;
521
522
523 // mathnormal should be the first, otherwise the fallback further down
524 // does not work
525 fontinfo fontinfos[] = {
526         // math fonts
527         {"mathnormal",    LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
528                           LyXFont::ITALIC_SHAPE, LColor::math},
529         {"mathbf",        inh_family, LyXFont::BOLD_SERIES,
530                           inh_shape, LColor::math},
531         {"mathcal",       LyXFont::CMSY_FAMILY, inh_series,
532                           inh_shape, LColor::math},
533         {"mathfrak",      LyXFont::EUFRAK_FAMILY, inh_series,
534                           inh_shape, LColor::math},
535         {"mathrm",        LyXFont::ROMAN_FAMILY, inh_series,
536                           LyXFont::UP_SHAPE, LColor::math},
537         {"mathsf",        LyXFont::SANS_FAMILY, inh_series,
538                           inh_shape, LColor::math},
539         {"mathbb",        LyXFont::MSB_FAMILY, inh_series,
540                           inh_shape, LColor::math},
541         {"mathtt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
542                           inh_shape, LColor::math},
543         {"mathit",        inh_family, inh_series,
544                           LyXFont::ITALIC_SHAPE, LColor::math},
545         {"cmex",          LyXFont::CMEX_FAMILY, inh_series,
546                           inh_shape, LColor::math},
547         {"cmm",           LyXFont::CMM_FAMILY, inh_series,
548                           inh_shape, LColor::math},
549         {"cmr",           LyXFont::CMR_FAMILY, inh_series,
550                           inh_shape, LColor::math},
551         {"cmsy",          LyXFont::CMSY_FAMILY, inh_series,
552                           inh_shape, LColor::math},
553         {"eufrak",        LyXFont::EUFRAK_FAMILY, inh_series,
554                           inh_shape, LColor::math},
555         {"msa",           LyXFont::MSA_FAMILY, inh_series,
556                           inh_shape, LColor::math},
557         {"msb",           LyXFont::MSB_FAMILY, inh_series,
558                           inh_shape, LColor::math},
559         {"wasy",          LyXFont::WASY_FAMILY, inh_series,
560                           inh_shape, LColor::none},
561
562         // Text fonts
563         {"text",          inh_family, inh_series,
564                           inh_shape, LColor::foreground},
565         {"textbf",        inh_family, LyXFont::BOLD_SERIES,
566                           inh_shape, LColor::foreground},
567         {"textit",        inh_family, inh_series,
568                           LyXFont::ITALIC_SHAPE, LColor::foreground},
569         {"textmd",        inh_family, LyXFont::MEDIUM_SERIES,
570                           inh_shape, LColor::foreground},
571         {"textnormal",    inh_family, inh_series,
572                           LyXFont::UP_SHAPE, LColor::foreground},
573         {"textrm",        LyXFont::ROMAN_FAMILY,
574                           inh_series, LyXFont::UP_SHAPE,LColor::foreground},
575         {"textsc",        inh_family, inh_series,
576                           LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
577         {"textsf",        LyXFont::SANS_FAMILY, inh_series,
578                           inh_shape, LColor::foreground},
579         {"textsl",        inh_family, inh_series,
580                           LyXFont::SLANTED_SHAPE, LColor::foreground},
581         {"texttt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
582                           inh_shape, LColor::foreground},
583         {"textup",        inh_family, inh_series,
584                           LyXFont::UP_SHAPE, LColor::foreground},
585
586         // TIPA support
587         {"textipa",       inh_family, inh_series,
588                           inh_shape, LColor::foreground},
589
590         // LyX internal usage
591         {"lyxtex",        inh_family, inh_series,
592                           LyXFont::UP_SHAPE, LColor::latex},
593         {"lyxsymbol",     LyXFont::SYMBOL_FAMILY, inh_series,
594                           inh_shape, LColor::math},
595         {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
596                           inh_shape, LColor::math},
597         {"lyxblacktext",  LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
598                           LyXFont::UP_SHAPE, LColor::foreground},
599         {"lyxnochange",   inh_family, inh_series,
600                           inh_shape, LColor::foreground},
601         {"lyxfakebb",     LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
602                           LyXFont::UP_SHAPE, LColor::math},
603         {"lyxfakecal",    LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
604                           LyXFont::ITALIC_SHAPE, LColor::math},
605         {"lyxfakefrak",   LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
606                           LyXFont::ITALIC_SHAPE, LColor::math}
607 };
608
609
610 fontinfo * lookupFont(string const & name)
611 {
612         //lyxerr << "searching font '" << name << "'" << endl;
613         int const n = sizeof(fontinfos) / sizeof(fontinfo);
614         for (int i = 0; i < n; ++i)
615                 if (fontinfos[i].cmd_ == name) {
616                         //lyxerr << "found '" << i << "'" << endl;
617                         return fontinfos + i;
618                 }
619         return 0;
620 }
621
622
623 fontinfo * searchFont(string const & name)
624 {
625         fontinfo * f = lookupFont(name);
626         return f ? f : fontinfos;
627         // this should be mathnormal
628         //return searchFont("mathnormal");
629 }
630
631
632 bool isFontName(string const & name)
633 {
634         return lookupFont(name);
635 }
636
637
638 LyXFont getFont(string const & name)
639 {
640         LyXFont font;
641         augmentFont(font, name);
642         return font;
643 }
644
645
646 void fakeFont(string const & orig, string const & fake)
647 {
648         fontinfo * forig = searchFont(orig);
649         fontinfo * ffake = searchFont(fake);
650         if (forig && ffake) {
651                 forig->family_ = ffake->family_;
652                 forig->series_ = ffake->series_;
653                 forig->shape_  = ffake->shape_;
654                 forig->color_  = ffake->color_;
655         } else {
656                 lyxerr << "Can't fake font '" << orig << "' with '"
657                        << fake << "'" << endl;
658         }
659 }
660
661
662 void augmentFont(LyXFont & font, string const & name)
663 {
664         static bool initialized = false;
665         if (!initialized) {
666                 initialized = true;
667                 // fake fonts if necessary
668                 if (!theApp->fontLoader().available(getFont("mathfrak")))
669                         fakeFont("mathfrak", "lyxfakefrak");
670                 if (!theApp->fontLoader().available(getFont("mathcal")))
671                         fakeFont("mathcal", "lyxfakecal");
672         }
673         fontinfo * info = searchFont(name);
674         if (info->family_ != inh_family)
675                 font.setFamily(info->family_);
676         if (info->series_ != inh_series)
677                 font.setSeries(info->series_);
678         if (info->shape_ != inh_shape)
679                 font.setShape(info->shape_);
680         if (info->color_ != LColor::none)
681                 font.setColor(info->color_);
682 }
683
684
685 string asString(MathArray const & ar)
686 {
687         std::ostringstream os;
688         WriteStream ws(os);
689         ws << ar;
690         return os.str();
691 }
692
693
694 void asArray(string const & str, MathArray & ar)
695 {
696         mathed_parse_cell(ar, str);
697 }
698
699
700 string asString(InsetMath const & inset)
701 {
702         std::ostringstream os;
703         WriteStream ws(os);
704         inset.write(ws);
705         return os.str();
706 }
707
708
709 string asString(MathAtom const & at)
710 {
711         std::ostringstream os;
712         WriteStream ws(os);
713         at->write(ws);
714         return os.str();
715 }