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