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"
18 #include "MathParser.h"
19 #include "MathStream.h"
21 #include "frontends/FontLoader.h"
22 #include "frontends/FontMetrics.h"
23 #include "frontends/Painter.h"
25 #include "support/debug.h"
26 #include "support/docstream.h"
35 using 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 },
294 {"slash", slash, 0 },
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 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 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(FontInfo const & font, char_type c)
372 return theFontMetrics(font).width(c);
376 int mathed_char_kerning(FontInfo 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(FontInfo 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(FontInfo 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 Color_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, Color_math);
476 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
478 FontInfo f = pi.base.font;
479 f.setColor(Color_latex);
480 pi.pain.text(x, y, str, f);
484 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
486 FontInfo f = pi.base.font;
487 f.setColor(Color_foreground);
488 pi.pain.text(x, y, str, f);
492 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
494 frontend::FontMetrics const & fm = theFontMetrics(font);
495 asc = fm.maxAscent();
496 des = fm.maxDescent();
509 FontFamily const inh_family = INHERIT_FAMILY;
510 FontSeries const inh_series = INHERIT_SERIES;
511 FontShape const inh_shape = INHERIT_SHAPE;
514 // mathnormal should be the first, otherwise the fallback further down
516 fontinfo fontinfos[] = {
518 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
519 ITALIC_SHAPE, Color_math},
520 {"mathbf", inh_family, BOLD_SERIES,
521 inh_shape, Color_math},
522 {"mathcal", CMSY_FAMILY, inh_series,
523 inh_shape, Color_math},
524 {"mathfrak", EUFRAK_FAMILY, inh_series,
525 inh_shape, Color_math},
526 {"mathrm", ROMAN_FAMILY, inh_series,
527 UP_SHAPE, Color_math},
528 {"mathsf", SANS_FAMILY, inh_series,
529 inh_shape, Color_math},
530 {"mathbb", MSB_FAMILY, inh_series,
531 inh_shape, Color_math},
532 {"mathtt", TYPEWRITER_FAMILY, inh_series,
533 inh_shape, Color_math},
534 {"mathit", inh_family, inh_series,
535 ITALIC_SHAPE, Color_math},
536 {"cmex", CMEX_FAMILY, inh_series,
537 inh_shape, Color_math},
538 {"cmm", CMM_FAMILY, inh_series,
539 inh_shape, Color_math},
540 {"cmr", CMR_FAMILY, inh_series,
541 inh_shape, Color_math},
542 {"cmsy", CMSY_FAMILY, inh_series,
543 inh_shape, Color_math},
544 {"eufrak", EUFRAK_FAMILY, inh_series,
545 inh_shape, Color_math},
546 {"msa", MSA_FAMILY, inh_series,
547 inh_shape, Color_math},
548 {"msb", MSB_FAMILY, inh_series,
549 inh_shape, Color_math},
550 {"wasy", WASY_FAMILY, inh_series,
551 inh_shape, Color_math},
552 {"esint", ESINT_FAMILY, inh_series,
553 inh_shape, Color_math},
556 {"text", inh_family, inh_series,
557 inh_shape, Color_foreground},
558 {"textbf", inh_family, BOLD_SERIES,
559 inh_shape, Color_foreground},
560 {"textit", inh_family, inh_series,
561 ITALIC_SHAPE, Color_foreground},
562 {"textmd", inh_family, MEDIUM_SERIES,
563 inh_shape, Color_foreground},
564 {"textnormal", inh_family, inh_series,
565 UP_SHAPE, Color_foreground},
566 {"textrm", ROMAN_FAMILY,
567 inh_series, UP_SHAPE,Color_foreground},
568 {"textsc", inh_family, inh_series,
569 SMALLCAPS_SHAPE, Color_foreground},
570 {"textsf", SANS_FAMILY, inh_series,
571 inh_shape, Color_foreground},
572 {"textsl", inh_family, inh_series,
573 SLANTED_SHAPE, Color_foreground},
574 {"texttt", TYPEWRITER_FAMILY, inh_series,
575 inh_shape, Color_foreground},
576 {"textup", inh_family, inh_series,
577 UP_SHAPE, Color_foreground},
580 {"textipa", inh_family, inh_series,
581 inh_shape, Color_foreground},
583 // LyX internal usage
584 {"lyxtex", inh_family, inh_series,
585 UP_SHAPE, Color_latex},
586 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
587 inh_shape, Color_math},
588 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
589 inh_shape, Color_math},
590 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
591 UP_SHAPE, Color_foreground},
592 {"lyxnochange", inh_family, inh_series,
593 inh_shape, Color_foreground},
594 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
595 UP_SHAPE, Color_math},
596 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
597 ITALIC_SHAPE, Color_math},
598 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
599 ITALIC_SHAPE, Color_math}
603 fontinfo * lookupFont(docstring const & name0)
605 //lyxerr << "searching font '" << name << "'" << endl;
606 int const n = sizeof(fontinfos) / sizeof(fontinfo);
607 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 FontInfo 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(FontInfo & 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_ != Color_none)
675 font.setColor(info->color_);
679 docstring asString(MathData const & ar)
688 void asArray(docstring const & str, MathData & ar)
690 mathed_parse_cell(ar, str);
694 docstring asString(InsetMath const & inset)
703 docstring asString(MathAtom const & at)