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 "MathStream.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<docstring, 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[from_ascii(p->name)] = d;
357 static init_deco_table dummy;
360 deco_struct const * search_deco(docstring const & name)
362 std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
363 return p == deco_list.end() ? 0 : &(p->second);
370 int mathed_char_width(LyXFont const & font, char_type c)
372 return theFontMetrics(font).width(c);
376 void mathed_string_dim(LyXFont const & font,
380 frontend::FontMetrics const & fm = theFontMetrics(font);
383 for (docstring::const_iterator it = s.begin();
386 dim.asc = max(dim.asc, fm.ascent(*it));
387 dim.des = max(dim.des, fm.descent(*it));
389 dim.wid = fm.width(&s[0], s.size());
393 int mathed_string_width(LyXFont const & font, docstring const & s)
395 return theFontMetrics(font).width(s);
399 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
400 docstring const & name)
403 pi.pain.line(x + w/2, y, x + w/2, y + h,
404 LColor::cursor, Painter::line_onoffdash);
408 deco_struct const * mds = search_deco(name);
410 lyxerr << "Deco was not found. Programming error?" << endl;
411 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
415 int const n = (w < h) ? w : h;
416 int const r = mds->angle;
417 double const * d = mds->data;
419 if (h > 70 && (name == "(" || name == ")"))
423 Matrix sqmt(r, n, n);
431 for (int i = 0; d[i]; ) {
432 int code = int(d[i++]);
433 if (code & 1) { // code == 1 || code == 3
439 sqmt.transform(xx, yy);
441 mt.transform(xx, yy);
442 mt.transform(x2, y2);
444 int(x + xx + 0.5), int(y + yy + 0.5),
445 int(x + x2 + 0.5), int(y + y2 + 0.5),
450 int const n = int(d[i++]);
451 for (int j = 0; j < n; ++j) {
454 // lyxerr << ' ' << xx << ' ' << yy << ' ';
456 sqmt.transform(xx, yy);
458 mt.transform(xx, yy);
459 xp[j] = int(x + xx + 0.5);
460 yp[j] = int(y + yy + 0.5);
461 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
463 pi.pain.lines(xp, yp, n, LColor::math);
469 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
471 LyXFont f = pi.base.font;
472 f.setColor(LColor::latex);
473 pi.pain.text(x, y, str, f);
477 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
479 LyXFont f = pi.base.font;
480 f.setColor(LColor::foreground);
481 pi.pain.text(x, y, str, f);
485 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
487 frontend::FontMetrics const & fm = theFontMetrics(font);
488 asc = fm.maxAscent();
489 des = fm.maxDescent();
495 LyXFont::FONT_FAMILY family_;
496 LyXFont::FONT_SERIES series_;
497 LyXFont::FONT_SHAPE shape_;
498 LColor::color color_;
502 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
503 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
504 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
507 // mathnormal should be the first, otherwise the fallback further down
509 fontinfo fontinfos[] = {
511 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
512 LyXFont::ITALIC_SHAPE, LColor::math},
513 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
514 inh_shape, LColor::math},
515 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
516 inh_shape, LColor::math},
517 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
518 inh_shape, LColor::math},
519 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
520 LyXFont::UP_SHAPE, LColor::math},
521 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
522 inh_shape, LColor::math},
523 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
524 inh_shape, LColor::math},
525 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
526 inh_shape, LColor::math},
527 {"mathit", inh_family, inh_series,
528 LyXFont::ITALIC_SHAPE, LColor::math},
529 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
530 inh_shape, LColor::math},
531 {"cmm", LyXFont::CMM_FAMILY, inh_series,
532 inh_shape, LColor::math},
533 {"cmr", LyXFont::CMR_FAMILY, inh_series,
534 inh_shape, LColor::math},
535 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
536 inh_shape, LColor::math},
537 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
538 inh_shape, LColor::math},
539 {"msa", LyXFont::MSA_FAMILY, inh_series,
540 inh_shape, LColor::math},
541 {"msb", LyXFont::MSB_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"wasy", LyXFont::WASY_FAMILY, inh_series,
544 inh_shape, LColor::none},
545 {"esint", LyXFont::ESINT_FAMILY, inh_series,
546 inh_shape, LColor::none},
549 {"text", inh_family, inh_series,
550 inh_shape, LColor::foreground},
551 {"textbf", inh_family, LyXFont::BOLD_SERIES,
552 inh_shape, LColor::foreground},
553 {"textit", inh_family, inh_series,
554 LyXFont::ITALIC_SHAPE, LColor::foreground},
555 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
556 inh_shape, LColor::foreground},
557 {"textnormal", inh_family, inh_series,
558 LyXFont::UP_SHAPE, LColor::foreground},
559 {"textrm", LyXFont::ROMAN_FAMILY,
560 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
561 {"textsc", inh_family, inh_series,
562 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
563 {"textsf", LyXFont::SANS_FAMILY, inh_series,
564 inh_shape, LColor::foreground},
565 {"textsl", inh_family, inh_series,
566 LyXFont::SLANTED_SHAPE, LColor::foreground},
567 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
568 inh_shape, LColor::foreground},
569 {"textup", inh_family, inh_series,
570 LyXFont::UP_SHAPE, LColor::foreground},
573 {"textipa", inh_family, inh_series,
574 inh_shape, LColor::foreground},
576 // LyX internal usage
577 {"lyxtex", inh_family, inh_series,
578 LyXFont::UP_SHAPE, LColor::latex},
579 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
580 inh_shape, LColor::math},
581 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
582 inh_shape, LColor::math},
583 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
584 LyXFont::UP_SHAPE, LColor::foreground},
585 {"lyxnochange", inh_family, inh_series,
586 inh_shape, LColor::foreground},
587 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
588 LyXFont::UP_SHAPE, LColor::math},
589 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
590 LyXFont::ITALIC_SHAPE, LColor::math},
591 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
592 LyXFont::ITALIC_SHAPE, LColor::math}
596 fontinfo * lookupFont(docstring const & name0)
598 //lyxerr << "searching font '" << name << "'" << endl;
599 int const n = sizeof(fontinfos) / sizeof(fontinfo);
600 std::string name = to_utf8(name0);
601 for (int i = 0; i < n; ++i)
602 if (fontinfos[i].cmd_ == name) {
603 //lyxerr << "found '" << i << "'" << endl;
604 return fontinfos + i;
610 fontinfo * searchFont(docstring const & name)
612 fontinfo * f = lookupFont(name);
613 return f ? f : fontinfos;
614 // this should be mathnormal
615 //return searchFont("mathnormal");
619 bool isFontName(docstring const & name)
621 return lookupFont(name);
625 LyXFont getFont(docstring const & name)
628 augmentFont(font, name);
633 void fakeFont(docstring const & orig, docstring const & fake)
635 fontinfo * forig = searchFont(orig);
636 fontinfo * ffake = searchFont(fake);
637 if (forig && ffake) {
638 forig->family_ = ffake->family_;
639 forig->series_ = ffake->series_;
640 forig->shape_ = ffake->shape_;
641 forig->color_ = ffake->color_;
643 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
644 << to_utf8(fake) << "'" << endl;
649 void augmentFont(LyXFont & font, docstring const & name)
651 static bool initialized = false;
654 // fake fonts if necessary
655 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
656 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
657 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
658 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
660 fontinfo * info = searchFont(name);
661 if (info->family_ != inh_family)
662 font.setFamily(info->family_);
663 if (info->series_ != inh_series)
664 font.setSeries(info->series_);
665 if (info->shape_ != inh_shape)
666 font.setShape(info->shape_);
667 if (info->color_ != LColor::none)
668 font.setColor(info->color_);
672 docstring asString(MathArray const & ar)
681 void asArray(docstring const & str, MathArray & ar)
683 mathed_parse_cell(ar, str);
687 docstring asString(InsetMath const & inset)
696 docstring asString(MathAtom const & at)