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