2 * \file MathSupport.cpp
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 },
296 {"slash", slash, 0 },
301 {"backslash", slash, 1 },
302 {"langle", angle, 0 },
303 {"lceil", corner, 0 },
304 {"lfloor", corner, 1 },
305 {"rangle", angle, 2 },
306 {"rceil", corner, 3 },
307 {"rfloor", corner, 2 },
308 {"downarrow", arrow, 2 },
309 {"Downarrow", Arrow, 2 },
310 {"uparrow", arrow, 0 },
311 {"Uparrow", Arrow, 0 },
312 {"updownarrow", udarrow, 0 },
313 {"Updownarrow", Udarrow, 0 },
317 {"dddot", dddot, 0 },
319 {"grave", slash, 1 },
320 {"acute", slash, 0 },
321 {"tilde", tilde, 0 },
323 {"dot", hlinesmall, 0 },
324 {"check", angle, 1 },
325 {"breve", parenth, 1 },
327 {"mathring", ring, 0 },
330 {"dots", hline3, 0 },
331 {"ldots", hline3, 0 },
332 {"cdots", hline3, 0 },
333 {"vdots", hline3, 1 },
334 {"ddots", dline3, 0 },
335 {"dotsb", hline3, 0 },
336 {"dotsc", hline3, 0 },
337 {"dotsi", hline3, 0 },
338 {"dotsm", hline3, 0 },
339 {"dotso", hline3, 0 }
343 std::map<docstring, deco_struct> deco_list;
345 // sort the table on startup
346 class init_deco_table {
349 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
350 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
354 deco_list[from_ascii(p->name)] = d;
359 static init_deco_table dummy;
362 deco_struct const * search_deco(docstring const & name)
364 std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
365 return p == deco_list.end() ? 0 : &(p->second);
372 int mathed_char_width(Font const & font, char_type c)
374 return theFontMetrics(font).width(c);
378 int mathed_char_kerning(Font const & font, char_type c)
380 frontend::FontMetrics const & fm = theFontMetrics(font);
381 return fm.rbearing(c) - fm.width(c);
385 void mathed_string_dim(Font const & font,
389 frontend::FontMetrics const & fm = theFontMetrics(font);
392 for (docstring::const_iterator it = s.begin();
395 dim.asc = max(dim.asc, fm.ascent(*it));
396 dim.des = max(dim.des, fm.descent(*it));
398 dim.wid = fm.width(s);
402 int mathed_string_width(Font const & font, docstring const & s)
404 return theFontMetrics(font).width(s);
408 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
409 docstring const & name)
412 pi.pain.line(x + w/2, y, x + w/2, y + h,
413 Color::cursor, Painter::line_onoffdash);
417 deco_struct const * mds = search_deco(name);
419 lyxerr << "Deco was not found. Programming error?" << endl;
420 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
424 int const n = (w < h) ? w : h;
425 int const r = mds->angle;
426 double const * d = mds->data;
428 if (h > 70 && (name == "(" || name == ")"))
432 Matrix sqmt(r, n, n);
440 for (int i = 0; d[i]; ) {
441 int code = int(d[i++]);
442 if (code & 1) { // code == 1 || code == 3
448 sqmt.transform(xx, yy);
450 mt.transform(xx, yy);
451 mt.transform(x2, y2);
453 int(x + xx + 0.5), int(y + yy + 0.5),
454 int(x + x2 + 0.5), int(y + y2 + 0.5),
459 int const n = int(d[i++]);
460 for (int j = 0; j < n; ++j) {
463 // lyxerr << ' ' << xx << ' ' << yy << ' ';
465 sqmt.transform(xx, yy);
467 mt.transform(xx, yy);
468 xp[j] = int(x + xx + 0.5);
469 yp[j] = int(y + yy + 0.5);
470 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
472 pi.pain.lines(xp, yp, n, Color::math);
478 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
480 Font f = pi.base.font;
481 f.setColor(Color::latex);
482 pi.pain.text(x, y, str, f);
486 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
488 Font f = pi.base.font;
489 f.setColor(Color::foreground);
490 pi.pain.text(x, y, str, f);
494 void math_font_max_dim(Font const & font, int & asc, int & des)
496 frontend::FontMetrics const & fm = theFontMetrics(font);
497 asc = fm.maxAscent();
498 des = fm.maxDescent();
504 Font::FONT_FAMILY family_;
505 Font::FONT_SERIES series_;
506 Font::FONT_SHAPE shape_;
511 Font::FONT_FAMILY const inh_family = Font::INHERIT_FAMILY;
512 Font::FONT_SERIES const inh_series = Font::INHERIT_SERIES;
513 Font::FONT_SHAPE const inh_shape = Font::INHERIT_SHAPE;
516 // mathnormal should be the first, otherwise the fallback further down
518 fontinfo fontinfos[] = {
520 {"mathnormal", Font::ROMAN_FAMILY, Font::MEDIUM_SERIES,
521 Font::ITALIC_SHAPE, Color::math},
522 {"mathbf", inh_family, Font::BOLD_SERIES,
523 inh_shape, Color::math},
524 {"mathcal", Font::CMSY_FAMILY, inh_series,
525 inh_shape, Color::math},
526 {"mathfrak", Font::EUFRAK_FAMILY, inh_series,
527 inh_shape, Color::math},
528 {"mathrm", Font::ROMAN_FAMILY, inh_series,
529 Font::UP_SHAPE, Color::math},
530 {"mathsf", Font::SANS_FAMILY, inh_series,
531 inh_shape, Color::math},
532 {"mathbb", Font::MSB_FAMILY, inh_series,
533 inh_shape, Color::math},
534 {"mathtt", Font::TYPEWRITER_FAMILY, inh_series,
535 inh_shape, Color::math},
536 {"mathit", inh_family, inh_series,
537 Font::ITALIC_SHAPE, Color::math},
538 {"cmex", Font::CMEX_FAMILY, inh_series,
539 inh_shape, Color::math},
540 {"cmm", Font::CMM_FAMILY, inh_series,
541 inh_shape, Color::math},
542 {"cmr", Font::CMR_FAMILY, inh_series,
543 inh_shape, Color::math},
544 {"cmsy", Font::CMSY_FAMILY, inh_series,
545 inh_shape, Color::math},
546 {"eufrak", Font::EUFRAK_FAMILY, inh_series,
547 inh_shape, Color::math},
548 {"msa", Font::MSA_FAMILY, inh_series,
549 inh_shape, Color::math},
550 {"msb", Font::MSB_FAMILY, inh_series,
551 inh_shape, Color::math},
552 {"wasy", Font::WASY_FAMILY, inh_series,
553 inh_shape, Color::none},
554 {"esint", Font::ESINT_FAMILY, inh_series,
555 inh_shape, Color::none},
558 {"text", inh_family, inh_series,
559 inh_shape, Color::foreground},
560 {"textbf", inh_family, Font::BOLD_SERIES,
561 inh_shape, Color::foreground},
562 {"textit", inh_family, inh_series,
563 Font::ITALIC_SHAPE, Color::foreground},
564 {"textmd", inh_family, Font::MEDIUM_SERIES,
565 inh_shape, Color::foreground},
566 {"textnormal", inh_family, inh_series,
567 Font::UP_SHAPE, Color::foreground},
568 {"textrm", Font::ROMAN_FAMILY,
569 inh_series, Font::UP_SHAPE,Color::foreground},
570 {"textsc", inh_family, inh_series,
571 Font::SMALLCAPS_SHAPE, Color::foreground},
572 {"textsf", Font::SANS_FAMILY, inh_series,
573 inh_shape, Color::foreground},
574 {"textsl", inh_family, inh_series,
575 Font::SLANTED_SHAPE, Color::foreground},
576 {"texttt", Font::TYPEWRITER_FAMILY, inh_series,
577 inh_shape, Color::foreground},
578 {"textup", inh_family, inh_series,
579 Font::UP_SHAPE, Color::foreground},
582 {"textipa", inh_family, inh_series,
583 inh_shape, Color::foreground},
585 // LyX internal usage
586 {"lyxtex", inh_family, inh_series,
587 Font::UP_SHAPE, Color::latex},
588 {"lyxsymbol", Font::SYMBOL_FAMILY, inh_series,
589 inh_shape, Color::math},
590 {"lyxboldsymbol", Font::SYMBOL_FAMILY, Font::BOLD_SERIES,
591 inh_shape, Color::math},
592 {"lyxblacktext", Font::ROMAN_FAMILY, Font::MEDIUM_SERIES,
593 Font::UP_SHAPE, Color::foreground},
594 {"lyxnochange", inh_family, inh_series,
595 inh_shape, Color::foreground},
596 {"lyxfakebb", Font::TYPEWRITER_FAMILY, Font::BOLD_SERIES,
597 Font::UP_SHAPE, Color::math},
598 {"lyxfakecal", Font::SANS_FAMILY, Font::MEDIUM_SERIES,
599 Font::ITALIC_SHAPE, Color::math},
600 {"lyxfakefrak", Font::ROMAN_FAMILY, Font::BOLD_SERIES,
601 Font::ITALIC_SHAPE, Color::math}
605 fontinfo * lookupFont(docstring const & name0)
607 //lyxerr << "searching font '" << name << "'" << endl;
608 int const n = sizeof(fontinfos) / sizeof(fontinfo);
609 std::string name = to_utf8(name0);
610 for (int i = 0; i < n; ++i)
611 if (fontinfos[i].cmd_ == name) {
612 //lyxerr << "found '" << i << "'" << endl;
613 return fontinfos + i;
619 fontinfo * searchFont(docstring const & name)
621 fontinfo * f = lookupFont(name);
622 return f ? f : fontinfos;
623 // this should be mathnormal
624 //return searchFont("mathnormal");
628 bool isFontName(docstring const & name)
630 return lookupFont(name);
634 Font getFont(docstring const & name)
637 augmentFont(font, name);
642 void fakeFont(docstring const & orig, docstring const & fake)
644 fontinfo * forig = searchFont(orig);
645 fontinfo * ffake = searchFont(fake);
646 if (forig && ffake) {
647 forig->family_ = ffake->family_;
648 forig->series_ = ffake->series_;
649 forig->shape_ = ffake->shape_;
650 forig->color_ = ffake->color_;
652 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
653 << to_utf8(fake) << "'" << endl;
658 void augmentFont(Font & font, docstring const & name)
660 static bool initialized = false;
663 // fake fonts if necessary
664 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
665 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
666 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
667 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
669 fontinfo * info = searchFont(name);
670 if (info->family_ != inh_family)
671 font.setFamily(info->family_);
672 if (info->series_ != inh_series)
673 font.setSeries(info->series_);
674 if (info->shape_ != inh_shape)
675 font.setShape(info->shape_);
676 if (info->color_ != Color::none)
677 font.setColor(info->color_);
681 docstring asString(MathData const & ar)
690 void asArray(docstring const & str, MathData & ar)
692 mathed_parse_cell(ar, str);
696 docstring asString(InsetMath const & inset)
705 docstring asString(MathAtom const & at)