]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.C
Rename files in src/mathed and src/graphics from .C to .cpp, step 1
[lyx.git] / src / mathed / MathSupport.C
1 /**
2  * \file MathSupport.cpp
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         {"slash",          slash,      0 },
297         {"vert",           vert,       0 },
298         {"Vert",           Vert,       0 },
299         {"'",              slash,      1 },
300         {"\\",             slash,      1 },
301         {"backslash",      slash,      1 },
302         {"langle",         angle,      0 },
303         {"lceil",          corner,     0 },
304         {"lfloor",         corner,     1 },
305         {"rangle",         angle,      2 },
306         {"rceil",          corner,     3 },
307         {"rfloor",         corner,     2 },
308         {"downarrow",      arrow,      2 },
309         {"Downarrow",      Arrow,      2 },
310         {"uparrow",        arrow,      0 },
311         {"Uparrow",        Arrow,      0 },
312         {"updownarrow",    udarrow,    0 },
313         {"Updownarrow",    Udarrow,    0 },
314
315         // Accents
316         {"ddot",           ddot,       0 },
317         {"dddot",          dddot,      0 },
318         {"hat",            angle,      3 },
319         {"grave",          slash,      1 },
320         {"acute",          slash,      0 },
321         {"tilde",          tilde,      0 },
322         {"bar",            hline,      0 },
323         {"dot",            hlinesmall, 0 },
324         {"check",          angle,      1 },
325         {"breve",          parenth,    1 },
326         {"vec",            arrow,      3 },
327         {"mathring",       ring,       0 },
328
329         // Dots
330         {"dots",           hline3,     0 },
331         {"ldots",          hline3,     0 },
332         {"cdots",          hline3,     0 },
333         {"vdots",          hline3,     1 },
334         {"ddots",          dline3,     0 },
335         {"dotsb",          hline3,     0 },
336         {"dotsc",          hline3,     0 },
337         {"dotsi",          hline3,     0 },
338         {"dotsm",          hline3,     0 },
339         {"dotso",          hline3,     0 }
340 };
341
342
343 std::map<docstring, deco_struct> deco_list;
344
345 // sort the table on startup
346 class init_deco_table {
347 public:
348         init_deco_table() {
349                 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
350                 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
351                         deco_struct d;
352                         d.data  = p->data;
353                         d.angle = p->angle;
354                         deco_list[from_ascii(p->name)] = d;
355                 }
356         }
357 };
358
359 static init_deco_table dummy;
360
361
362 deco_struct const * search_deco(docstring const & name)
363 {
364         std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
365         return p == deco_list.end() ? 0 : &(p->second);
366 }
367
368
369 } // namespace anon
370
371
372 int mathed_char_width(LyXFont const & font, char_type c)
373 {
374         return theFontMetrics(font).width(c);
375 }
376
377
378 int mathed_char_kerning(LyXFont const & font, char_type c)
379 {
380         frontend::FontMetrics const & fm = theFontMetrics(font);
381         return fm.rbearing(c) - fm.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);
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         {"esint",         LyXFont::ESINT_FAMILY, inh_series,
555                           inh_shape, LColor::none},
556
557         // Text fonts
558         {"text",          inh_family, inh_series,
559                           inh_shape, LColor::foreground},
560         {"textbf",        inh_family, LyXFont::BOLD_SERIES,
561                           inh_shape, LColor::foreground},
562         {"textit",        inh_family, inh_series,
563                           LyXFont::ITALIC_SHAPE, LColor::foreground},
564         {"textmd",        inh_family, LyXFont::MEDIUM_SERIES,
565                           inh_shape, LColor::foreground},
566         {"textnormal",    inh_family, inh_series,
567                           LyXFont::UP_SHAPE, LColor::foreground},
568         {"textrm",        LyXFont::ROMAN_FAMILY,
569                           inh_series, LyXFont::UP_SHAPE,LColor::foreground},
570         {"textsc",        inh_family, inh_series,
571                           LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
572         {"textsf",        LyXFont::SANS_FAMILY, inh_series,
573                           inh_shape, LColor::foreground},
574         {"textsl",        inh_family, inh_series,
575                           LyXFont::SLANTED_SHAPE, LColor::foreground},
576         {"texttt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
577                           inh_shape, LColor::foreground},
578         {"textup",        inh_family, inh_series,
579                           LyXFont::UP_SHAPE, LColor::foreground},
580
581         // TIPA support
582         {"textipa",       inh_family, inh_series,
583                           inh_shape, LColor::foreground},
584
585         // LyX internal usage
586         {"lyxtex",        inh_family, inh_series,
587                           LyXFont::UP_SHAPE, LColor::latex},
588         {"lyxsymbol",     LyXFont::SYMBOL_FAMILY, inh_series,
589                           inh_shape, LColor::math},
590         {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
591                           inh_shape, LColor::math},
592         {"lyxblacktext",  LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
593                           LyXFont::UP_SHAPE, LColor::foreground},
594         {"lyxnochange",   inh_family, inh_series,
595                           inh_shape, LColor::foreground},
596         {"lyxfakebb",     LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
597                           LyXFont::UP_SHAPE, LColor::math},
598         {"lyxfakecal",    LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
599                           LyXFont::ITALIC_SHAPE, LColor::math},
600         {"lyxfakefrak",   LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
601                           LyXFont::ITALIC_SHAPE, LColor::math}
602 };
603
604
605 fontinfo * lookupFont(docstring const & name0)
606 {
607         //lyxerr << "searching font '" << name << "'" << endl;
608         int const n = sizeof(fontinfos) / sizeof(fontinfo);
609         std::string name = to_utf8(name0);
610         for (int i = 0; i < n; ++i)
611                 if (fontinfos[i].cmd_ == name) {
612                         //lyxerr << "found '" << i << "'" << endl;
613                         return fontinfos + i;
614                 }
615         return 0;
616 }
617
618
619 fontinfo * searchFont(docstring const & name)
620 {
621         fontinfo * f = lookupFont(name);
622         return f ? f : fontinfos;
623         // this should be mathnormal
624         //return searchFont("mathnormal");
625 }
626
627
628 bool isFontName(docstring const & name)
629 {
630         return lookupFont(name);
631 }
632
633
634 LyXFont getFont(docstring const & name)
635 {
636         LyXFont font;
637         augmentFont(font, name);
638         return font;
639 }
640
641
642 void fakeFont(docstring const & orig, docstring const & fake)
643 {
644         fontinfo * forig = searchFont(orig);
645         fontinfo * ffake = searchFont(fake);
646         if (forig && ffake) {
647                 forig->family_ = ffake->family_;
648                 forig->series_ = ffake->series_;
649                 forig->shape_  = ffake->shape_;
650                 forig->color_  = ffake->color_;
651         } else {
652                 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
653                        << to_utf8(fake) << "'" << endl;
654         }
655 }
656
657
658 void augmentFont(LyXFont & font, docstring const & name)
659 {
660         static bool initialized = false;
661         if (!initialized) {
662                 initialized = true;
663                 // fake fonts if necessary
664                 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
665                         fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
666                 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
667                         fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
668         }
669         fontinfo * info = searchFont(name);
670         if (info->family_ != inh_family)
671                 font.setFamily(info->family_);
672         if (info->series_ != inh_series)
673                 font.setSeries(info->series_);
674         if (info->shape_ != inh_shape)
675                 font.setShape(info->shape_);
676         if (info->color_ != LColor::none)
677                 font.setColor(info->color_);
678 }
679
680
681 docstring asString(MathArray const & ar)
682 {
683         odocstringstream os;
684         WriteStream ws(os);
685         ws << ar;
686         return os.str();
687 }
688
689
690 void asArray(docstring const & str, MathArray & ar)
691 {
692         mathed_parse_cell(ar, str);
693 }
694
695
696 docstring asString(InsetMath const & inset)
697 {
698         odocstringstream os;
699         WriteStream ws(os);
700         inset.write(ws);
701         return os.str();
702 }
703
704
705 docstring asString(MathAtom const & at)
706 {
707         odocstringstream os;
708         WriteStream ws(os);
709         at->write(ws);
710         return os.str();
711 }
712
713
714 } // namespace lyx