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"
40 Matrix(int, double, double);
42 void transform(double &, double &);
49 Matrix::Matrix(int code, double x, double y)
51 double const cs = (code & 1) ? 0 : (1 - code);
52 double const sn = (code & 1) ? (2 - code) : 0;
60 void Matrix::transform(double & x, double & y)
62 double xx = m_[0][0] * x + m_[0][1] * y;
63 double yy = m_[1][0] * x + m_[1][1] * y;
73 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
74 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
78 double const parenthHigh[] = {
80 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
81 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
82 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
83 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
89 double const parenth[] = {
91 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
92 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
93 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
94 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
100 double const brace[] = {
102 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
103 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
104 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
105 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
106 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
107 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
108 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
113 double const arrow[] = {
115 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
116 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
118 3, 0.5000, 0.1500, 0.5000, 0.9500,
123 double const Arrow[] = {
125 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
126 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
128 3, 0.3500, 0.5000, 0.3500, 0.9500,
129 3, 0.6500, 0.5000, 0.6500, 0.9500,
134 double const udarrow[] = {
136 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
138 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
139 1, 0.5, 0.2, 0.5, 0.8,
144 double const Udarrow[] = {
146 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
148 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
149 1, 0.35, 0.2, 0.35, 0.8,
150 1, 0.65, 0.2, 0.65, 0.8,
155 double const brack[] = {
157 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
162 double const corner[] = {
164 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
169 double const angle[] = {
171 1, 0, 0.05, 0.5, 1, 1,
176 double const slash[] = {
177 1, 0.95, 0.05, 0.05, 0.95,
182 double const hline[] = {
183 1, 0.00, 0.5, 1.0, 0.5,
188 double const ddot[] = {
189 1, 0.2, 0.5, 0.3, 0.5,
190 1, 0.7, 0.5, 0.8, 0.5,
195 double const dddot[] = {
196 1, 0.1, 0.5, 0.2, 0.5,
197 1, 0.45, 0.5, 0.55, 0.5,
198 1, 0.8, 0.5, 0.9, 0.5,
203 double const hline3[] = {
205 1, 0.475, 0, 0.525, 0,
211 double const dline3[] = {
212 1, 0.1, 0.1, 0.15, 0.15,
213 1, 0.475, 0.475, 0.525, 0.525,
214 1, 0.85, 0.85, 0.9, 0.9,
219 double const hlinesmall[] = {
220 1, 0.4, 0.5, 0.6, 0.5,
225 double const ring[] = {
227 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
232 double const vert[] = {
233 1, 0.5, 0.05, 0.5, 0.95,
238 double const Vert[] = {
239 1, 0.3, 0.05, 0.3, 0.95,
240 1, 0.7, 0.05, 0.7, 0.95,
245 double const tilde[] = {
247 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
257 struct named_deco_struct {
263 named_deco_struct deco_table[] = {
265 {"widehat", angle, 3 },
266 {"widetilde", tilde, 0 },
267 {"underbar", hline, 0 },
268 {"underline", hline, 0 },
269 {"overline", hline, 0 },
270 {"underbrace", brace, 1 },
271 {"overbrace", brace, 3 },
272 {"overleftarrow", arrow, 1 },
273 {"overrightarrow", arrow, 3 },
274 {"overleftrightarrow", udarrow, 1 },
275 {"xleftarrow", arrow, 1 },
276 {"xrightarrow", arrow, 3 },
277 {"underleftarrow", arrow, 1 },
278 {"underrightarrow", arrow, 3 },
279 {"underleftrightarrow", udarrow, 1 },
293 {"backslash", slash, 1 },
294 {"langle", angle, 0 },
295 {"lceil", corner, 0 },
296 {"lfloor", corner, 1 },
297 {"rangle", angle, 2 },
298 {"rceil", corner, 3 },
299 {"rfloor", corner, 2 },
300 {"downarrow", arrow, 2 },
301 {"Downarrow", Arrow, 2 },
302 {"uparrow", arrow, 0 },
303 {"Uparrow", Arrow, 0 },
304 {"updownarrow", udarrow, 0 },
305 {"Updownarrow", Udarrow, 0 },
309 {"dddot", dddot, 0 },
311 {"grave", slash, 1 },
312 {"acute", slash, 0 },
313 {"tilde", tilde, 0 },
315 {"dot", hlinesmall, 0 },
316 {"check", angle, 1 },
317 {"breve", parenth, 1 },
319 {"mathring", ring, 0 },
322 {"dots", hline3, 0 },
323 {"ldots", hline3, 0 },
324 {"cdots", hline3, 0 },
325 {"vdots", hline3, 1 },
326 {"ddots", dline3, 0 },
327 {"dotsb", hline3, 0 },
328 {"dotsc", hline3, 0 },
329 {"dotsi", hline3, 0 },
330 {"dotsm", hline3, 0 },
331 {"dotso", hline3, 0 }
335 std::map<string, deco_struct> deco_list;
337 // sort the table on startup
338 class 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 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
485 LyXFont f = pi.base.font;
486 f.setColor(LColor::latex);
487 pi.pain.text(x, y, str, f);
491 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
493 LyXFont f = pi.base.font;
494 f.setColor(LColor::foreground);
495 pi.pain.text(x, y, str, f);
499 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
501 asc = font_metrics::maxAscent(font);
502 des = font_metrics::maxDescent(font);
508 LyXFont::FONT_FAMILY family_;
509 LyXFont::FONT_SERIES series_;
510 LyXFont::FONT_SHAPE shape_;
511 LColor::color color_;
515 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
516 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
517 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
520 // mathnormal should be the first, otherwise the fallback further down
522 fontinfo fontinfos[] = {
524 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
525 LyXFont::ITALIC_SHAPE, LColor::math},
526 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
527 inh_shape, LColor::math},
528 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
529 inh_shape, LColor::math},
530 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
531 inh_shape, LColor::math},
532 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
533 LyXFont::UP_SHAPE, LColor::math},
534 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
535 inh_shape, LColor::math},
536 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"mathit", inh_family, inh_series,
541 LyXFont::ITALIC_SHAPE, LColor::math},
542 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"cmm", LyXFont::CMM_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"cmr", LyXFont::CMR_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
549 inh_shape, LColor::math},
550 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"msa", LyXFont::MSA_FAMILY, inh_series,
553 inh_shape, LColor::math},
554 {"msb", LyXFont::MSB_FAMILY, inh_series,
555 inh_shape, LColor::math},
556 {"wasy", LyXFont::WASY_FAMILY, inh_series,
557 inh_shape, LColor::none},
560 {"text", inh_family, inh_series,
561 inh_shape, LColor::foreground},
562 {"textbf", inh_family, LyXFont::BOLD_SERIES,
563 inh_shape, LColor::foreground},
564 {"textit", inh_family, inh_series,
565 LyXFont::ITALIC_SHAPE, LColor::foreground},
566 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
567 inh_shape, LColor::foreground},
568 {"textnormal", inh_family, inh_series,
569 LyXFont::UP_SHAPE, LColor::foreground},
570 {"textrm", LyXFont::ROMAN_FAMILY,
571 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
572 {"textsc", inh_family, inh_series,
573 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
574 {"textsf", LyXFont::SANS_FAMILY, inh_series,
575 inh_shape, LColor::foreground},
576 {"textsl", inh_family, inh_series,
577 LyXFont::SLANTED_SHAPE, LColor::foreground},
578 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
579 inh_shape, LColor::foreground},
580 {"textup", inh_family, inh_series,
581 LyXFont::UP_SHAPE, LColor::foreground},
584 {"textipa", inh_family, inh_series,
585 inh_shape, LColor::foreground},
587 // LyX internal usage
588 {"lyxtex", inh_family, inh_series,
589 LyXFont::UP_SHAPE, LColor::latex},
590 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
591 inh_shape, LColor::math},
592 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
593 inh_shape, LColor::math},
594 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
595 LyXFont::UP_SHAPE, LColor::foreground},
596 {"lyxnochange", inh_family, inh_series,
597 inh_shape, LColor::foreground},
598 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
599 LyXFont::UP_SHAPE, LColor::math},
600 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
601 LyXFont::ITALIC_SHAPE, LColor::math},
602 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
603 LyXFont::ITALIC_SHAPE, LColor::math}
607 fontinfo * lookupFont(string const & name)
609 //lyxerr << "searching font '" << name << "'" << endl;
610 int const n = sizeof(fontinfos) / sizeof(fontinfo);
611 for (int i = 0; i < n; ++i)
612 if (fontinfos[i].cmd_ == name) {
613 //lyxerr << "found '" << i << "'" << endl;
614 return fontinfos + i;
620 fontinfo * searchFont(string const & name)
622 fontinfo * f = lookupFont(name);
623 return f ? f : fontinfos;
624 // this should be mathnormal
625 //return searchFont("mathnormal");
629 bool isFontName(string const & name)
631 return lookupFont(name);
635 LyXFont getFont(string const & name)
638 augmentFont(font, name);
643 void fakeFont(string const & orig, string const & fake)
645 fontinfo * forig = searchFont(orig);
646 fontinfo * ffake = searchFont(fake);
647 if (forig && ffake) {
648 forig->family_ = ffake->family_;
649 forig->series_ = ffake->series_;
650 forig->shape_ = ffake->shape_;
651 forig->color_ = ffake->color_;
653 lyxerr << "Can't fake font '" << orig << "' with '"
654 << fake << "'" << endl;
659 void augmentFont(LyXFont & font, string const & name)
661 static bool initialized = false;
664 // fake fonts if necessary
665 if (!lyx_gui::font_available(getFont("mathfrak")))
666 fakeFont("mathfrak", "lyxfakefrak");
667 if (!lyx_gui::font_available(getFont("mathcal")))
668 fakeFont("mathcal", "lyxfakecal");
670 fontinfo * info = searchFont(name);
671 if (info->family_ != inh_family)
672 font.setFamily(info->family_);
673 if (info->series_ != inh_series)
674 font.setSeries(info->series_);
675 if (info->shape_ != inh_shape)
676 font.setShape(info->shape_);
677 if (info->color_ != LColor::none)
678 font.setColor(info->color_);
682 string asString(MathArray const & ar)
684 std::ostringstream os;
691 void asArray(string const & str, MathArray & ar)
693 mathed_parse_cell(ar, str);
697 string asString(MathInset const & inset)
699 std::ostringstream os;
706 string asString(MathAtom const & at)
708 std::ostringstream os;