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"
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, unsigned char c, Dimension & dim)
370 dim.des = font_metrics::descent(c, font);
371 dim.asc = font_metrics::ascent(c, font);
372 dim.wid = mathed_char_width(font, c);
376 int mathed_char_ascent(LyXFont const & font, unsigned char c)
378 return font_metrics::ascent(c, font);
382 int mathed_char_descent(LyXFont const & font, unsigned char c)
384 return font_metrics::descent(c, font);
388 int mathed_char_width(LyXFont const & font, unsigned char c)
390 return font_metrics::width(c, font);
394 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
399 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
400 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
401 dim.des = max(dim.des, font_metrics::descent(*it, font));
404 dim.asc = font_metrics::maxAscent(font);
405 dim.des = font_metrics::maxDescent(font);
407 docstring ds(s.begin(), s.end());
408 dim.wid = font_metrics::width(ds, font);
412 int mathed_string_width(LyXFont const & font, string const & s)
414 docstring ds(s.begin(), s.end());
415 return font_metrics::width(ds, font);
419 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
423 pi.pain.line(x + w/2, y, x + w/2, y + h,
424 LColor::cursor, Painter::line_onoffdash);
428 deco_struct const * mds = search_deco(name);
430 lyxerr << "Deco was not found. Programming error?" << endl;
431 lyxerr << "name: '" << name << "'" << endl;
435 int const n = (w < h) ? w : h;
436 int const r = mds->angle;
437 double const * d = mds->data;
439 if (h > 70 && (name == "(" || name == ")"))
443 Matrix sqmt(r, n, n);
451 for (int i = 0; d[i]; ) {
452 int code = int(d[i++]);
453 if (code & 1) { // code == 1 || code == 3
459 sqmt.transform(xx, yy);
461 mt.transform(xx, yy);
462 mt.transform(x2, y2);
464 int(x + xx + 0.5), int(y + yy + 0.5),
465 int(x + x2 + 0.5), int(y + y2 + 0.5),
470 int const n = int(d[i++]);
471 for (int j = 0; j < n; ++j) {
474 // lyxerr << ' ' << xx << ' ' << yy << ' ';
476 sqmt.transform(xx, yy);
478 mt.transform(xx, yy);
479 xp[j] = int(x + xx + 0.5);
480 yp[j] = int(y + yy + 0.5);
481 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
483 pi.pain.lines(xp, yp, n, LColor::math);
489 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
491 LyXFont f = pi.base.font;
492 f.setColor(LColor::latex);
493 docstring dstr(str.begin(), str.end());
494 pi.pain.text(x, y, dstr, f);
498 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
500 LyXFont f = pi.base.font;
501 f.setColor(LColor::foreground);
502 docstring dstr(str.begin(), str.end());
503 pi.pain.text(x, y, dstr, f);
507 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
509 asc = font_metrics::maxAscent(font);
510 des = font_metrics::maxDescent(font);
516 LyXFont::FONT_FAMILY family_;
517 LyXFont::FONT_SERIES series_;
518 LyXFont::FONT_SHAPE shape_;
519 LColor::color color_;
523 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
524 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
525 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
528 // mathnormal should be the first, otherwise the fallback further down
530 fontinfo fontinfos[] = {
532 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
533 LyXFont::ITALIC_SHAPE, LColor::math},
534 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
535 inh_shape, LColor::math},
536 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
541 LyXFont::UP_SHAPE, LColor::math},
542 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"mathit", inh_family, inh_series,
549 LyXFont::ITALIC_SHAPE, LColor::math},
550 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"cmm", LyXFont::CMM_FAMILY, inh_series,
553 inh_shape, LColor::math},
554 {"cmr", LyXFont::CMR_FAMILY, inh_series,
555 inh_shape, LColor::math},
556 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
557 inh_shape, LColor::math},
558 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
559 inh_shape, LColor::math},
560 {"msa", LyXFont::MSA_FAMILY, inh_series,
561 inh_shape, LColor::math},
562 {"msb", LyXFont::MSB_FAMILY, inh_series,
563 inh_shape, LColor::math},
564 {"wasy", LyXFont::WASY_FAMILY, inh_series,
565 inh_shape, LColor::none},
568 {"text", inh_family, inh_series,
569 inh_shape, LColor::foreground},
570 {"textbf", inh_family, LyXFont::BOLD_SERIES,
571 inh_shape, LColor::foreground},
572 {"textit", inh_family, inh_series,
573 LyXFont::ITALIC_SHAPE, LColor::foreground},
574 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
575 inh_shape, LColor::foreground},
576 {"textnormal", inh_family, inh_series,
577 LyXFont::UP_SHAPE, LColor::foreground},
578 {"textrm", LyXFont::ROMAN_FAMILY,
579 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
580 {"textsc", inh_family, inh_series,
581 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
582 {"textsf", LyXFont::SANS_FAMILY, inh_series,
583 inh_shape, LColor::foreground},
584 {"textsl", inh_family, inh_series,
585 LyXFont::SLANTED_SHAPE, LColor::foreground},
586 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
587 inh_shape, LColor::foreground},
588 {"textup", inh_family, inh_series,
589 LyXFont::UP_SHAPE, LColor::foreground},
592 {"textipa", inh_family, inh_series,
593 inh_shape, LColor::foreground},
595 // LyX internal usage
596 {"lyxtex", inh_family, inh_series,
597 LyXFont::UP_SHAPE, LColor::latex},
598 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
599 inh_shape, LColor::math},
600 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
601 inh_shape, LColor::math},
602 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
603 LyXFont::UP_SHAPE, LColor::foreground},
604 {"lyxnochange", inh_family, inh_series,
605 inh_shape, LColor::foreground},
606 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
607 LyXFont::UP_SHAPE, LColor::math},
608 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
609 LyXFont::ITALIC_SHAPE, LColor::math},
610 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
611 LyXFont::ITALIC_SHAPE, LColor::math}
615 fontinfo * lookupFont(string const & name)
617 //lyxerr << "searching font '" << name << "'" << endl;
618 int const n = sizeof(fontinfos) / sizeof(fontinfo);
619 for (int i = 0; i < n; ++i)
620 if (fontinfos[i].cmd_ == name) {
621 //lyxerr << "found '" << i << "'" << endl;
622 return fontinfos + i;
628 fontinfo * searchFont(string const & name)
630 fontinfo * f = lookupFont(name);
631 return f ? f : fontinfos;
632 // this should be mathnormal
633 //return searchFont("mathnormal");
637 bool isFontName(string const & name)
639 return lookupFont(name);
643 LyXFont getFont(string const & name)
646 augmentFont(font, name);
651 void fakeFont(string const & orig, string const & fake)
653 fontinfo * forig = searchFont(orig);
654 fontinfo * ffake = searchFont(fake);
655 if (forig && ffake) {
656 forig->family_ = ffake->family_;
657 forig->series_ = ffake->series_;
658 forig->shape_ = ffake->shape_;
659 forig->color_ = ffake->color_;
661 lyxerr << "Can't fake font '" << orig << "' with '"
662 << fake << "'" << endl;
667 void augmentFont(LyXFont & font, string const & name)
669 static bool initialized = false;
672 // fake fonts if necessary
673 if (!lyx_gui::font_available(getFont("mathfrak")))
674 fakeFont("mathfrak", "lyxfakefrak");
675 if (!lyx_gui::font_available(getFont("mathcal")))
676 fakeFont("mathcal", "lyxfakecal");
678 fontinfo * info = searchFont(name);
679 if (info->family_ != inh_family)
680 font.setFamily(info->family_);
681 if (info->series_ != inh_series)
682 font.setSeries(info->series_);
683 if (info->shape_ != inh_shape)
684 font.setShape(info->shape_);
685 if (info->color_ != LColor::none)
686 font.setColor(info->color_);
690 string asString(MathArray const & ar)
692 std::ostringstream os;
699 void asArray(string const & str, MathArray & ar)
701 mathed_parse_cell(ar, str);
705 string asString(MathInset const & inset)
707 std::ostringstream os;
714 string asString(MathAtom const & at)
716 std::ostringstream os;