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),
464 int const n = int(d[i++]);
465 for (int j = 0; j < n; ++j) {
468 // lyxerr << ' ' << xx << ' ' << yy << ' ';
470 sqmt.transform(xx, yy);
472 mt.transform(xx, yy);
473 xp[j] = int(x + xx + 0.5);
474 yp[j] = int(y + yy + 0.5);
475 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
477 pi.pain.lines(xp, yp, n, LColor::math);
483 // In the future maybe we use a better fonts renderer
484 void drawStr(PainterInfo & pi, LyXFont const & font,
485 int x, int y, string const & str)
487 pi.pain.text(x, y, str, font);
491 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
493 LyXFont f = pi.base.font;
494 f.setColor(LColor::latex);
495 pi.pain.text(x, y, str, 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 pi.pain.text(x, y, str, f);
507 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
509 pi.pain.text(x, y, c, font);
513 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
515 asc = font_metrics::maxAscent(font);
516 des = font_metrics::maxDescent(font);
522 LyXFont::FONT_FAMILY family_;
523 LyXFont::FONT_SERIES series_;
524 LyXFont::FONT_SHAPE shape_;
525 LColor::color color_;
529 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
530 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
531 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
534 // mathnormal should be the first, otherwise the fallback further down
536 fontinfo fontinfos[] = {
538 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
539 LyXFont::ITALIC_SHAPE, LColor::math},
540 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
541 inh_shape, LColor::math},
542 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
547 LyXFont::UP_SHAPE, LColor::math},
548 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
549 inh_shape, LColor::math},
550 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
553 inh_shape, LColor::math},
554 {"mathit", inh_family, inh_series,
555 LyXFont::ITALIC_SHAPE, LColor::math},
556 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
557 inh_shape, LColor::math},
558 {"cmm", LyXFont::CMM_FAMILY, inh_series,
559 inh_shape, LColor::math},
560 {"cmr", LyXFont::CMR_FAMILY, inh_series,
561 inh_shape, LColor::math},
562 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
563 inh_shape, LColor::math},
564 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
565 inh_shape, LColor::math},
566 {"msa", LyXFont::MSA_FAMILY, inh_series,
567 inh_shape, LColor::math},
568 {"msb", LyXFont::MSB_FAMILY, inh_series,
569 inh_shape, LColor::math},
570 {"wasy", LyXFont::WASY_FAMILY, inh_series,
571 inh_shape, LColor::none},
574 {"text", inh_family, inh_series,
575 inh_shape, LColor::foreground},
576 {"textbf", inh_family, LyXFont::BOLD_SERIES,
577 inh_shape, LColor::foreground},
578 {"textit", inh_family, inh_series,
579 LyXFont::ITALIC_SHAPE, LColor::foreground},
580 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
581 inh_shape, LColor::foreground},
582 {"textnormal", inh_family, inh_series,
583 LyXFont::UP_SHAPE, LColor::foreground},
584 {"textrm", LyXFont::ROMAN_FAMILY,
585 inh_series,LyXFont::UP_SHAPE,LColor::foreground},
586 {"textsc", inh_family, inh_series,
587 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
588 {"textsf", LyXFont::SANS_FAMILY, inh_series,
589 inh_shape, LColor::foreground},
590 {"textsl", inh_family, inh_series,
591 LyXFont::SLANTED_SHAPE, LColor::foreground},
592 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
593 inh_shape, LColor::foreground},
594 {"textup", inh_family, inh_series,
595 LyXFont::UP_SHAPE, LColor::foreground},
598 {"textipa", inh_family, inh_series,
599 inh_shape, LColor::foreground},
601 // LyX internal usage
602 {"lyxtex", inh_family, inh_series,
603 LyXFont::UP_SHAPE, LColor::latex},
604 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
605 LyXFont::UP_SHAPE, LColor::latex},
606 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
607 inh_shape, LColor::math},
608 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
609 inh_shape, LColor::math},
610 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
611 LyXFont::UP_SHAPE, LColor::foreground},
612 {"lyxnochange", inh_family, inh_series,
613 inh_shape, LColor::foreground},
614 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
615 LyXFont::UP_SHAPE, LColor::math},
616 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
617 LyXFont::ITALIC_SHAPE, LColor::math},
618 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
619 LyXFont::ITALIC_SHAPE, LColor::math}
623 fontinfo * lookupFont(string const & name)
625 //lyxerr << "searching font '" << name << "'" << endl;
626 int const n = sizeof(fontinfos) / sizeof(fontinfo);
627 for (int i = 0; i < n; ++i)
628 if (fontinfos[i].cmd_ == name) {
629 //lyxerr << "found '" << i << "'" << endl;
630 return fontinfos + i;
636 fontinfo * searchFont(string const & name)
638 fontinfo * f = lookupFont(name);
639 return f ? f : fontinfos;
640 // this should be mathnormal
641 //return searchFont("mathnormal");
645 bool isFontName(string const & name)
647 return lookupFont(name);
651 LyXFont getFont(string const & name)
654 augmentFont(font, name);
659 void fakeFont(string const & orig, string const & fake)
661 fontinfo * forig = searchFont(orig);
662 fontinfo * ffake = searchFont(fake);
663 if (forig && ffake) {
664 forig->family_ = ffake->family_;
665 forig->series_ = ffake->series_;
666 forig->shape_ = ffake->shape_;
667 forig->color_ = ffake->color_;
669 lyxerr << "Can't fake font '" << orig << "' with '"
670 << fake << "'" << endl;
675 void augmentFont(LyXFont & font, string const & name)
677 static bool initialized = false;
680 // fake fonts if necessary
681 if (!lyx_gui::font_available(getFont("mathfrak")))
682 fakeFont("mathfrak", "lyxfakefrak");
683 if (!lyx_gui::font_available(getFont("mathcal")))
684 fakeFont("mathcal", "lyxfakecal");
686 fontinfo * info = searchFont(name);
687 if (info->family_ != inh_family)
688 font.setFamily(info->family_);
689 if (info->series_ != inh_series)
690 font.setSeries(info->series_);
691 if (info->shape_ != inh_shape)
692 font.setShape(info->shape_);
693 if (info->color_ != LColor::none)
694 font.setColor(info->color_);
698 string asString(MathArray const & ar)
700 std::ostringstream os;
707 void asArray(string const & str, MathArray & ar)
709 mathed_parse_cell(ar, str);
713 string asString(MathInset const & inset)
715 std::ostringstream os;
722 string asString(MathAtom const & at)
724 std::ostringstream os;