]> git.lyx.org Git - lyx.git/blob - src/mathed/MathSupport.C
* output_plaintext.C: cosmetics in comment: line length cannot be < 0
[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 int mathed_char_width(LyXFont const & font, char_type c)
371 {
372         return theFontMetrics(font).width(c);
373 }
374
375
376 void mathed_string_dim(LyXFont const & font,
377                        docstring const & s,
378                        Dimension & dim)
379 {
380         frontend::FontMetrics const & fm = theFontMetrics(font);
381         dim.asc = 0;
382         dim.des = 0;
383         for (docstring::const_iterator it = s.begin();
384              it != s.end();
385              ++it) {
386                 dim.asc = max(dim.asc, fm.ascent(*it));
387                 dim.des = max(dim.des, fm.descent(*it));
388         }
389         dim.wid = fm.width(&s[0], s.size());
390 }
391
392
393 int mathed_string_width(LyXFont const & font, docstring const & s)
394 {
395         return theFontMetrics(font).width(s);
396 }
397
398
399 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
400         docstring const & name)
401 {
402         if (name == ".") {
403                 pi.pain.line(x + w/2, y, x + w/2, y + h,
404                           LColor::cursor, Painter::line_onoffdash);
405                 return;
406         }
407
408         deco_struct const * mds = search_deco(name);
409         if (!mds) {
410                 lyxerr << "Deco was not found. Programming error?" << endl;
411                 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
412                 return;
413         }
414
415         int const n = (w < h) ? w : h;
416         int const r = mds->angle;
417         double const * d = mds->data;
418
419         if (h > 70 && (name == "(" || name == ")"))
420                 d = parenthHigh;
421
422         Matrix mt(r, w, h);
423         Matrix sqmt(r, n, n);
424
425         if (r > 0 && r < 3)
426                 y += h;
427
428         if (r >= 2)
429                 x += w;
430
431         for (int i = 0; d[i]; ) {
432                 int code = int(d[i++]);
433                 if (code & 1) {  // code == 1 || code == 3
434                         double xx = d[i++];
435                         double yy = d[i++];
436                         double x2 = d[i++];
437                         double y2 = d[i++];
438                         if (code == 3)
439                                 sqmt.transform(xx, yy);
440                         else
441                                 mt.transform(xx, yy);
442                         mt.transform(x2, y2);
443                         pi.pain.line(
444                                 int(x + xx + 0.5), int(y + yy + 0.5),
445                                 int(x + x2 + 0.5), int(y + y2 + 0.5),
446                                 LColor::math);
447                 } else {
448                         int xp[32];
449                         int yp[32];
450                         int const n = int(d[i++]);
451                         for (int j = 0; j < n; ++j) {
452                                 double xx = d[i++];
453                                 double yy = d[i++];
454 //           lyxerr << ' ' << xx << ' ' << yy << ' ';
455                                 if (code == 4)
456                                         sqmt.transform(xx, yy);
457                                 else
458                                         mt.transform(xx, yy);
459                                 xp[j] = int(x + xx + 0.5);
460                                 yp[j] = int(y + yy + 0.5);
461                                 //  lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
462                         }
463                         pi.pain.lines(xp, yp, n, LColor::math);
464                 }
465         }
466 }
467
468
469 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
470 {
471         LyXFont f = pi.base.font;
472         f.setColor(LColor::latex);
473         pi.pain.text(x, y, str, f);
474 }
475
476
477 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
478 {
479         LyXFont f = pi.base.font;
480         f.setColor(LColor::foreground);
481         pi.pain.text(x, y, str, f);
482 }
483
484
485 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
486 {
487         frontend::FontMetrics const & fm = theFontMetrics(font);
488         asc = fm.maxAscent();
489         des = fm.maxDescent();
490 }
491
492
493 struct fontinfo {
494         std::string cmd_;
495         LyXFont::FONT_FAMILY family_;
496         LyXFont::FONT_SERIES series_;
497         LyXFont::FONT_SHAPE  shape_;
498         LColor::color        color_;
499 };
500
501
502 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
503 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
504 LyXFont::FONT_SHAPE  const inh_shape  = LyXFont::INHERIT_SHAPE;
505
506
507 // mathnormal should be the first, otherwise the fallback further down
508 // does not work
509 fontinfo fontinfos[] = {
510         // math fonts
511         {"mathnormal",    LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
512                           LyXFont::ITALIC_SHAPE, LColor::math},
513         {"mathbf",        inh_family, LyXFont::BOLD_SERIES,
514                           inh_shape, LColor::math},
515         {"mathcal",       LyXFont::CMSY_FAMILY, inh_series,
516                           inh_shape, LColor::math},
517         {"mathfrak",      LyXFont::EUFRAK_FAMILY, inh_series,
518                           inh_shape, LColor::math},
519         {"mathrm",        LyXFont::ROMAN_FAMILY, inh_series,
520                           LyXFont::UP_SHAPE, LColor::math},
521         {"mathsf",        LyXFont::SANS_FAMILY, inh_series,
522                           inh_shape, LColor::math},
523         {"mathbb",        LyXFont::MSB_FAMILY, inh_series,
524                           inh_shape, LColor::math},
525         {"mathtt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
526                           inh_shape, LColor::math},
527         {"mathit",        inh_family, inh_series,
528                           LyXFont::ITALIC_SHAPE, LColor::math},
529         {"cmex",          LyXFont::CMEX_FAMILY, inh_series,
530                           inh_shape, LColor::math},
531         {"cmm",           LyXFont::CMM_FAMILY, inh_series,
532                           inh_shape, LColor::math},
533         {"cmr",           LyXFont::CMR_FAMILY, inh_series,
534                           inh_shape, LColor::math},
535         {"cmsy",          LyXFont::CMSY_FAMILY, inh_series,
536                           inh_shape, LColor::math},
537         {"eufrak",        LyXFont::EUFRAK_FAMILY, inh_series,
538                           inh_shape, LColor::math},
539         {"msa",           LyXFont::MSA_FAMILY, inh_series,
540                           inh_shape, LColor::math},
541         {"msb",           LyXFont::MSB_FAMILY, inh_series,
542                           inh_shape, LColor::math},
543         {"wasy",          LyXFont::WASY_FAMILY, inh_series,
544                           inh_shape, LColor::none},
545         {"esint",         LyXFont::ESINT_FAMILY, inh_series,
546                           inh_shape, LColor::none},
547
548         // Text fonts
549         {"text",          inh_family, inh_series,
550                           inh_shape, LColor::foreground},
551         {"textbf",        inh_family, LyXFont::BOLD_SERIES,
552                           inh_shape, LColor::foreground},
553         {"textit",        inh_family, inh_series,
554                           LyXFont::ITALIC_SHAPE, LColor::foreground},
555         {"textmd",        inh_family, LyXFont::MEDIUM_SERIES,
556                           inh_shape, LColor::foreground},
557         {"textnormal",    inh_family, inh_series,
558                           LyXFont::UP_SHAPE, LColor::foreground},
559         {"textrm",        LyXFont::ROMAN_FAMILY,
560                           inh_series, LyXFont::UP_SHAPE,LColor::foreground},
561         {"textsc",        inh_family, inh_series,
562                           LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
563         {"textsf",        LyXFont::SANS_FAMILY, inh_series,
564                           inh_shape, LColor::foreground},
565         {"textsl",        inh_family, inh_series,
566                           LyXFont::SLANTED_SHAPE, LColor::foreground},
567         {"texttt",        LyXFont::TYPEWRITER_FAMILY, inh_series,
568                           inh_shape, LColor::foreground},
569         {"textup",        inh_family, inh_series,
570                           LyXFont::UP_SHAPE, LColor::foreground},
571
572         // TIPA support
573         {"textipa",       inh_family, inh_series,
574                           inh_shape, LColor::foreground},
575
576         // LyX internal usage
577         {"lyxtex",        inh_family, inh_series,
578                           LyXFont::UP_SHAPE, LColor::latex},
579         {"lyxsymbol",     LyXFont::SYMBOL_FAMILY, inh_series,
580                           inh_shape, LColor::math},
581         {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
582                           inh_shape, LColor::math},
583         {"lyxblacktext",  LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
584                           LyXFont::UP_SHAPE, LColor::foreground},
585         {"lyxnochange",   inh_family, inh_series,
586                           inh_shape, LColor::foreground},
587         {"lyxfakebb",     LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
588                           LyXFont::UP_SHAPE, LColor::math},
589         {"lyxfakecal",    LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
590                           LyXFont::ITALIC_SHAPE, LColor::math},
591         {"lyxfakefrak",   LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
592                           LyXFont::ITALIC_SHAPE, LColor::math}
593 };
594
595
596 fontinfo * lookupFont(docstring const & name0)
597 {
598         //lyxerr << "searching font '" << name << "'" << endl;
599         int const n = sizeof(fontinfos) / sizeof(fontinfo);
600         std::string name = to_utf8(name0);
601         for (int i = 0; i < n; ++i)
602                 if (fontinfos[i].cmd_ == name) {
603                         //lyxerr << "found '" << i << "'" << endl;
604                         return fontinfos + i;
605                 }
606         return 0;
607 }
608
609
610 fontinfo * searchFont(docstring const & name)
611 {
612         fontinfo * f = lookupFont(name);
613         return f ? f : fontinfos;
614         // this should be mathnormal
615         //return searchFont("mathnormal");
616 }
617
618
619 bool isFontName(docstring const & name)
620 {
621         return lookupFont(name);
622 }
623
624
625 LyXFont getFont(docstring const & name)
626 {
627         LyXFont font;
628         augmentFont(font, name);
629         return font;
630 }
631
632
633 void fakeFont(docstring const & orig, docstring const & fake)
634 {
635         fontinfo * forig = searchFont(orig);
636         fontinfo * ffake = searchFont(fake);
637         if (forig && ffake) {
638                 forig->family_ = ffake->family_;
639                 forig->series_ = ffake->series_;
640                 forig->shape_  = ffake->shape_;
641                 forig->color_  = ffake->color_;
642         } else {
643                 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
644                        << to_utf8(fake) << "'" << endl;
645         }
646 }
647
648
649 void augmentFont(LyXFont & font, docstring const & name)
650 {
651         static bool initialized = false;
652         if (!initialized) {
653                 initialized = true;
654                 // fake fonts if necessary
655                 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
656                         fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
657                 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
658                         fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
659         }
660         fontinfo * info = searchFont(name);
661         if (info->family_ != inh_family)
662                 font.setFamily(info->family_);
663         if (info->series_ != inh_series)
664                 font.setSeries(info->series_);
665         if (info->shape_ != inh_shape)
666                 font.setShape(info->shape_);
667         if (info->color_ != LColor::none)
668                 font.setColor(info->color_);
669 }
670
671
672 docstring asString(MathArray const & ar)
673 {
674         odocstringstream os;
675         WriteStream ws(os);
676         ws << ar;
677         return os.str();
678 }
679
680
681 void asArray(docstring const & str, MathArray & ar)
682 {
683         mathed_parse_cell(ar, str);
684 }
685
686
687 docstring asString(InsetMath const & inset)
688 {
689         odocstringstream os;
690         WriteStream ws(os);
691         inset.write(ws);
692         return os.str();
693 }
694
695
696 docstring asString(MathAtom const & at)
697 {
698         odocstringstream os;
699         WriteStream ws(os);
700         at->write(ws);
701         return os.str();
702 }
703
704
705 } // namespace lyx