3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
9 * Full author contact details are available in file CREDITS.
14 #include "MathSupport.h"
16 #include "InsetMath.h"
17 #include "MathMLStream.h"
18 #include "MathParser.h"
23 #include "frontends/Application.h"
24 #include "frontends/Painter.h"
25 #include "frontends/font_metrics.h"
26 #include "frontends/FontLoader.h"
32 using lyx::frontend::Painter;
43 Matrix(int, double, double);
45 void transform(double &, double &);
52 Matrix::Matrix(int code, double x, double y)
54 double const cs = (code & 1) ? 0 : (1 - code);
55 double const sn = (code & 1) ? (2 - code) : 0;
63 void Matrix::transform(double & x, double & y)
65 double xx = m_[0][0] * x + m_[0][1] * y;
66 double yy = m_[1][0] * x + m_[1][1] * y;
76 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
81 double const parenthHigh[] = {
83 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
92 double const parenth[] = {
94 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
103 double const brace[] = {
105 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
116 double const arrow[] = {
118 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
121 3, 0.5000, 0.1500, 0.5000, 0.9500,
126 double const Arrow[] = {
128 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
131 3, 0.3500, 0.5000, 0.3500, 0.9500,
132 3, 0.6500, 0.5000, 0.6500, 0.9500,
137 double const udarrow[] = {
139 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
141 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
142 1, 0.5, 0.2, 0.5, 0.8,
147 double const Udarrow[] = {
149 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
151 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
152 1, 0.35, 0.2, 0.35, 0.8,
153 1, 0.65, 0.2, 0.65, 0.8,
158 double const brack[] = {
160 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
165 double const corner[] = {
167 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
172 double const angle[] = {
174 1, 0, 0.05, 0.5, 1, 1,
179 double const slash[] = {
180 1, 0.95, 0.05, 0.05, 0.95,
185 double const hline[] = {
186 1, 0.00, 0.5, 1.0, 0.5,
191 double const ddot[] = {
192 1, 0.2, 0.5, 0.3, 0.5,
193 1, 0.7, 0.5, 0.8, 0.5,
198 double const dddot[] = {
199 1, 0.1, 0.5, 0.2, 0.5,
200 1, 0.45, 0.5, 0.55, 0.5,
201 1, 0.8, 0.5, 0.9, 0.5,
206 double const hline3[] = {
208 1, 0.475, 0, 0.525, 0,
214 double const dline3[] = {
215 1, 0.1, 0.1, 0.15, 0.15,
216 1, 0.475, 0.475, 0.525, 0.525,
217 1, 0.85, 0.85, 0.9, 0.9,
222 double const hlinesmall[] = {
223 1, 0.4, 0.5, 0.6, 0.5,
228 double const ring[] = {
230 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
235 double const vert[] = {
236 1, 0.5, 0.05, 0.5, 0.95,
241 double const Vert[] = {
242 1, 0.3, 0.05, 0.3, 0.95,
243 1, 0.7, 0.05, 0.7, 0.95,
248 double const tilde[] = {
250 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
260 struct named_deco_struct {
266 named_deco_struct deco_table[] = {
268 {"widehat", angle, 3 },
269 {"widetilde", tilde, 0 },
270 {"underbar", hline, 0 },
271 {"underline", hline, 0 },
272 {"overline", hline, 0 },
273 {"underbrace", brace, 1 },
274 {"overbrace", brace, 3 },
275 {"overleftarrow", arrow, 1 },
276 {"overrightarrow", arrow, 3 },
277 {"overleftrightarrow", udarrow, 1 },
278 {"xleftarrow", arrow, 1 },
279 {"xrightarrow", arrow, 3 },
280 {"underleftarrow", arrow, 1 },
281 {"underrightarrow", arrow, 3 },
282 {"underleftrightarrow", udarrow, 1 },
289 {"lbrace", brace, 0 },
290 {"rbrace", brace, 2 },
298 {"backslash", slash, 1 },
299 {"langle", angle, 0 },
300 {"lceil", corner, 0 },
301 {"lfloor", corner, 1 },
302 {"rangle", angle, 2 },
303 {"rceil", corner, 3 },
304 {"rfloor", corner, 2 },
305 {"downarrow", arrow, 2 },
306 {"Downarrow", Arrow, 2 },
307 {"uparrow", arrow, 0 },
308 {"Uparrow", Arrow, 0 },
309 {"updownarrow", udarrow, 0 },
310 {"Updownarrow", Udarrow, 0 },
314 {"dddot", dddot, 0 },
316 {"grave", slash, 1 },
317 {"acute", slash, 0 },
318 {"tilde", tilde, 0 },
320 {"dot", hlinesmall, 0 },
321 {"check", angle, 1 },
322 {"breve", parenth, 1 },
324 {"mathring", ring, 0 },
327 {"dots", hline3, 0 },
328 {"ldots", hline3, 0 },
329 {"cdots", hline3, 0 },
330 {"vdots", hline3, 1 },
331 {"ddots", dline3, 0 },
332 {"dotsb", hline3, 0 },
333 {"dotsc", hline3, 0 },
334 {"dotsi", hline3, 0 },
335 {"dotsm", hline3, 0 },
336 {"dotso", hline3, 0 }
340 std::map<string, deco_struct> deco_list;
342 // sort the table on startup
343 class init_deco_table {
346 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
347 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
351 deco_list[p->name]= d;
356 static init_deco_table dummy;
359 deco_struct const * search_deco(string const & name)
361 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
362 return (p == deco_list.end()) ? 0 : &(p->second);
369 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
371 dim.des = font_metrics::descent(c, font);
372 dim.asc = font_metrics::ascent(c, font);
373 dim.wid = mathed_char_width(font, c);
377 int mathed_char_ascent(LyXFont const & font, unsigned char c)
379 return font_metrics::ascent(c, font);
383 int mathed_char_descent(LyXFont const & font, unsigned char c)
385 return font_metrics::descent(c, font);
389 int mathed_char_width(LyXFont const & font, unsigned char c)
391 return font_metrics::width(c, font);
395 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
400 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
401 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
402 dim.des = max(dim.des, font_metrics::descent(*it, font));
405 dim.asc = font_metrics::maxAscent(font);
406 dim.des = font_metrics::maxDescent(font);
408 docstring ds(s.begin(), s.end());
409 dim.wid = font_metrics::width(ds, font);
413 int mathed_string_width(LyXFont const & font, string const & s)
415 docstring ds(s.begin(), s.end());
416 return font_metrics::width(ds, font);
420 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
424 pi.pain.line(x + w/2, y, x + w/2, y + h,
425 LColor::cursor, Painter::line_onoffdash);
429 deco_struct const * mds = search_deco(name);
431 lyxerr << "Deco was not found. Programming error?" << endl;
432 lyxerr << "name: '" << name << "'" << endl;
436 int const n = (w < h) ? w : h;
437 int const r = mds->angle;
438 double const * d = mds->data;
440 if (h > 70 && (name == "(" || name == ")"))
444 Matrix sqmt(r, n, n);
452 for (int i = 0; d[i]; ) {
453 int code = int(d[i++]);
454 if (code & 1) { // code == 1 || code == 3
460 sqmt.transform(xx, yy);
462 mt.transform(xx, yy);
463 mt.transform(x2, y2);
465 int(x + xx + 0.5), int(y + yy + 0.5),
466 int(x + x2 + 0.5), int(y + y2 + 0.5),
471 int const n = int(d[i++]);
472 for (int j = 0; j < n; ++j) {
475 // lyxerr << ' ' << xx << ' ' << yy << ' ';
477 sqmt.transform(xx, yy);
479 mt.transform(xx, yy);
480 xp[j] = int(x + xx + 0.5);
481 yp[j] = int(y + yy + 0.5);
482 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
484 pi.pain.lines(xp, yp, n, LColor::math);
490 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
492 LyXFont f = pi.base.font;
493 f.setColor(LColor::latex);
494 docstring dstr(str.begin(), str.end());
495 pi.pain.text(x, y, dstr, f);
499 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
501 LyXFont f = pi.base.font;
502 f.setColor(LColor::foreground);
503 docstring dstr(str.begin(), str.end());
504 pi.pain.text(x, y, dstr, f);
508 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
510 asc = font_metrics::maxAscent(font);
511 des = font_metrics::maxDescent(font);
517 LyXFont::FONT_FAMILY family_;
518 LyXFont::FONT_SERIES series_;
519 LyXFont::FONT_SHAPE shape_;
520 LColor::color color_;
524 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
525 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
526 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
529 // mathnormal should be the first, otherwise the fallback further down
531 fontinfo fontinfos[] = {
533 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
534 LyXFont::ITALIC_SHAPE, LColor::math},
535 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
536 inh_shape, LColor::math},
537 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
538 inh_shape, LColor::math},
539 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
540 inh_shape, LColor::math},
541 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
542 LyXFont::UP_SHAPE, LColor::math},
543 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
544 inh_shape, LColor::math},
545 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
546 inh_shape, LColor::math},
547 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"mathit", inh_family, inh_series,
550 LyXFont::ITALIC_SHAPE, LColor::math},
551 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
552 inh_shape, LColor::math},
553 {"cmm", LyXFont::CMM_FAMILY, inh_series,
554 inh_shape, LColor::math},
555 {"cmr", LyXFont::CMR_FAMILY, inh_series,
556 inh_shape, LColor::math},
557 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
558 inh_shape, LColor::math},
559 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
560 inh_shape, LColor::math},
561 {"msa", LyXFont::MSA_FAMILY, inh_series,
562 inh_shape, LColor::math},
563 {"msb", LyXFont::MSB_FAMILY, inh_series,
564 inh_shape, LColor::math},
565 {"wasy", LyXFont::WASY_FAMILY, inh_series,
566 inh_shape, LColor::none},
569 {"text", inh_family, inh_series,
570 inh_shape, LColor::foreground},
571 {"textbf", inh_family, LyXFont::BOLD_SERIES,
572 inh_shape, LColor::foreground},
573 {"textit", inh_family, inh_series,
574 LyXFont::ITALIC_SHAPE, LColor::foreground},
575 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
576 inh_shape, LColor::foreground},
577 {"textnormal", inh_family, inh_series,
578 LyXFont::UP_SHAPE, LColor::foreground},
579 {"textrm", LyXFont::ROMAN_FAMILY,
580 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
581 {"textsc", inh_family, inh_series,
582 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
583 {"textsf", LyXFont::SANS_FAMILY, inh_series,
584 inh_shape, LColor::foreground},
585 {"textsl", inh_family, inh_series,
586 LyXFont::SLANTED_SHAPE, LColor::foreground},
587 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
588 inh_shape, LColor::foreground},
589 {"textup", inh_family, inh_series,
590 LyXFont::UP_SHAPE, LColor::foreground},
593 {"textipa", inh_family, inh_series,
594 inh_shape, LColor::foreground},
596 // LyX internal usage
597 {"lyxtex", inh_family, inh_series,
598 LyXFont::UP_SHAPE, LColor::latex},
599 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
600 inh_shape, LColor::math},
601 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
602 inh_shape, LColor::math},
603 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
604 LyXFont::UP_SHAPE, LColor::foreground},
605 {"lyxnochange", inh_family, inh_series,
606 inh_shape, LColor::foreground},
607 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
608 LyXFont::UP_SHAPE, LColor::math},
609 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
610 LyXFont::ITALIC_SHAPE, LColor::math},
611 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
612 LyXFont::ITALIC_SHAPE, LColor::math}
616 fontinfo * lookupFont(string const & name)
618 //lyxerr << "searching font '" << name << "'" << endl;
619 int const n = sizeof(fontinfos) / sizeof(fontinfo);
620 for (int i = 0; i < n; ++i)
621 if (fontinfos[i].cmd_ == name) {
622 //lyxerr << "found '" << i << "'" << endl;
623 return fontinfos + i;
629 fontinfo * searchFont(string const & name)
631 fontinfo * f = lookupFont(name);
632 return f ? f : fontinfos;
633 // this should be mathnormal
634 //return searchFont("mathnormal");
638 bool isFontName(string const & name)
640 return lookupFont(name);
644 LyXFont getFont(string const & name)
647 augmentFont(font, name);
652 void fakeFont(string const & orig, string const & fake)
654 fontinfo * forig = searchFont(orig);
655 fontinfo * ffake = searchFont(fake);
656 if (forig && ffake) {
657 forig->family_ = ffake->family_;
658 forig->series_ = ffake->series_;
659 forig->shape_ = ffake->shape_;
660 forig->color_ = ffake->color_;
662 lyxerr << "Can't fake font '" << orig << "' with '"
663 << fake << "'" << endl;
668 void augmentFont(LyXFont & font, string const & name)
670 static bool initialized = false;
673 // fake fonts if necessary
674 if (!theApp->fontLoader().available(getFont("mathfrak")))
675 fakeFont("mathfrak", "lyxfakefrak");
676 if (!theApp->fontLoader().available(getFont("mathcal")))
677 fakeFont("mathcal", "lyxfakecal");
679 fontinfo * info = searchFont(name);
680 if (info->family_ != inh_family)
681 font.setFamily(info->family_);
682 if (info->series_ != inh_series)
683 font.setSeries(info->series_);
684 if (info->shape_ != inh_shape)
685 font.setShape(info->shape_);
686 if (info->color_ != LColor::none)
687 font.setColor(info->color_);
691 string asString(MathArray const & ar)
693 std::ostringstream os;
700 void asArray(string const & str, MathArray & ar)
702 mathed_parse_cell(ar, str);
706 string asString(InsetMath const & inset)
708 std::ostringstream os;
715 string asString(MathAtom const & at)
717 std::ostringstream os;