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/FontLoader.h"
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
31 using lyx::frontend::Painter;
42 Matrix(int, double, double);
44 void transform(double &, double &);
51 Matrix::Matrix(int code, double x, double y)
53 double const cs = (code & 1) ? 0 : (1 - code);
54 double const sn = (code & 1) ? (2 - code) : 0;
62 void Matrix::transform(double & x, double & y)
64 double xx = m_[0][0] * x + m_[0][1] * y;
65 double yy = m_[1][0] * x + m_[1][1] * y;
75 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
76 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
80 double const parenthHigh[] = {
82 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
83 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
84 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
85 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
91 double const parenth[] = {
93 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
94 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
95 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
96 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
102 double const brace[] = {
104 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
105 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
106 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
107 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
108 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
109 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
110 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
115 double const arrow[] = {
117 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
118 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
120 3, 0.5000, 0.1500, 0.5000, 0.9500,
125 double const Arrow[] = {
127 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
128 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
130 3, 0.3500, 0.5000, 0.3500, 0.9500,
131 3, 0.6500, 0.5000, 0.6500, 0.9500,
136 double const udarrow[] = {
138 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
140 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
141 1, 0.5, 0.2, 0.5, 0.8,
146 double const Udarrow[] = {
148 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
150 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
151 1, 0.35, 0.2, 0.35, 0.8,
152 1, 0.65, 0.2, 0.65, 0.8,
157 double const brack[] = {
159 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
164 double const corner[] = {
166 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
171 double const angle[] = {
173 1, 0, 0.05, 0.5, 1, 1,
178 double const slash[] = {
179 1, 0.95, 0.05, 0.05, 0.95,
184 double const hline[] = {
185 1, 0.00, 0.5, 1.0, 0.5,
190 double const ddot[] = {
191 1, 0.2, 0.5, 0.3, 0.5,
192 1, 0.7, 0.5, 0.8, 0.5,
197 double const dddot[] = {
198 1, 0.1, 0.5, 0.2, 0.5,
199 1, 0.45, 0.5, 0.55, 0.5,
200 1, 0.8, 0.5, 0.9, 0.5,
205 double const hline3[] = {
207 1, 0.475, 0, 0.525, 0,
213 double const dline3[] = {
214 1, 0.1, 0.1, 0.15, 0.15,
215 1, 0.475, 0.475, 0.525, 0.525,
216 1, 0.85, 0.85, 0.9, 0.9,
221 double const hlinesmall[] = {
222 1, 0.4, 0.5, 0.6, 0.5,
227 double const ring[] = {
229 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
234 double const vert[] = {
235 1, 0.5, 0.05, 0.5, 0.95,
240 double const Vert[] = {
241 1, 0.3, 0.05, 0.3, 0.95,
242 1, 0.7, 0.05, 0.7, 0.95,
247 double const tilde[] = {
249 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
259 struct named_deco_struct {
265 named_deco_struct deco_table[] = {
267 {"widehat", angle, 3 },
268 {"widetilde", tilde, 0 },
269 {"underbar", hline, 0 },
270 {"underline", hline, 0 },
271 {"overline", hline, 0 },
272 {"underbrace", brace, 1 },
273 {"overbrace", brace, 3 },
274 {"overleftarrow", arrow, 1 },
275 {"overrightarrow", arrow, 3 },
276 {"overleftrightarrow", udarrow, 1 },
277 {"xleftarrow", arrow, 1 },
278 {"xrightarrow", arrow, 3 },
279 {"underleftarrow", arrow, 1 },
280 {"underrightarrow", arrow, 3 },
281 {"underleftrightarrow", udarrow, 1 },
288 {"lbrace", brace, 0 },
289 {"rbrace", brace, 2 },
297 {"backslash", slash, 1 },
298 {"langle", angle, 0 },
299 {"lceil", corner, 0 },
300 {"lfloor", corner, 1 },
301 {"rangle", angle, 2 },
302 {"rceil", corner, 3 },
303 {"rfloor", corner, 2 },
304 {"downarrow", arrow, 2 },
305 {"Downarrow", Arrow, 2 },
306 {"uparrow", arrow, 0 },
307 {"Uparrow", Arrow, 0 },
308 {"updownarrow", udarrow, 0 },
309 {"Updownarrow", Udarrow, 0 },
313 {"dddot", dddot, 0 },
315 {"grave", slash, 1 },
316 {"acute", slash, 0 },
317 {"tilde", tilde, 0 },
319 {"dot", hlinesmall, 0 },
320 {"check", angle, 1 },
321 {"breve", parenth, 1 },
323 {"mathring", ring, 0 },
326 {"dots", hline3, 0 },
327 {"ldots", hline3, 0 },
328 {"cdots", hline3, 0 },
329 {"vdots", hline3, 1 },
330 {"ddots", dline3, 0 },
331 {"dotsb", hline3, 0 },
332 {"dotsc", hline3, 0 },
333 {"dotsi", hline3, 0 },
334 {"dotsm", hline3, 0 },
335 {"dotso", hline3, 0 }
339 std::map<string, deco_struct> deco_list;
341 // sort the table on startup
342 class init_deco_table {
345 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
346 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
350 deco_list[p->name]= d;
355 static init_deco_table dummy;
358 deco_struct const * search_deco(string const & name)
360 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
361 return (p == deco_list.end()) ? 0 : &(p->second);
368 void mathed_char_dim(LyXFont const & font, lyx::char_type c, Dimension & dim)
370 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
371 dim.des = fm.descent(c);
372 dim.asc = fm.ascent(c);
373 dim.wid = fm.width(c);
377 int mathed_char_width(LyXFont const & font, lyx::char_type c)
379 return theFontMetrics(font).width(c);
383 void mathed_string_dim(LyXFont const & font, docstring const & s, Dimension & dim)
385 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
388 for (docstring::const_iterator it = s.begin(); it != s.end(); ++it) {
389 dim.asc = max(dim.asc, fm.ascent(*it));
390 dim.des = max(dim.des, fm.descent(*it));
392 dim.wid = fm.width(s);
396 int mathed_string_width(LyXFont const & font, docstring const & s)
398 return theFontMetrics(font).width(s);
402 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
406 pi.pain.line(x + w/2, y, x + w/2, y + h,
407 LColor::cursor, Painter::line_onoffdash);
411 deco_struct const * mds = search_deco(name);
413 lyxerr << "Deco was not found. Programming error?" << endl;
414 lyxerr << "name: '" << name << "'" << endl;
418 int const n = (w < h) ? w : h;
419 int const r = mds->angle;
420 double const * d = mds->data;
422 if (h > 70 && (name == "(" || name == ")"))
426 Matrix sqmt(r, n, n);
434 for (int i = 0; d[i]; ) {
435 int code = int(d[i++]);
436 if (code & 1) { // code == 1 || code == 3
442 sqmt.transform(xx, yy);
444 mt.transform(xx, yy);
445 mt.transform(x2, y2);
447 int(x + xx + 0.5), int(y + yy + 0.5),
448 int(x + x2 + 0.5), int(y + y2 + 0.5),
453 int const n = int(d[i++]);
454 for (int j = 0; j < n; ++j) {
457 // lyxerr << ' ' << xx << ' ' << yy << ' ';
459 sqmt.transform(xx, yy);
461 mt.transform(xx, yy);
462 xp[j] = int(x + xx + 0.5);
463 yp[j] = int(y + yy + 0.5);
464 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
466 pi.pain.lines(xp, yp, n, LColor::math);
472 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
474 LyXFont f = pi.base.font;
475 f.setColor(LColor::latex);
476 pi.pain.text(x, y, str, f);
480 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
482 LyXFont f = pi.base.font;
483 f.setColor(LColor::foreground);
484 pi.pain.text(x, y, str, f);
488 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
490 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
491 asc = fm.maxAscent();
492 des = fm.maxDescent();
498 LyXFont::FONT_FAMILY family_;
499 LyXFont::FONT_SERIES series_;
500 LyXFont::FONT_SHAPE shape_;
501 LColor::color color_;
505 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
506 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
507 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
510 // mathnormal should be the first, otherwise the fallback further down
512 fontinfo fontinfos[] = {
514 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
515 LyXFont::ITALIC_SHAPE, LColor::math},
516 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
517 inh_shape, LColor::math},
518 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
519 inh_shape, LColor::math},
520 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
521 inh_shape, LColor::math},
522 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
523 LyXFont::UP_SHAPE, LColor::math},
524 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
525 inh_shape, LColor::math},
526 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
527 inh_shape, LColor::math},
528 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
529 inh_shape, LColor::math},
530 {"mathit", inh_family, inh_series,
531 LyXFont::ITALIC_SHAPE, LColor::math},
532 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
533 inh_shape, LColor::math},
534 {"cmm", LyXFont::CMM_FAMILY, inh_series,
535 inh_shape, LColor::math},
536 {"cmr", LyXFont::CMR_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"msa", LyXFont::MSA_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"msb", LyXFont::MSB_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"wasy", LyXFont::WASY_FAMILY, inh_series,
547 inh_shape, LColor::none},
550 {"text", inh_family, inh_series,
551 inh_shape, LColor::foreground},
552 {"textbf", inh_family, LyXFont::BOLD_SERIES,
553 inh_shape, LColor::foreground},
554 {"textit", inh_family, inh_series,
555 LyXFont::ITALIC_SHAPE, LColor::foreground},
556 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
557 inh_shape, LColor::foreground},
558 {"textnormal", inh_family, inh_series,
559 LyXFont::UP_SHAPE, LColor::foreground},
560 {"textrm", LyXFont::ROMAN_FAMILY,
561 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
562 {"textsc", inh_family, inh_series,
563 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
564 {"textsf", LyXFont::SANS_FAMILY, inh_series,
565 inh_shape, LColor::foreground},
566 {"textsl", inh_family, inh_series,
567 LyXFont::SLANTED_SHAPE, LColor::foreground},
568 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
569 inh_shape, LColor::foreground},
570 {"textup", inh_family, inh_series,
571 LyXFont::UP_SHAPE, LColor::foreground},
574 {"textipa", inh_family, inh_series,
575 inh_shape, LColor::foreground},
577 // LyX internal usage
578 {"lyxtex", inh_family, inh_series,
579 LyXFont::UP_SHAPE, LColor::latex},
580 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
581 inh_shape, LColor::math},
582 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
583 inh_shape, LColor::math},
584 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
585 LyXFont::UP_SHAPE, LColor::foreground},
586 {"lyxnochange", inh_family, inh_series,
587 inh_shape, LColor::foreground},
588 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
589 LyXFont::UP_SHAPE, LColor::math},
590 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
591 LyXFont::ITALIC_SHAPE, LColor::math},
592 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
593 LyXFont::ITALIC_SHAPE, LColor::math}
597 fontinfo * lookupFont(string const & name)
599 //lyxerr << "searching font '" << name << "'" << endl;
600 int const n = sizeof(fontinfos) / sizeof(fontinfo);
601 for (int i = 0; i < n; ++i)
602 if (fontinfos[i].cmd_ == name) {
603 //lyxerr << "found '" << i << "'" << endl;
604 return fontinfos + i;
610 fontinfo * searchFont(string const & name)
612 fontinfo * f = lookupFont(name);
613 return f ? f : fontinfos;
614 // this should be mathnormal
615 //return searchFont("mathnormal");
619 bool isFontName(string const & name)
621 return lookupFont(name);
625 LyXFont getFont(string const & name)
628 augmentFont(font, name);
633 void fakeFont(string const & orig, string const & fake)
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_;
643 lyxerr << "Can't fake font '" << orig << "' with '"
644 << fake << "'" << endl;
649 void augmentFont(LyXFont & font, string const & name)
651 static bool initialized = false;
654 // fake fonts if necessary
655 if (!theFontLoader().available(getFont("mathfrak")))
656 fakeFont("mathfrak", "lyxfakefrak");
657 if (!theFontLoader().available(getFont("mathcal")))
658 fakeFont("mathcal", "lyxfakecal");
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_);
672 string asString(MathArray const & ar)
674 lyx::odocstringstream os;
678 return lyx::to_utf8(os.str());
682 void asArray(docstring const & str, MathArray & ar)
684 mathed_parse_cell(ar, lyx::to_utf8(str));
688 string asString(InsetMath const & inset)
690 lyx::odocstringstream os;
694 return lyx::to_utf8(os.str());
698 string asString(MathAtom const & at)
700 lyx::odocstringstream os;
704 return lyx::to_utf8(os.str());