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 "MathSupport.h"
16 #include "InsetMath.h"
17 #include "MathMLStream.h"
18 #include "MathParser.h"
23 #include "frontends/FontLoader.h"
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
33 using frontend::Painter;
44 Matrix(int, double, double);
46 void transform(double &, double &);
53 Matrix::Matrix(int code, double x, double y)
55 double const cs = (code & 1) ? 0 : (1 - code);
56 double const sn = (code & 1) ? (2 - code) : 0;
64 void Matrix::transform(double & x, double & y)
66 double xx = m_[0][0] * x + m_[0][1] * y;
67 double yy = m_[1][0] * x + m_[1][1] * y;
77 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
78 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
82 double const parenthHigh[] = {
84 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
85 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
86 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
87 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
93 double const parenth[] = {
95 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
96 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
97 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
98 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
104 double const brace[] = {
106 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
107 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
108 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
109 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
110 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
111 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
112 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
117 double const arrow[] = {
119 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
120 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
122 3, 0.5000, 0.1500, 0.5000, 0.9500,
127 double const Arrow[] = {
129 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
130 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
132 3, 0.3500, 0.5000, 0.3500, 0.9500,
133 3, 0.6500, 0.5000, 0.6500, 0.9500,
138 double const udarrow[] = {
140 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
142 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
143 1, 0.5, 0.2, 0.5, 0.8,
148 double const Udarrow[] = {
150 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
152 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
153 1, 0.35, 0.2, 0.35, 0.8,
154 1, 0.65, 0.2, 0.65, 0.8,
159 double const brack[] = {
161 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
166 double const corner[] = {
168 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
173 double const angle[] = {
175 1, 0, 0.05, 0.5, 1, 1,
180 double const slash[] = {
181 1, 0.95, 0.05, 0.05, 0.95,
186 double const hline[] = {
187 1, 0.00, 0.5, 1.0, 0.5,
192 double const ddot[] = {
193 1, 0.2, 0.5, 0.3, 0.5,
194 1, 0.7, 0.5, 0.8, 0.5,
199 double const dddot[] = {
200 1, 0.1, 0.5, 0.2, 0.5,
201 1, 0.45, 0.5, 0.55, 0.5,
202 1, 0.8, 0.5, 0.9, 0.5,
207 double const hline3[] = {
209 1, 0.475, 0, 0.525, 0,
215 double const dline3[] = {
216 1, 0.1, 0.1, 0.15, 0.15,
217 1, 0.475, 0.475, 0.525, 0.525,
218 1, 0.85, 0.85, 0.9, 0.9,
223 double const hlinesmall[] = {
224 1, 0.4, 0.5, 0.6, 0.5,
229 double const ring[] = {
231 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
236 double const vert[] = {
237 1, 0.5, 0.05, 0.5, 0.95,
242 double const Vert[] = {
243 1, 0.3, 0.05, 0.3, 0.95,
244 1, 0.7, 0.05, 0.7, 0.95,
249 double const tilde[] = {
251 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
261 struct named_deco_struct {
267 named_deco_struct deco_table[] = {
269 {"widehat", angle, 3 },
270 {"widetilde", tilde, 0 },
271 {"underbar", hline, 0 },
272 {"underline", hline, 0 },
273 {"overline", hline, 0 },
274 {"underbrace", brace, 1 },
275 {"overbrace", brace, 3 },
276 {"overleftarrow", arrow, 1 },
277 {"overrightarrow", arrow, 3 },
278 {"overleftrightarrow", udarrow, 1 },
279 {"xleftarrow", arrow, 1 },
280 {"xrightarrow", arrow, 3 },
281 {"underleftarrow", arrow, 1 },
282 {"underrightarrow", arrow, 3 },
283 {"underleftrightarrow", udarrow, 1 },
290 {"lbrace", brace, 0 },
291 {"rbrace", brace, 2 },
299 {"backslash", slash, 1 },
300 {"langle", angle, 0 },
301 {"lceil", corner, 0 },
302 {"lfloor", corner, 1 },
303 {"rangle", angle, 2 },
304 {"rceil", corner, 3 },
305 {"rfloor", corner, 2 },
306 {"downarrow", arrow, 2 },
307 {"Downarrow", Arrow, 2 },
308 {"uparrow", arrow, 0 },
309 {"Uparrow", Arrow, 0 },
310 {"updownarrow", udarrow, 0 },
311 {"Updownarrow", Udarrow, 0 },
315 {"dddot", dddot, 0 },
317 {"grave", slash, 1 },
318 {"acute", slash, 0 },
319 {"tilde", tilde, 0 },
321 {"dot", hlinesmall, 0 },
322 {"check", angle, 1 },
323 {"breve", parenth, 1 },
325 {"mathring", ring, 0 },
328 {"dots", hline3, 0 },
329 {"ldots", hline3, 0 },
330 {"cdots", hline3, 0 },
331 {"vdots", hline3, 1 },
332 {"ddots", dline3, 0 },
333 {"dotsb", hline3, 0 },
334 {"dotsc", hline3, 0 },
335 {"dotsi", hline3, 0 },
336 {"dotsm", hline3, 0 },
337 {"dotso", hline3, 0 }
341 std::map<string, deco_struct> deco_list;
343 // sort the table on startup
344 class init_deco_table {
347 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
348 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
352 deco_list[p->name]= d;
357 static init_deco_table dummy;
360 deco_struct const * search_deco(string const & name)
362 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
363 return (p == deco_list.end()) ? 0 : &(p->second);
370 void mathed_char_dim(LyXFont const & font, char_type c, Dimension & dim)
372 frontend::FontMetrics const & fm = theFontMetrics(font);
373 dim.des = fm.descent(c);
374 dim.asc = fm.ascent(c);
375 dim.wid = fm.width(c);
379 int mathed_char_width(LyXFont const & font, char_type c)
381 return theFontMetrics(font).width(c);
385 void mathed_string_dim(LyXFont const & font, docstring const & s, Dimension & dim)
387 frontend::FontMetrics const & fm = theFontMetrics(font);
390 for (docstring::const_iterator it = s.begin(); it != s.end(); ++it) {
391 dim.asc = max(dim.asc, fm.ascent(*it));
392 dim.des = max(dim.des, fm.descent(*it));
394 dim.wid = fm.width(s);
398 int mathed_string_width(LyXFont const & font, docstring const & s)
400 return theFontMetrics(font).width(s);
404 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
408 pi.pain.line(x + w/2, y, x + w/2, y + h,
409 LColor::cursor, Painter::line_onoffdash);
413 deco_struct const * mds = search_deco(name);
415 lyxerr << "Deco was not found. Programming error?" << endl;
416 lyxerr << "name: '" << name << "'" << endl;
420 int const n = (w < h) ? w : h;
421 int const r = mds->angle;
422 double const * d = mds->data;
424 if (h > 70 && (name == "(" || name == ")"))
428 Matrix sqmt(r, n, n);
436 for (int i = 0; d[i]; ) {
437 int code = int(d[i++]);
438 if (code & 1) { // code == 1 || code == 3
444 sqmt.transform(xx, yy);
446 mt.transform(xx, yy);
447 mt.transform(x2, y2);
449 int(x + xx + 0.5), int(y + yy + 0.5),
450 int(x + x2 + 0.5), int(y + y2 + 0.5),
455 int const n = int(d[i++]);
456 for (int j = 0; j < n; ++j) {
459 // lyxerr << ' ' << xx << ' ' << yy << ' ';
461 sqmt.transform(xx, yy);
463 mt.transform(xx, yy);
464 xp[j] = int(x + xx + 0.5);
465 yp[j] = int(y + yy + 0.5);
466 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
468 pi.pain.lines(xp, yp, n, LColor::math);
474 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
476 LyXFont f = pi.base.font;
477 f.setColor(LColor::latex);
478 pi.pain.text(x, y, str, f);
482 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
484 LyXFont f = pi.base.font;
485 f.setColor(LColor::foreground);
486 pi.pain.text(x, y, str, f);
490 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
492 frontend::FontMetrics const & fm = theFontMetrics(font);
493 asc = fm.maxAscent();
494 des = fm.maxDescent();
500 LyXFont::FONT_FAMILY family_;
501 LyXFont::FONT_SERIES series_;
502 LyXFont::FONT_SHAPE shape_;
503 LColor::color color_;
507 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
508 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
509 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
512 // mathnormal should be the first, otherwise the fallback further down
514 fontinfo fontinfos[] = {
516 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
517 LyXFont::ITALIC_SHAPE, LColor::math},
518 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
519 inh_shape, LColor::math},
520 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
521 inh_shape, LColor::math},
522 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
523 inh_shape, LColor::math},
524 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
525 LyXFont::UP_SHAPE, LColor::math},
526 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
527 inh_shape, LColor::math},
528 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
529 inh_shape, LColor::math},
530 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
531 inh_shape, LColor::math},
532 {"mathit", inh_family, inh_series,
533 LyXFont::ITALIC_SHAPE, LColor::math},
534 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
535 inh_shape, LColor::math},
536 {"cmm", LyXFont::CMM_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"cmr", LyXFont::CMR_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"msa", LyXFont::MSA_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"msb", LyXFont::MSB_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"wasy", LyXFont::WASY_FAMILY, inh_series,
549 inh_shape, LColor::none},
552 {"text", inh_family, inh_series,
553 inh_shape, LColor::foreground},
554 {"textbf", inh_family, LyXFont::BOLD_SERIES,
555 inh_shape, LColor::foreground},
556 {"textit", inh_family, inh_series,
557 LyXFont::ITALIC_SHAPE, LColor::foreground},
558 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
559 inh_shape, LColor::foreground},
560 {"textnormal", inh_family, inh_series,
561 LyXFont::UP_SHAPE, LColor::foreground},
562 {"textrm", LyXFont::ROMAN_FAMILY,
563 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
564 {"textsc", inh_family, inh_series,
565 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
566 {"textsf", LyXFont::SANS_FAMILY, inh_series,
567 inh_shape, LColor::foreground},
568 {"textsl", inh_family, inh_series,
569 LyXFont::SLANTED_SHAPE, LColor::foreground},
570 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
571 inh_shape, LColor::foreground},
572 {"textup", inh_family, inh_series,
573 LyXFont::UP_SHAPE, LColor::foreground},
576 {"textipa", inh_family, inh_series,
577 inh_shape, LColor::foreground},
579 // LyX internal usage
580 {"lyxtex", inh_family, inh_series,
581 LyXFont::UP_SHAPE, LColor::latex},
582 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
583 inh_shape, LColor::math},
584 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
585 inh_shape, LColor::math},
586 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
587 LyXFont::UP_SHAPE, LColor::foreground},
588 {"lyxnochange", inh_family, inh_series,
589 inh_shape, LColor::foreground},
590 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
591 LyXFont::UP_SHAPE, LColor::math},
592 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
593 LyXFont::ITALIC_SHAPE, LColor::math},
594 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
595 LyXFont::ITALIC_SHAPE, LColor::math}
599 fontinfo * lookupFont(string const & name)
601 //lyxerr << "searching font '" << name << "'" << endl;
602 int const n = sizeof(fontinfos) / sizeof(fontinfo);
603 for (int i = 0; i < n; ++i)
604 if (fontinfos[i].cmd_ == name) {
605 //lyxerr << "found '" << i << "'" << endl;
606 return fontinfos + i;
612 fontinfo * searchFont(string const & name)
614 fontinfo * f = lookupFont(name);
615 return f ? f : fontinfos;
616 // this should be mathnormal
617 //return searchFont("mathnormal");
621 bool isFontName(string const & name)
623 return lookupFont(name);
627 LyXFont getFont(string const & name)
630 augmentFont(font, name);
635 void fakeFont(string const & orig, string const & fake)
637 fontinfo * forig = searchFont(orig);
638 fontinfo * ffake = searchFont(fake);
639 if (forig && ffake) {
640 forig->family_ = ffake->family_;
641 forig->series_ = ffake->series_;
642 forig->shape_ = ffake->shape_;
643 forig->color_ = ffake->color_;
645 lyxerr << "Can't fake font '" << orig << "' with '"
646 << fake << "'" << endl;
651 void augmentFont(LyXFont & font, string const & name)
653 static bool initialized = false;
656 // fake fonts if necessary
657 if (!theFontLoader().available(getFont("mathfrak")))
658 fakeFont("mathfrak", "lyxfakefrak");
659 if (!theFontLoader().available(getFont("mathcal")))
660 fakeFont("mathcal", "lyxfakecal");
662 fontinfo * info = searchFont(name);
663 if (info->family_ != inh_family)
664 font.setFamily(info->family_);
665 if (info->series_ != inh_series)
666 font.setSeries(info->series_);
667 if (info->shape_ != inh_shape)
668 font.setShape(info->shape_);
669 if (info->color_ != LColor::none)
670 font.setColor(info->color_);
674 string asString(MathArray const & ar)
680 return to_utf8(os.str());
684 void asArray(docstring const & str, MathArray & ar)
686 mathed_parse_cell(ar, to_utf8(str));
690 string asString(InsetMath const & inset)
696 return to_utf8(os.str());
700 string asString(MathAtom const & at)
706 return to_utf8(os.str());