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 "InsetMathFont.h"
17 #include "InsetMathSymbol.h"
19 #include "MathParser.h"
20 #include "MathStream.h"
22 #include "MetricsInfo.h"
24 #include "frontends/FontLoader.h"
25 #include "frontends/FontMetrics.h"
26 #include "frontends/Painter.h"
28 #include "support/debug.h"
29 #include "support/docstream.h"
30 #include "support/lyxlib.h"
39 using frontend::Painter;
46 Matrix(int, double, double);
48 void transform(double &, double &);
55 Matrix::Matrix(int code, double x, double y)
57 double const cs = (code & 1) ? 0 : (1 - code);
58 double const sn = (code & 1) ? (2 - code) : 0;
66 void Matrix::transform(double & x, double & y)
68 double xx = m_[0][0] * x + m_[0][1] * y;
69 double yy = m_[1][0] * x + m_[1][1] * y;
79 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
80 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
84 double const parenthHigh[] = {
86 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
87 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
88 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
89 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
95 double const parenth[] = {
97 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
98 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
99 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
100 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
106 double const brace[] = {
108 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
109 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
110 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
111 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
112 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
113 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
114 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
119 double const mapsto[] = {
121 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
122 1, 0.015, 0.475, 0.945, 0.475,
123 1, 0.015, 0.015, 0.015, 0.985,
128 double const lhook[] = {
130 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
131 1, 0.015, 0.475, 0.7, 0.475,
133 0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
134 0.825, 0.35, 0.7, 0.475,
139 double const rhook[] = {
141 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
142 1, 0.3, 0.475, 0.985, 0.475,
144 0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
145 0.175, 0.35, 0.3, 0.475,
150 double const LRArrow[] = {
152 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
154 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
155 1, 0.2, 0.8, 0.8, 0.8,
156 1, 0.2, 0.2, 0.8, 0.2,
161 double const LArrow[] = {
163 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
164 1, 0.2, 0.8, 0.985, 0.8,
165 1, 0.2, 0.2, 0.985, 0.2,
170 double const lharpoondown[] = {
172 0.015, 0.5, 0.25, 0.985,
173 1, 0.02, 0.475, 0.985, 0.475,
178 double const lharpoonup[] = {
180 0.25, 0.015, 0.015, 0.5,
181 1, 0.02, 0.525, 0.985, 0.525,
186 double const lrharpoons[] = {
188 0.25, 0.015, 0.015, 0.225,
189 1, 0.02, 0.23, 0.985, 0.23,
191 0.75, 0.985, 0.985, 0.775,
192 1, 0.02, 0.7, 0.980, 0.7,
197 double const rlharpoons[] = {
199 0.75, 0.015, 0.985, 0.225,
200 1, 0.02, 0.23, 0.985, 0.23,
202 0.25, 0.985, 0.015, 0.775,
203 1, 0.02, 0.7, 0.980, 0.7,
208 double const arrow[] = {
210 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
211 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
213 3, 0.5000, 0.1500, 0.5000, 0.9500,
218 double const Arrow[] = {
220 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
221 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
223 3, 0.3500, 0.5000, 0.3500, 0.9500,
224 3, 0.6500, 0.5000, 0.6500, 0.9500,
229 double const udarrow[] = {
231 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
233 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
234 1, 0.5, 0.1, 0.5, 0.9,
239 double const Udarrow[] = {
241 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
243 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
244 1, 0.35, 0.2, 0.35, 0.8,
245 1, 0.65, 0.2, 0.65, 0.8,
250 double const brack[] = {
252 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
257 double const dbrack[] = {
259 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
261 0.50, 0.05, 0.50, 0.95,
266 double const corner[] = {
268 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
273 double const angle[] = {
275 1, 0, 0.05, 0.5, 1, 1,
280 double const slash[] = {
281 1, 0.95, 0.05, 0.05, 0.95,
286 double const hline[] = {
287 1, 0.00, 0.5, 1.0, 0.5,
292 double const ddot[] = {
293 1, 0.2, 0.5, 0.3, 0.5,
294 1, 0.7, 0.5, 0.8, 0.5,
299 double const dddot[] = {
300 1, 0.1, 0.5, 0.2, 0.5,
301 1, 0.45, 0.5, 0.55, 0.5,
302 1, 0.8, 0.5, 0.9, 0.5,
307 double const ddddot[] = {
308 1, 0.1, 0.5, 0.2, 0.5,
309 1, 0.45, 0.5, 0.55, 0.5,
310 1, 0.8, 0.5, 0.9, 0.5,
311 1, 1.15, 0.5, 1.25, 0.5,
316 double const hline3[] = {
318 1, 0.475, 0, 0.525, 0,
324 double const dline3[] = {
325 1, 0.1, 0.1, 0.15, 0.15,
326 1, 0.475, 0.475, 0.525, 0.525,
327 1, 0.85, 0.85, 0.9, 0.9,
332 double const hlinesmall[] = {
333 1, 0.4, 0.5, 0.6, 0.5,
338 double const ring[] = {
340 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
345 double const vert[] = {
346 1, 0.5, 0.05, 0.5, 0.95,
351 double const Vert[] = {
352 1, 0.3, 0.05, 0.3, 0.95,
353 1, 0.7, 0.05, 0.7, 0.95,
358 double const tilde[] = {
360 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
370 struct named_deco_struct {
376 named_deco_struct deco_table[] = {
378 {"widehat", angle, 3 },
379 {"widetilde", tilde, 0 },
380 {"underbar", hline, 0 },
381 {"underline", hline, 0 },
382 {"overline", hline, 0 },
383 {"underbrace", brace, 1 },
384 {"overbrace", brace, 3 },
385 {"overleftarrow", arrow, 1 },
386 {"overrightarrow", arrow, 3 },
387 {"overleftrightarrow", udarrow, 1 },
388 {"xhookleftarrow", lhook, 0 },
389 {"xhookrightarrow", rhook, 0 },
390 {"xleftarrow", arrow, 1 },
391 {"xLeftarrow", LArrow, 0 },
392 {"xleftharpoondown", lharpoondown, 0 },
393 {"xleftharpoonup", lharpoonup, 0 },
394 {"xleftrightharpoons", lrharpoons, 0 },
395 {"xleftrightarrow", udarrow, 1 },
396 {"xLeftrightarrow", LRArrow, 0 },
397 {"xmapsto", mapsto, 0 },
398 {"xrightarrow", arrow, 3 },
399 {"xRightarrow", LArrow, 2 },
400 {"xrightharpoondown", lharpoonup, 2 },
401 {"xrightharpoonup", lharpoondown, 2 },
402 {"xrightleftharpoons", rlharpoons, 0 },
403 {"underleftarrow", arrow, 1 },
404 {"underrightarrow", arrow, 3 },
405 {"underleftrightarrow", udarrow, 1 },
406 {"undertilde", tilde, 0 },
407 {"utilde", tilde, 0 },
414 {"lbrace", brace, 0 },
415 {"rbrace", brace, 2 },
418 {"llbracket", dbrack, 0 },
419 {"rrbracket", dbrack, 2 },
422 {"slash", slash, 0 },
433 {"backslash", slash, 1 },
434 {"langle", angle, 0 },
435 {"lceil", corner, 0 },
436 {"lfloor", corner, 1 },
437 {"rangle", angle, 2 },
438 {"rceil", corner, 3 },
439 {"rfloor", corner, 2 },
440 {"downarrow", arrow, 2 },
441 {"Downarrow", Arrow, 2 },
442 {"uparrow", arrow, 0 },
443 {"Uparrow", Arrow, 0 },
444 {"updownarrow", udarrow, 0 },
445 {"Updownarrow", Udarrow, 0 },
449 {"dddot", dddot, 0 },
450 {"ddddot", ddddot, 0 },
452 {"grave", slash, 1 },
453 {"acute", slash, 0 },
454 {"tilde", tilde, 0 },
456 {"dot", hlinesmall, 0 },
457 {"check", angle, 1 },
458 {"breve", parenth, 1 },
460 {"mathring", ring, 0 },
463 {"dots", hline3, 0 },
464 {"ldots", hline3, 0 },
465 {"cdots", hline3, 0 },
466 {"vdots", hline3, 1 },
467 {"ddots", dline3, 0 },
468 {"adots", dline3, 1 },
469 {"iddots", dline3, 1 },
470 {"dotsb", hline3, 0 },
471 {"dotsc", hline3, 0 },
472 {"dotsi", hline3, 0 },
473 {"dotsm", hline3, 0 },
474 {"dotso", hline3, 0 }
478 map<docstring, deco_struct> deco_list;
480 // sort the table on startup
481 class init_deco_table {
484 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
485 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
489 deco_list[from_ascii(p->name)] = d;
494 static init_deco_table dummy;
497 deco_struct const * search_deco(docstring const & name)
499 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
500 return p == deco_list.end() ? 0 : &(p->second);
507 int mathed_font_em(FontInfo const & font)
509 return theFontMetrics(font).em();
512 /* The math units. Quoting TeX by Topic, p.205:
514 * Spacing around mathematical objects is measured in mu units. A mu
515 * is 1/18th part of \fontdimen6 of the font in family 2 in the
516 * current style, the ‘quad’ value of the symbol font.
518 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
519 * inserted around (binary) relations, except where these are preceded
520 * or followed by other relations or punctuation, and except if they
521 * follow an open, or precede a close symbol.
523 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
524 * is put around binary operators.
526 * A \thinmuskip (default value in plain TeX: 3mu) follows after
527 * punctuation, and is put around inner objects, except where these
528 * are followed by a close or preceded by an open symbol, and except
529 * if the other object is a large operator or a binary relation.
532 int mathed_thinmuskip(FontInfo font)
534 font.setFamily(SYMBOL_FAMILY);
535 return support::iround(3.0 / 18 * theFontMetrics(font).em());
539 int mathed_medmuskip(FontInfo font)
541 font.setFamily(SYMBOL_FAMILY);
542 return support::iround(4.0 / 18 * theFontMetrics(font).em());
546 int mathed_thickmuskip(FontInfo font)
548 font.setFamily(SYMBOL_FAMILY);
549 return support::iround(5.0 / 18 * theFontMetrics(font).em());
553 int mathed_char_width(FontInfo const & font, char_type c)
555 return theFontMetrics(font).width(c);
559 int mathed_char_kerning(FontInfo const & font, char_type c)
561 frontend::FontMetrics const & fm = theFontMetrics(font);
562 return fm.rbearing(c) - fm.width(c);
566 void mathed_string_dim(FontInfo const & font,
570 frontend::FontMetrics const & fm = theFontMetrics(font);
573 for (docstring::const_iterator it = s.begin();
576 dim.asc = max(dim.asc, fm.ascent(*it));
577 dim.des = max(dim.des, fm.descent(*it));
579 dim.wid = fm.width(s);
583 int mathed_string_width(FontInfo const & font, docstring const & s)
585 return theFontMetrics(font).width(s);
589 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
590 docstring const & name)
593 pi.pain.line(x + w/2, y, x + w/2, y + h,
594 Color_cursor, Painter::line_onoffdash);
598 deco_struct const * mds = search_deco(name);
600 lyxerr << "Deco was not found. Programming error?" << endl;
601 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
605 int const n = (w < h) ? w : h;
606 int const r = mds->angle;
607 double const * d = mds->data;
609 if (h > 70 && (name == "(" || name == ")"))
613 Matrix sqmt(r, n, n);
621 for (int i = 0; d[i]; ) {
622 int code = int(d[i++]);
623 if (code & 1) { // code == 1 || code == 3
629 sqmt.transform(xx, yy);
631 mt.transform(xx, yy);
632 mt.transform(x2, y2);
634 int(x + xx + 0.5), int(y + yy + 0.5),
635 int(x + x2 + 0.5), int(y + y2 + 0.5),
636 pi.base.font.color());
640 int const n = int(d[i++]);
641 for (int j = 0; j < n; ++j) {
644 // lyxerr << ' ' << xx << ' ' << yy << ' ';
646 sqmt.transform(xx, yy);
648 mt.transform(xx, yy);
649 xp[j] = int(x + xx + 0.5);
650 yp[j] = int(y + yy + 0.5);
651 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
653 pi.pain.lines(xp, yp, n, pi.base.font.color());
659 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
661 FontInfo font = mi.base.font;
662 augmentFont(font, "mathnormal");
663 mathed_string_dim(font, str, dim);
667 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
669 FontInfo f = pi.base.font;
670 augmentFont(f, "mathnormal");
671 f.setColor(Color_latex);
672 pi.pain.text(x, y, str, f);
676 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
678 FontInfo f = pi.base.font;
679 augmentFont(f, "mathnormal");
680 f.setColor(Color_foreground);
681 pi.pain.text(x, y, str, f);
685 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
687 frontend::FontMetrics const & fm = theFontMetrics(font);
688 asc = fm.maxAscent();
689 des = fm.maxDescent();
702 FontFamily const inh_family = INHERIT_FAMILY;
703 FontSeries const inh_series = INHERIT_SERIES;
704 FontShape const inh_shape = INHERIT_SHAPE;
707 // mathnormal should be the first, otherwise the fallback further down
709 fontinfo fontinfos[] = {
711 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
712 ITALIC_SHAPE, Color_math},
713 {"mathbf", inh_family, BOLD_SERIES,
714 inh_shape, Color_math},
715 {"mathcal", CMSY_FAMILY, inh_series,
716 inh_shape, Color_math},
717 {"mathfrak", EUFRAK_FAMILY, inh_series,
718 inh_shape, Color_math},
719 {"mathrm", ROMAN_FAMILY, inh_series,
720 UP_SHAPE, Color_math},
721 {"mathsf", SANS_FAMILY, inh_series,
722 inh_shape, Color_math},
723 {"mathbb", MSB_FAMILY, inh_series,
724 inh_shape, Color_math},
725 {"mathtt", TYPEWRITER_FAMILY, inh_series,
726 inh_shape, Color_math},
727 {"mathit", inh_family, inh_series,
728 ITALIC_SHAPE, Color_math},
729 {"mathscr", RSFS_FAMILY, inh_series,
730 inh_shape, Color_math},
731 {"cmex", CMEX_FAMILY, inh_series,
732 inh_shape, Color_math},
733 {"cmm", CMM_FAMILY, inh_series,
734 inh_shape, Color_math},
735 {"cmr", CMR_FAMILY, inh_series,
736 inh_shape, Color_math},
737 {"cmsy", CMSY_FAMILY, inh_series,
738 inh_shape, Color_math},
739 {"eufrak", EUFRAK_FAMILY, inh_series,
740 inh_shape, Color_math},
741 {"msa", MSA_FAMILY, inh_series,
742 inh_shape, Color_math},
743 {"msb", MSB_FAMILY, inh_series,
744 inh_shape, Color_math},
745 {"stmry", STMARY_FAMILY, inh_series,
746 inh_shape, Color_math},
747 {"wasy", WASY_FAMILY, inh_series,
748 inh_shape, Color_math},
749 {"esint", ESINT_FAMILY, inh_series,
750 inh_shape, Color_math},
753 {"text", inh_family, inh_series,
754 inh_shape, Color_foreground},
755 {"textbf", inh_family, BOLD_SERIES,
756 inh_shape, Color_foreground},
757 {"textit", inh_family, inh_series,
758 ITALIC_SHAPE, Color_foreground},
759 {"textmd", inh_family, MEDIUM_SERIES,
760 inh_shape, Color_foreground},
761 {"textnormal", inh_family, inh_series,
762 UP_SHAPE, Color_foreground},
763 {"textrm", ROMAN_FAMILY,
764 inh_series, UP_SHAPE,Color_foreground},
765 {"textsc", inh_family, inh_series,
766 SMALLCAPS_SHAPE, Color_foreground},
767 {"textsf", SANS_FAMILY, inh_series,
768 inh_shape, Color_foreground},
769 {"textsl", inh_family, inh_series,
770 SLANTED_SHAPE, Color_foreground},
771 {"texttt", TYPEWRITER_FAMILY, inh_series,
772 inh_shape, Color_foreground},
773 {"textup", inh_family, inh_series,
774 UP_SHAPE, Color_foreground},
777 {"textipa", inh_family, inh_series,
778 inh_shape, Color_foreground},
781 {"ce", inh_family, inh_series,
782 inh_shape, Color_foreground},
783 {"cf", inh_family, inh_series,
784 inh_shape, Color_foreground},
786 // LyX internal usage
787 {"lyxtex", inh_family, inh_series,
788 UP_SHAPE, Color_latex},
789 // FIXME: The following two don't work on OS X, since the Symbol font
790 // uses a different encoding, and is therefore disabled in
791 // FontLoader::available().
792 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
793 inh_shape, Color_math},
794 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
795 inh_shape, Color_math},
796 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
797 UP_SHAPE, Color_foreground},
798 {"lyxnochange", inh_family, inh_series,
799 inh_shape, Color_foreground},
800 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
801 UP_SHAPE, Color_math},
802 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
803 ITALIC_SHAPE, Color_math},
804 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
805 ITALIC_SHAPE, Color_math}
809 fontinfo * lookupFont(string const & name)
811 //lyxerr << "searching font '" << name << "'" << endl;
812 int const n = sizeof(fontinfos) / sizeof(fontinfo);
813 for (int i = 0; i < n; ++i)
814 if (fontinfos[i].cmd_ == name) {
815 //lyxerr << "found '" << i << "'" << endl;
816 return fontinfos + i;
822 fontinfo * searchFont(string const & name)
824 fontinfo * f = lookupFont(name);
825 return f ? f : fontinfos;
826 // this should be mathnormal
827 //return searchFont("mathnormal");
831 bool isFontName(string const & name)
833 return lookupFont(name);
837 bool isMathFont(string const & name)
839 fontinfo * f = lookupFont(name);
840 return f && f->color_ == Color_math;
844 bool isTextFont(string const & name)
846 fontinfo * f = lookupFont(name);
847 return f && f->color_ == Color_foreground;
851 FontInfo getFont(string const & name)
854 augmentFont(font, name);
859 void fakeFont(string const & orig, string const & fake)
861 fontinfo * forig = searchFont(orig);
862 fontinfo * ffake = searchFont(fake);
863 if (forig && ffake) {
864 forig->family_ = ffake->family_;
865 forig->series_ = ffake->series_;
866 forig->shape_ = ffake->shape_;
867 forig->color_ = ffake->color_;
869 lyxerr << "Can't fake font '" << orig << "' with '"
870 << fake << "'" << endl;
875 void augmentFont(FontInfo & font, string const & name)
877 static bool initialized = false;
880 // fake fonts if necessary
881 if (!theFontLoader().available(getFont("mathfrak")))
882 fakeFont("mathfrak", "lyxfakefrak");
883 if (!theFontLoader().available(getFont("mathcal")))
884 fakeFont("mathcal", "lyxfakecal");
886 fontinfo * info = searchFont(name);
887 if (info->family_ != inh_family)
888 font.setFamily(info->family_);
889 if (info->series_ != inh_series)
890 font.setSeries(info->series_);
891 if (info->shape_ != inh_shape)
892 font.setShape(info->shape_);
893 if (info->color_ != Color_none)
894 font.setColor(info->color_);
898 bool isAlphaSymbol(MathAtom const & at)
900 if (at->asCharInset() ||
901 (at->asSymbolInset() &&
902 at->asSymbolInset()->isOrdAlpha()))
905 if (at->asFontInset()) {
906 MathData const & ar = at->asFontInset()->cell(0);
907 for (size_t i = 0; i < ar.size(); ++i) {
908 if (!(ar[i]->asCharInset() ||
909 (ar[i]->asSymbolInset() &&
910 ar[i]->asSymbolInset()->isOrdAlpha())))
919 docstring asString(MathData const & ar)
922 otexrowstream ots(os, false);
929 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
931 bool quiet = pf & Parse::QUIET;
932 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
933 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
937 docstring asString(InsetMath const & inset)
940 otexrowstream ots(os, false);
947 docstring asString(MathAtom const & at)
950 otexrowstream ots(os, false);