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"
16 #include "math_data.h"
17 #include "math_mathmlstream.h"
18 #include "math_parser.h"
22 #include "frontends/Painter.h"
23 #include "frontends/font_metrics.h"
24 #include "frontends/lyx_gui.h"
26 #include "support/std_sstream.h"
38 Matrix(int, double, double);
40 void transform(double &, double &);
47 Matrix::Matrix(int code, double x, double y)
49 double const cs = (code & 1) ? 0 : (1 - code);
50 double const sn = (code & 1) ? (2 - code) : 0;
58 void Matrix::transform(double & x, double & y)
60 double xx = m_[0][0] * x + m_[0][1] * y;
61 double yy = m_[1][0] * x + m_[1][1] * y;
71 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
72 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
76 double const parenthHigh[] = {
78 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
79 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
80 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
81 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
87 double const parenth[] = {
89 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
90 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
91 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
92 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
98 double const brace[] = {
100 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
101 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
102 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
103 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
104 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
105 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
106 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
111 double const arrow[] = {
113 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
114 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
116 3, 0.5000, 0.1500, 0.5000, 0.9500,
121 double const Arrow[] = {
123 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
124 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
126 3, 0.3500, 0.5000, 0.3500, 0.9500,
127 3, 0.6500, 0.5000, 0.6500, 0.9500,
132 double const udarrow[] = {
134 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
136 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
137 1, 0.5, 0.2, 0.5, 0.8,
142 double const Udarrow[] = {
144 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
146 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
147 1, 0.35, 0.2, 0.35, 0.8,
148 1, 0.65, 0.2, 0.65, 0.8,
153 double const brack[] = {
155 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
160 double const corner[] = {
162 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
167 double const angle[] = {
169 1, 0, 0.05, 0.5, 1, 1,
174 double const slash[] = {
175 1, 0.95, 0.05, 0.05, 0.95,
180 double const hline[] = {
181 1, 0.00, 0.5, 1.0, 0.5,
186 double const ddot[] = {
187 1, 0.2, 0.5, 0.3, 0.5,
188 1, 0.7, 0.5, 0.8, 0.5,
193 double const dddot[] = {
194 1, 0.1, 0.5, 0.2, 0.5,
195 1, 0.45, 0.5, 0.55, 0.5,
196 1, 0.8, 0.5, 0.9, 0.5,
201 double const hline3[] = {
203 1, 0.475, 0, 0.525, 0,
209 double const dline3[] = {
210 1, 0.1, 0.1, 0.15, 0.15,
211 1, 0.475, 0.475, 0.525, 0.525,
212 1, 0.85, 0.85, 0.9, 0.9,
217 double const hlinesmall[] = {
218 1, 0.4, 0.5, 0.6, 0.5,
223 double const ring[] = {
225 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
230 double const vert[] = {
231 1, 0.5, 0.05, 0.5, 0.95,
236 double const Vert[] = {
237 1, 0.3, 0.05, 0.3, 0.95,
238 1, 0.7, 0.05, 0.7, 0.95,
243 double const tilde[] = {
245 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
255 struct named_deco_struct {
261 named_deco_struct deco_table[] = {
263 {"widehat", angle, 3 },
264 {"widetilde", tilde, 0 },
265 {"underbar", hline, 0 },
266 {"underline", hline, 0 },
267 {"overline", hline, 0 },
268 {"underbrace", brace, 1 },
269 {"overbrace", brace, 3 },
270 {"overleftarrow", arrow, 1 },
271 {"overrightarrow", arrow, 3 },
272 {"overleftrightarrow", udarrow, 1 },
273 {"xleftarrow", arrow, 1 },
274 {"xrightarrow", arrow, 3 },
275 {"underleftarrow", arrow, 1 },
276 {"underrightarrow", arrow, 3 },
277 {"underleftrightarrow", udarrow, 1 },
291 {"backslash", slash, 1 },
292 {"langle", angle, 0 },
293 {"lceil", corner, 0 },
294 {"lfloor", corner, 1 },
295 {"rangle", angle, 2 },
296 {"rceil", corner, 3 },
297 {"rfloor", corner, 2 },
298 {"downarrow", arrow, 2 },
299 {"Downarrow", Arrow, 2 },
300 {"uparrow", arrow, 0 },
301 {"Uparrow", Arrow, 0 },
302 {"updownarrow", udarrow, 0 },
303 {"Updownarrow", Udarrow, 0 },
307 {"dddot", dddot, 0 },
309 {"grave", slash, 1 },
310 {"acute", slash, 0 },
311 {"tilde", tilde, 0 },
313 {"dot", hlinesmall, 0 },
314 {"check", angle, 1 },
315 {"breve", parenth, 1 },
317 {"mathring", ring, 0 },
320 {"dots", hline3, 0 },
321 {"ldots", hline3, 0 },
322 {"cdots", hline3, 0 },
323 {"vdots", hline3, 1 },
324 {"ddots", dline3, 0 },
325 {"dotsb", hline3, 0 },
326 {"dotsc", hline3, 0 },
327 {"dotsi", hline3, 0 },
328 {"dotsm", hline3, 0 },
329 {"dotso", hline3, 0 }
333 std::map<string, deco_struct> deco_list;
335 // sort the table on startup
336 struct init_deco_table {
338 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
339 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
343 deco_list[p->name]= d;
348 static init_deco_table dummy;
351 deco_struct const * search_deco(string const & name)
353 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
354 return (p == deco_list.end()) ? 0 : &(p->second);
361 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
363 dim.des = font_metrics::descent(c, font);
364 dim.asc = font_metrics::ascent(c, font);
365 dim.wid = mathed_char_width(font, c);
369 int mathed_char_ascent(LyXFont const & font, unsigned char c)
371 return font_metrics::ascent(c, font);
375 int mathed_char_descent(LyXFont const & font, unsigned char c)
377 return font_metrics::descent(c, font);
381 int mathed_char_width(LyXFont const & font, unsigned char c)
383 return font_metrics::width(c, font);
387 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
392 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
393 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
394 dim.des = max(dim.des, font_metrics::descent(*it, font));
397 dim.asc = font_metrics::maxAscent(font);
398 dim.des = font_metrics::maxDescent(font);
400 dim.wid = font_metrics::width(s, font);
404 int mathed_string_width(LyXFont const & font, string const & s)
406 return font_metrics::width(s, font);
410 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
414 pi.pain.line(x + w/2, y, x + w/2, y + h,
415 LColor::cursor, Painter::line_onoffdash);
419 deco_struct const * mds = search_deco(name);
421 lyxerr << "Deco was not found. Programming error?" << endl;
422 lyxerr << "name: '" << name << "'" << endl;
426 int const n = (w < h) ? w : h;
427 int const r = mds->angle;
428 double const * d = mds->data;
430 if (h > 70 && (name == "(" || name == ")"))
434 Matrix sqmt(r, n, n);
442 for (int i = 0; d[i]; ) {
443 int code = int(d[i++]);
444 if (code & 1) { // code == 1 || code == 3
450 sqmt.transform(xx, yy);
452 mt.transform(xx, yy);
453 mt.transform(x2, y2);
455 int(x + xx + 0.5), int(y + yy + 0.5),
456 int(x + x2 + 0.5), int(y + y2 + 0.5),
461 int const n = int(d[i++]);
462 for (int j = 0; j < n; ++j) {
465 // lyxerr << ' ' << xx << ' ' << yy << ' ';
467 sqmt.transform(xx, yy);
469 mt.transform(xx, yy);
470 xp[j] = int(x + xx + 0.5);
471 yp[j] = int(y + yy + 0.5);
472 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
474 pi.pain.lines(xp, yp, n, LColor::math);
480 // In the future maybe we use a better fonts renderer
481 void drawStr(PainterInfo & pi, LyXFont const & font,
482 int x, int y, string const & str)
484 pi.pain.text(x, y, str, font);
488 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
490 LyXFont f = pi.base.font;
491 f.setColor(LColor::latex);
492 pi.pain.text(x, y, str, f);
496 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
498 LyXFont f = pi.base.font;
499 f.setColor(LColor::foreground);
500 pi.pain.text(x, y, str, f);
504 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
506 pi.pain.text(x, y, c, font);
510 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
512 asc = font_metrics::maxAscent(font);
513 des = font_metrics::maxDescent(font);
519 LyXFont::FONT_FAMILY family_;
520 LyXFont::FONT_SERIES series_;
521 LyXFont::FONT_SHAPE shape_;
522 LColor::color color_;
526 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
527 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
528 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
531 // mathnormal should be the first, otherwise the fallback further down
533 fontinfo fontinfos[] = {
535 {"mathnormal", inh_family, LyXFont::MEDIUM_SERIES,
536 LyXFont::UP_SHAPE, LColor::math},
537 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
538 inh_shape, LColor::math},
539 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
540 inh_shape, LColor::math},
541 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
544 inh_shape, LColor::math},
545 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
546 inh_shape, LColor::math},
547 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
550 inh_shape, LColor::math},
551 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
552 inh_shape, LColor::none},
553 {"cmm", LyXFont::CMM_FAMILY, inh_series,
554 inh_shape, LColor::none},
555 {"cmr", LyXFont::CMR_FAMILY, inh_series,
556 inh_shape, LColor::none},
557 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
558 inh_shape, LColor::none},
559 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
560 inh_shape, LColor::none},
561 {"msa", LyXFont::MSA_FAMILY, inh_series,
562 inh_shape, LColor::none},
563 {"msb", LyXFont::MSB_FAMILY, inh_series,
564 inh_shape, LColor::none},
565 {"wasy", LyXFont::WASY_FAMILY, inh_series,
566 inh_shape, LColor::none},
569 {"text", inh_family, inh_series,
570 inh_shape, LColor::foreground},
571 {"textbf", inh_family, LyXFont::BOLD_SERIES,
572 inh_shape, LColor::foreground},
573 {"textit", inh_family, inh_series,
574 LyXFont::ITALIC_SHAPE, LColor::foreground},
575 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
576 inh_shape, LColor::foreground},
577 {"textnormal", inh_family, inh_series,
578 LyXFont::UP_SHAPE, LColor::foreground},
579 {"textrm", LyXFont::ROMAN_FAMILY,
580 inh_series,LyXFont::UP_SHAPE,LColor::foreground},
581 {"textsc", inh_family, inh_series,
582 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
583 {"textsf", LyXFont::SANS_FAMILY, inh_series,
584 inh_shape, LColor::foreground},
585 {"textsl", inh_family, inh_series,
586 LyXFont::SLANTED_SHAPE, LColor::foreground},
587 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
588 inh_shape, LColor::foreground},
589 {"textup", inh_family, inh_series,
590 LyXFont::UP_SHAPE, LColor::foreground},
593 {"textipa", inh_family, inh_series,
594 inh_shape, LColor::foreground},
596 // LyX internal usage
597 {"lyxtex", inh_family, inh_series,
598 inh_shape, LColor::latex},
599 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
600 inh_shape, LColor::latex},
601 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
602 inh_shape, LColor::math},
603 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
604 inh_shape, LColor::math},
605 {"lyxitsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
606 LyXFont::ITALIC_SHAPE, LColor::math},
607 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
608 LyXFont::UP_SHAPE, LColor::foreground},
609 {"lyxnochange", inh_family, inh_series,
610 inh_shape, LColor::foreground},
611 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
612 LyXFont::UP_SHAPE, LColor::math},
613 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
614 LyXFont::ITALIC_SHAPE, LColor::math},
615 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
616 LyXFont::ITALIC_SHAPE, LColor::math}
620 fontinfo * lookupFont(string const & name)
622 //lyxerr << "searching font '" << name << "'" << endl;
623 int const n = sizeof(fontinfos) / sizeof(fontinfo);
624 for (int i = 0; i < n; ++i)
625 if (fontinfos[i].cmd_ == name) {
626 //lyxerr << "found '" << i << "'" << endl;
627 return fontinfos + i;
633 fontinfo * searchFont(string const & name)
635 fontinfo * f = lookupFont(name);
636 return f ? f : fontinfos;
637 // this should be mathnormal
638 //return searchFont("mathnormal");
642 bool isFontName(string const & name)
644 return lookupFont(name);
648 LyXFont getFont(string const & name)
651 augmentFont(font, name);
656 void fakeFont(string const & orig, string const & fake)
658 fontinfo * forig = searchFont(orig);
659 fontinfo * ffake = searchFont(fake);
660 if (forig && ffake) {
661 forig->family_ = ffake->family_;
662 forig->series_ = ffake->series_;
663 forig->shape_ = ffake->shape_;
664 forig->color_ = ffake->color_;
666 lyxerr << "Can't fake font '" << orig << "' with '"
667 << fake << "'" << endl;
672 void augmentFont(LyXFont & font, string const & name)
674 static bool initialized = false;
677 // fake fonts if necessary
678 if (!lyx_gui::font_available(getFont("mathfrak")))
679 fakeFont("mathfrak", "lyxfakefrak");
680 if (!lyx_gui::font_available(getFont("mathcal")))
681 fakeFont("mathcal", "lyxfakecal");
683 fontinfo * info = searchFont(name);
684 if (info->family_ != inh_family)
685 font.setFamily(info->family_);
686 if (info->series_ != inh_series)
687 font.setSeries(info->series_);
688 if (info->shape_ != inh_shape)
689 font.setShape(info->shape_);
690 if (info->color_ != LColor::none)
691 font.setColor(info->color_);
695 string asString(MathArray const & ar)
697 std::ostringstream os;
704 void asArray(string const & str, MathArray & ar)
706 mathed_parse_cell(ar, str);