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 "math_support.h"
15 #include "math_data.h"
16 #include "math_inset.h"
17 #include "math_mathmlstream.h"
18 #include "math_parser.h"
23 #include "frontends/Painter.h"
24 #include "frontends/font_metrics.h"
25 #include "frontends/lyx_gui.h"
27 #include "support/std_sstream.h"
41 Matrix(int, double, double);
43 void transform(double &, double &);
50 Matrix::Matrix(int code, double x, double y)
52 double const cs = (code & 1) ? 0 : (1 - code);
53 double const sn = (code & 1) ? (2 - code) : 0;
61 void Matrix::transform(double & x, double & y)
63 double xx = m_[0][0] * x + m_[0][1] * y;
64 double yy = m_[1][0] * x + m_[1][1] * y;
74 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
75 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
79 double const parenthHigh[] = {
81 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
82 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
83 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
84 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
90 double const parenth[] = {
92 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
93 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
94 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
95 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
101 double const brace[] = {
103 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
104 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
105 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
106 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
107 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
108 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
109 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
114 double const arrow[] = {
116 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
117 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
119 3, 0.5000, 0.1500, 0.5000, 0.9500,
124 double const Arrow[] = {
126 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
127 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
129 3, 0.3500, 0.5000, 0.3500, 0.9500,
130 3, 0.6500, 0.5000, 0.6500, 0.9500,
135 double const udarrow[] = {
137 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
139 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
140 1, 0.5, 0.2, 0.5, 0.8,
145 double const Udarrow[] = {
147 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
149 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
150 1, 0.35, 0.2, 0.35, 0.8,
151 1, 0.65, 0.2, 0.65, 0.8,
156 double const brack[] = {
158 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
163 double const corner[] = {
165 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
170 double const angle[] = {
172 1, 0, 0.05, 0.5, 1, 1,
177 double const slash[] = {
178 1, 0.95, 0.05, 0.05, 0.95,
183 double const hline[] = {
184 1, 0.00, 0.5, 1.0, 0.5,
189 double const ddot[] = {
190 1, 0.2, 0.5, 0.3, 0.5,
191 1, 0.7, 0.5, 0.8, 0.5,
196 double const dddot[] = {
197 1, 0.1, 0.5, 0.2, 0.5,
198 1, 0.45, 0.5, 0.55, 0.5,
199 1, 0.8, 0.5, 0.9, 0.5,
204 double const hline3[] = {
206 1, 0.475, 0, 0.525, 0,
212 double const dline3[] = {
213 1, 0.1, 0.1, 0.15, 0.15,
214 1, 0.475, 0.475, 0.525, 0.525,
215 1, 0.85, 0.85, 0.9, 0.9,
220 double const hlinesmall[] = {
221 1, 0.4, 0.5, 0.6, 0.5,
226 double const ring[] = {
228 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
233 double const vert[] = {
234 1, 0.5, 0.05, 0.5, 0.95,
239 double const Vert[] = {
240 1, 0.3, 0.05, 0.3, 0.95,
241 1, 0.7, 0.05, 0.7, 0.95,
246 double const tilde[] = {
248 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
258 struct named_deco_struct {
264 named_deco_struct deco_table[] = {
266 {"widehat", angle, 3 },
267 {"widetilde", tilde, 0 },
268 {"underbar", hline, 0 },
269 {"underline", hline, 0 },
270 {"overline", hline, 0 },
271 {"underbrace", brace, 1 },
272 {"overbrace", brace, 3 },
273 {"overleftarrow", arrow, 1 },
274 {"overrightarrow", arrow, 3 },
275 {"overleftrightarrow", udarrow, 1 },
276 {"xleftarrow", arrow, 1 },
277 {"xrightarrow", arrow, 3 },
278 {"underleftarrow", arrow, 1 },
279 {"underrightarrow", arrow, 3 },
280 {"underleftrightarrow", udarrow, 1 },
294 {"backslash", slash, 1 },
295 {"langle", angle, 0 },
296 {"lceil", corner, 0 },
297 {"lfloor", corner, 1 },
298 {"rangle", angle, 2 },
299 {"rceil", corner, 3 },
300 {"rfloor", corner, 2 },
301 {"downarrow", arrow, 2 },
302 {"Downarrow", Arrow, 2 },
303 {"uparrow", arrow, 0 },
304 {"Uparrow", Arrow, 0 },
305 {"updownarrow", udarrow, 0 },
306 {"Updownarrow", Udarrow, 0 },
310 {"dddot", dddot, 0 },
312 {"grave", slash, 1 },
313 {"acute", slash, 0 },
314 {"tilde", tilde, 0 },
316 {"dot", hlinesmall, 0 },
317 {"check", angle, 1 },
318 {"breve", parenth, 1 },
320 {"mathring", ring, 0 },
323 {"dots", hline3, 0 },
324 {"ldots", hline3, 0 },
325 {"cdots", hline3, 0 },
326 {"vdots", hline3, 1 },
327 {"ddots", dline3, 0 },
328 {"dotsb", hline3, 0 },
329 {"dotsc", hline3, 0 },
330 {"dotsi", hline3, 0 },
331 {"dotsm", hline3, 0 },
332 {"dotso", hline3, 0 }
336 std::map<string, deco_struct> deco_list;
338 // sort the table on startup
339 struct init_deco_table {
341 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
342 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
346 deco_list[p->name]= d;
351 static init_deco_table dummy;
354 deco_struct const * search_deco(string const & name)
356 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
357 return (p == deco_list.end()) ? 0 : &(p->second);
364 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
366 dim.des = font_metrics::descent(c, font);
367 dim.asc = font_metrics::ascent(c, font);
368 dim.wid = mathed_char_width(font, c);
372 int mathed_char_ascent(LyXFont const & font, unsigned char c)
374 return font_metrics::ascent(c, font);
378 int mathed_char_descent(LyXFont const & font, unsigned char c)
380 return font_metrics::descent(c, font);
384 int mathed_char_width(LyXFont const & font, unsigned char c)
386 return font_metrics::width(c, font);
390 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
395 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
396 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
397 dim.des = max(dim.des, font_metrics::descent(*it, font));
400 dim.asc = font_metrics::maxAscent(font);
401 dim.des = font_metrics::maxDescent(font);
403 dim.wid = font_metrics::width(s, font);
407 int mathed_string_width(LyXFont const & font, string const & s)
409 return font_metrics::width(s, font);
413 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
417 pi.pain.line(x + w/2, y, x + w/2, y + h,
418 LColor::cursor, Painter::line_onoffdash);
422 deco_struct const * mds = search_deco(name);
424 lyxerr << "Deco was not found. Programming error?" << endl;
425 lyxerr << "name: '" << name << "'" << endl;
429 int const n = (w < h) ? w : h;
430 int const r = mds->angle;
431 double const * d = mds->data;
433 if (h > 70 && (name == "(" || name == ")"))
437 Matrix sqmt(r, n, n);
445 for (int i = 0; d[i]; ) {
446 int code = int(d[i++]);
447 if (code & 1) { // code == 1 || code == 3
453 sqmt.transform(xx, yy);
455 mt.transform(xx, yy);
456 mt.transform(x2, y2);
458 int(x + xx + 0.5), int(y + yy + 0.5),
459 int(x + x2 + 0.5), int(y + y2 + 0.5),
462 lyxerr << "drew line "
463 << "xx=" << xx << ", yy=" << yy
464 << ", x2 = " << x2 << ", y2 = " << y2 << '\n'
465 << int(x + xx + 0.5) << ", "
466 << int(y + yy + 0.5) << ", "
467 << int(x + x2 + 0.5) << ", "
468 << int(y + y2 + 0.5) << std::endl;
472 int const n = int(d[i++]);
473 for (int j = 0; j < n; ++j) {
476 // lyxerr << ' ' << xx << ' ' << yy << ' ';
478 sqmt.transform(xx, yy);
480 mt.transform(xx, yy);
481 xp[j] = int(x + xx + 0.5);
482 yp[j] = int(y + yy + 0.5);
483 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
485 pi.pain.lines(xp, yp, n, LColor::math);
491 // In the future maybe we use a better fonts renderer
492 void drawStr(PainterInfo & pi, LyXFont const & font,
493 int x, int y, string const & str)
495 pi.pain.text(x, y, str, font);
499 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
501 LyXFont f = pi.base.font;
502 f.setColor(LColor::latex);
503 pi.pain.text(x, y, str, f);
507 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
509 LyXFont f = pi.base.font;
510 f.setColor(LColor::foreground);
511 pi.pain.text(x, y, str, f);
515 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
517 pi.pain.text(x, y, c, font);
521 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
523 asc = font_metrics::maxAscent(font);
524 des = font_metrics::maxDescent(font);
530 LyXFont::FONT_FAMILY family_;
531 LyXFont::FONT_SERIES series_;
532 LyXFont::FONT_SHAPE shape_;
533 LColor::color color_;
537 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
538 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
539 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
542 // mathnormal should be the first, otherwise the fallback further down
544 fontinfo fontinfos[] = {
546 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
547 LyXFont::ITALIC_SHAPE, LColor::math},
548 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
549 inh_shape, LColor::math},
550 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
553 inh_shape, LColor::math},
554 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
555 LyXFont::UP_SHAPE, LColor::math},
556 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
557 inh_shape, LColor::math},
558 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
559 inh_shape, LColor::math},
560 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
561 inh_shape, LColor::math},
562 {"mathit", inh_family, inh_series,
563 LyXFont::ITALIC_SHAPE, LColor::math},
564 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
565 inh_shape, LColor::math},
566 {"cmm", LyXFont::CMM_FAMILY, inh_series,
567 inh_shape, LColor::math},
568 {"cmr", LyXFont::CMR_FAMILY, inh_series,
569 inh_shape, LColor::math},
570 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
571 inh_shape, LColor::math},
572 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
573 inh_shape, LColor::math},
574 {"msa", LyXFont::MSA_FAMILY, inh_series,
575 inh_shape, LColor::math},
576 {"msb", LyXFont::MSB_FAMILY, inh_series,
577 inh_shape, LColor::math},
578 {"wasy", LyXFont::WASY_FAMILY, inh_series,
579 inh_shape, LColor::none},
582 {"text", inh_family, inh_series,
583 inh_shape, LColor::foreground},
584 {"textbf", inh_family, LyXFont::BOLD_SERIES,
585 inh_shape, LColor::foreground},
586 {"textit", inh_family, inh_series,
587 LyXFont::ITALIC_SHAPE, LColor::foreground},
588 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
589 inh_shape, LColor::foreground},
590 {"textnormal", inh_family, inh_series,
591 LyXFont::UP_SHAPE, LColor::foreground},
592 {"textrm", LyXFont::ROMAN_FAMILY,
593 inh_series,LyXFont::UP_SHAPE,LColor::foreground},
594 {"textsc", inh_family, inh_series,
595 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
596 {"textsf", LyXFont::SANS_FAMILY, inh_series,
597 inh_shape, LColor::foreground},
598 {"textsl", inh_family, inh_series,
599 LyXFont::SLANTED_SHAPE, LColor::foreground},
600 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
601 inh_shape, LColor::foreground},
602 {"textup", inh_family, inh_series,
603 LyXFont::UP_SHAPE, LColor::foreground},
606 {"textipa", inh_family, inh_series,
607 inh_shape, LColor::foreground},
609 // LyX internal usage
610 {"lyxtex", inh_family, inh_series,
611 LyXFont::UP_SHAPE, LColor::latex},
612 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
613 LyXFont::UP_SHAPE, LColor::latex},
614 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
615 inh_shape, LColor::math},
616 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
617 inh_shape, LColor::math},
618 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
619 LyXFont::UP_SHAPE, LColor::foreground},
620 {"lyxnochange", inh_family, inh_series,
621 inh_shape, LColor::foreground},
622 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
623 LyXFont::UP_SHAPE, LColor::math},
624 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
625 LyXFont::ITALIC_SHAPE, LColor::math},
626 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
627 LyXFont::ITALIC_SHAPE, LColor::math}
631 fontinfo * lookupFont(string const & name)
633 //lyxerr << "searching font '" << name << "'" << endl;
634 int const n = sizeof(fontinfos) / sizeof(fontinfo);
635 for (int i = 0; i < n; ++i)
636 if (fontinfos[i].cmd_ == name) {
637 //lyxerr << "found '" << i << "'" << endl;
638 return fontinfos + i;
644 fontinfo * searchFont(string const & name)
646 fontinfo * f = lookupFont(name);
647 return f ? f : fontinfos;
648 // this should be mathnormal
649 //return searchFont("mathnormal");
653 bool isFontName(string const & name)
655 return lookupFont(name);
659 LyXFont getFont(string const & name)
662 augmentFont(font, name);
667 void fakeFont(string const & orig, string const & fake)
669 fontinfo * forig = searchFont(orig);
670 fontinfo * ffake = searchFont(fake);
671 if (forig && ffake) {
672 forig->family_ = ffake->family_;
673 forig->series_ = ffake->series_;
674 forig->shape_ = ffake->shape_;
675 forig->color_ = ffake->color_;
677 lyxerr << "Can't fake font '" << orig << "' with '"
678 << fake << "'" << endl;
683 void augmentFont(LyXFont & font, string const & name)
685 static bool initialized = false;
688 // fake fonts if necessary
689 if (!lyx_gui::font_available(getFont("mathfrak")))
690 fakeFont("mathfrak", "lyxfakefrak");
691 if (!lyx_gui::font_available(getFont("mathcal")))
692 fakeFont("mathcal", "lyxfakecal");
694 fontinfo * info = searchFont(name);
695 if (info->family_ != inh_family)
696 font.setFamily(info->family_);
697 if (info->series_ != inh_series)
698 font.setSeries(info->series_);
699 if (info->shape_ != inh_shape)
700 font.setShape(info->shape_);
701 if (info->color_ != LColor::none)
702 font.setColor(info->color_);
706 string asString(MathArray const & ar)
708 std::ostringstream os;
715 void asArray(string const & str, MathArray & ar)
717 mathed_parse_cell(ar, str);
721 string asString(MathInset const & inset)
723 std::ostringstream os;
730 string asString(MathAtom const & at)
732 std::ostringstream os;