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 "MathStream.h"
18 #include "MathParser.h"
23 #include "frontends/FontLoader.h"
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
33 using frontend::Painter;
44 Matrix(int, double, double);
46 void transform(double &, double &);
53 Matrix::Matrix(int code, double x, double y)
55 double const cs = (code & 1) ? 0 : (1 - code);
56 double const sn = (code & 1) ? (2 - code) : 0;
64 void Matrix::transform(double & x, double & y)
66 double xx = m_[0][0] * x + m_[0][1] * y;
67 double yy = m_[1][0] * x + m_[1][1] * y;
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
82 double const parenthHigh[] = {
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,
93 double const parenth[] = {
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,
104 double const brace[] = {
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,
117 double const arrow[] = {
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,
122 3, 0.5000, 0.1500, 0.5000, 0.9500,
127 double const Arrow[] = {
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,
132 3, 0.3500, 0.5000, 0.3500, 0.9500,
133 3, 0.6500, 0.5000, 0.6500, 0.9500,
138 double const udarrow[] = {
140 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
142 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
143 1, 0.5, 0.2, 0.5, 0.8,
148 double const Udarrow[] = {
150 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
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,
159 double const brack[] = {
161 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
166 double const corner[] = {
168 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
173 double const angle[] = {
175 1, 0, 0.05, 0.5, 1, 1,
180 double const slash[] = {
181 1, 0.95, 0.05, 0.05, 0.95,
186 double const hline[] = {
187 1, 0.00, 0.5, 1.0, 0.5,
192 double const ddot[] = {
193 1, 0.2, 0.5, 0.3, 0.5,
194 1, 0.7, 0.5, 0.8, 0.5,
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,
207 double const hline3[] = {
209 1, 0.475, 0, 0.525, 0,
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,
223 double const hlinesmall[] = {
224 1, 0.4, 0.5, 0.6, 0.5,
229 double const ring[] = {
231 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
236 double const vert[] = {
237 1, 0.5, 0.05, 0.5, 0.95,
242 double const Vert[] = {
243 1, 0.3, 0.05, 0.3, 0.95,
244 1, 0.7, 0.05, 0.7, 0.95,
249 double const tilde[] = {
251 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
261 struct named_deco_struct {
267 named_deco_struct deco_table[] = {
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 },
290 {"lbrace", brace, 0 },
291 {"rbrace", brace, 2 },
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 },
315 {"dddot", dddot, 0 },
317 {"grave", slash, 1 },
318 {"acute", slash, 0 },
319 {"tilde", tilde, 0 },
321 {"dot", hlinesmall, 0 },
322 {"check", angle, 1 },
323 {"breve", parenth, 1 },
325 {"mathring", ring, 0 },
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 }
341 std::map<docstring, deco_struct> deco_list;
343 // sort the table on startup
344 class 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) {
352 deco_list[from_ascii(p->name)] = d;
357 static init_deco_table dummy;
360 deco_struct const * search_deco(docstring const & name)
362 std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
363 return p == deco_list.end() ? 0 : &(p->second);
370 void mathed_char_dim(LyXFont const & font, char_type c, Dimension & dim)
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);
379 int mathed_char_width(LyXFont const & font, char_type c)
381 return theFontMetrics(font).width(c);
385 void mathed_string_dim(LyXFont const & font,
389 frontend::FontMetrics const & fm = theFontMetrics(font);
392 for (docstring::const_iterator it = s.begin();
395 dim.asc = max(dim.asc, fm.ascent(*it));
396 dim.des = max(dim.des, fm.descent(*it));
398 dim.wid = fm.width(&s[0], s.size());
402 int mathed_string_width(LyXFont const & font, docstring const & s)
404 return theFontMetrics(font).width(s);
408 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
409 docstring const & name)
412 pi.pain.line(x + w/2, y, x + w/2, y + h,
413 LColor::cursor, Painter::line_onoffdash);
417 deco_struct const * mds = search_deco(name);
419 lyxerr << "Deco was not found. Programming error?" << endl;
420 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
424 int const n = (w < h) ? w : h;
425 int const r = mds->angle;
426 double const * d = mds->data;
428 if (h > 70 && (name == "(" || name == ")"))
432 Matrix sqmt(r, n, n);
440 for (int i = 0; d[i]; ) {
441 int code = int(d[i++]);
442 if (code & 1) { // code == 1 || code == 3
448 sqmt.transform(xx, yy);
450 mt.transform(xx, yy);
451 mt.transform(x2, y2);
453 int(x + xx + 0.5), int(y + yy + 0.5),
454 int(x + x2 + 0.5), int(y + y2 + 0.5),
459 int const n = int(d[i++]);
460 for (int j = 0; j < n; ++j) {
463 // lyxerr << ' ' << xx << ' ' << yy << ' ';
465 sqmt.transform(xx, yy);
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 << ']';
472 pi.pain.lines(xp, yp, n, LColor::math);
478 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
480 LyXFont f = pi.base.font;
481 f.setColor(LColor::latex);
482 pi.pain.text(x, y, str, f);
486 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
488 LyXFont f = pi.base.font;
489 f.setColor(LColor::foreground);
490 pi.pain.text(x, y, str, f);
494 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
496 frontend::FontMetrics const & fm = theFontMetrics(font);
497 asc = fm.maxAscent();
498 des = fm.maxDescent();
504 LyXFont::FONT_FAMILY family_;
505 LyXFont::FONT_SERIES series_;
506 LyXFont::FONT_SHAPE shape_;
507 LColor::color color_;
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;
516 // mathnormal should be the first, otherwise the fallback further down
518 fontinfo fontinfos[] = {
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},
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},
580 {"textipa", inh_family, inh_series,
581 inh_shape, LColor::foreground},
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}
603 fontinfo * lookupFont(docstring const & name0)
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;
617 fontinfo * searchFont(docstring const & name)
619 fontinfo * f = lookupFont(name);
620 return f ? f : fontinfos;
621 // this should be mathnormal
622 //return searchFont("mathnormal");
626 bool isFontName(docstring const & name)
628 return lookupFont(name);
632 LyXFont getFont(docstring const & name)
635 augmentFont(font, name);
640 void fakeFont(docstring const & orig, docstring const & fake)
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_;
650 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
651 << to_utf8(fake) << "'" << endl;
656 void augmentFont(LyXFont & font, docstring const & name)
658 static bool initialized = false;
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"));
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_);
679 docstring asString(MathArray const & ar)
688 void asArray(docstring const & str, MathArray & ar)
690 mathed_parse_cell(ar, str);
694 docstring asString(InsetMath const & inset)
703 docstring asString(MathAtom const & at)