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 int mathed_char_kerning(LyXFont const & font, char_type c)
378 frontend::FontMetrics const & fm = theFontMetrics(font);
379 return fm.rbearing(c) - fm.width(c);
383 void mathed_string_dim(LyXFont const & font,
387 frontend::FontMetrics const & fm = theFontMetrics(font);
390 for (docstring::const_iterator it = s.begin();
393 dim.asc = max(dim.asc, fm.ascent(*it));
394 dim.des = max(dim.des, fm.descent(*it));
396 dim.wid = fm.width(s);
400 int mathed_string_width(LyXFont const & font, docstring const & s)
402 return theFontMetrics(font).width(s);
406 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
407 docstring const & name)
410 pi.pain.line(x + w/2, y, x + w/2, y + h,
411 LColor::cursor, Painter::line_onoffdash);
415 deco_struct const * mds = search_deco(name);
417 lyxerr << "Deco was not found. Programming error?" << endl;
418 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
422 int const n = (w < h) ? w : h;
423 int const r = mds->angle;
424 double const * d = mds->data;
426 if (h > 70 && (name == "(" || name == ")"))
430 Matrix sqmt(r, n, n);
438 for (int i = 0; d[i]; ) {
439 int code = int(d[i++]);
440 if (code & 1) { // code == 1 || code == 3
446 sqmt.transform(xx, yy);
448 mt.transform(xx, yy);
449 mt.transform(x2, y2);
451 int(x + xx + 0.5), int(y + yy + 0.5),
452 int(x + x2 + 0.5), int(y + y2 + 0.5),
457 int const n = int(d[i++]);
458 for (int j = 0; j < n; ++j) {
461 // lyxerr << ' ' << xx << ' ' << yy << ' ';
463 sqmt.transform(xx, yy);
465 mt.transform(xx, yy);
466 xp[j] = int(x + xx + 0.5);
467 yp[j] = int(y + yy + 0.5);
468 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
470 pi.pain.lines(xp, yp, n, LColor::math);
476 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
478 LyXFont f = pi.base.font;
479 f.setColor(LColor::latex);
480 pi.pain.text(x, y, str, f);
484 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
486 LyXFont f = pi.base.font;
487 f.setColor(LColor::foreground);
488 pi.pain.text(x, y, str, f);
492 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
494 frontend::FontMetrics const & fm = theFontMetrics(font);
495 asc = fm.maxAscent();
496 des = fm.maxDescent();
502 LyXFont::FONT_FAMILY family_;
503 LyXFont::FONT_SERIES series_;
504 LyXFont::FONT_SHAPE shape_;
505 LColor::color color_;
509 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
510 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
511 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
514 // mathnormal should be the first, otherwise the fallback further down
516 fontinfo fontinfos[] = {
518 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
519 LyXFont::ITALIC_SHAPE, LColor::math},
520 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
521 inh_shape, LColor::math},
522 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
523 inh_shape, LColor::math},
524 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
525 inh_shape, LColor::math},
526 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
527 LyXFont::UP_SHAPE, LColor::math},
528 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
529 inh_shape, LColor::math},
530 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
531 inh_shape, LColor::math},
532 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
533 inh_shape, LColor::math},
534 {"mathit", inh_family, inh_series,
535 LyXFont::ITALIC_SHAPE, LColor::math},
536 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"cmm", LyXFont::CMM_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"cmr", LyXFont::CMR_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"msa", LyXFont::MSA_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"msb", LyXFont::MSB_FAMILY, inh_series,
549 inh_shape, LColor::math},
550 {"wasy", LyXFont::WASY_FAMILY, inh_series,
551 inh_shape, LColor::none},
552 {"esint", LyXFont::ESINT_FAMILY, inh_series,
553 inh_shape, LColor::none},
556 {"text", inh_family, inh_series,
557 inh_shape, LColor::foreground},
558 {"textbf", inh_family, LyXFont::BOLD_SERIES,
559 inh_shape, LColor::foreground},
560 {"textit", inh_family, inh_series,
561 LyXFont::ITALIC_SHAPE, LColor::foreground},
562 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
563 inh_shape, LColor::foreground},
564 {"textnormal", inh_family, inh_series,
565 LyXFont::UP_SHAPE, LColor::foreground},
566 {"textrm", LyXFont::ROMAN_FAMILY,
567 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
568 {"textsc", inh_family, inh_series,
569 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
570 {"textsf", LyXFont::SANS_FAMILY, inh_series,
571 inh_shape, LColor::foreground},
572 {"textsl", inh_family, inh_series,
573 LyXFont::SLANTED_SHAPE, LColor::foreground},
574 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
575 inh_shape, LColor::foreground},
576 {"textup", inh_family, inh_series,
577 LyXFont::UP_SHAPE, LColor::foreground},
580 {"textipa", inh_family, inh_series,
581 inh_shape, LColor::foreground},
583 // LyX internal usage
584 {"lyxtex", inh_family, inh_series,
585 LyXFont::UP_SHAPE, LColor::latex},
586 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
587 inh_shape, LColor::math},
588 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
589 inh_shape, LColor::math},
590 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
591 LyXFont::UP_SHAPE, LColor::foreground},
592 {"lyxnochange", inh_family, inh_series,
593 inh_shape, LColor::foreground},
594 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
595 LyXFont::UP_SHAPE, LColor::math},
596 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
597 LyXFont::ITALIC_SHAPE, LColor::math},
598 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
599 LyXFont::ITALIC_SHAPE, LColor::math}
603 fontinfo * lookupFont(docstring const & name0)
605 //lyxerr << "searching font '" << name << "'" << endl;
606 int const n = sizeof(fontinfos) / sizeof(fontinfo);
607 std::string name = to_utf8(name0);
608 for (int i = 0; i < n; ++i)
609 if (fontinfos[i].cmd_ == name) {
610 //lyxerr << "found '" << i << "'" << endl;
611 return fontinfos + i;
617 fontinfo * searchFont(docstring const & name)
619 fontinfo * f = lookupFont(name);
620 return f ? f : fontinfos;
621 // this should be mathnormal
622 //return searchFont("mathnormal");
626 bool isFontName(docstring const & name)
628 return lookupFont(name);
632 LyXFont getFont(docstring const & name)
635 augmentFont(font, name);
640 void fakeFont(docstring const & orig, docstring const & fake)
642 fontinfo * forig = searchFont(orig);
643 fontinfo * ffake = searchFont(fake);
644 if (forig && ffake) {
645 forig->family_ = ffake->family_;
646 forig->series_ = ffake->series_;
647 forig->shape_ = ffake->shape_;
648 forig->color_ = ffake->color_;
650 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
651 << to_utf8(fake) << "'" << endl;
656 void augmentFont(LyXFont & font, docstring const & name)
658 static bool initialized = false;
661 // fake fonts if necessary
662 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
663 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
664 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
665 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
667 fontinfo * info = searchFont(name);
668 if (info->family_ != inh_family)
669 font.setFamily(info->family_);
670 if (info->series_ != inh_series)
671 font.setSeries(info->series_);
672 if (info->shape_ != inh_shape)
673 font.setShape(info->shape_);
674 if (info->color_ != LColor::none)
675 font.setColor(info->color_);
679 docstring asString(MathArray const & ar)
688 void asArray(docstring const & str, MathArray & ar)
690 mathed_parse_cell(ar, str);
694 docstring asString(InsetMath const & inset)
703 docstring asString(MathAtom const & at)