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 "frontends/FontLoader.h"
23 #include "frontends/FontMetrics.h"
24 #include "frontends/Painter.h"
26 #include "support/debug.h"
27 #include "support/docstream.h"
36 using frontend::Painter;
43 Matrix(int, double, double);
45 void transform(double &, double &);
52 Matrix::Matrix(int code, double x, double y)
54 double const cs = (code & 1) ? 0 : (1 - code);
55 double const sn = (code & 1) ? (2 - code) : 0;
63 void Matrix::transform(double & x, double & y)
65 double xx = m_[0][0] * x + m_[0][1] * y;
66 double yy = m_[1][0] * x + m_[1][1] * y;
76 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
81 double const parenthHigh[] = {
83 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
92 double const parenth[] = {
94 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
103 double const brace[] = {
105 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
116 double const arrow[] = {
118 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
121 3, 0.5000, 0.1500, 0.5000, 0.9500,
126 double const Arrow[] = {
128 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
131 3, 0.3500, 0.5000, 0.3500, 0.9500,
132 3, 0.6500, 0.5000, 0.6500, 0.9500,
137 double const udarrow[] = {
139 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
141 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
142 1, 0.5, 0.1, 0.5, 0.9,
147 double const Udarrow[] = {
149 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
151 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
152 1, 0.35, 0.2, 0.35, 0.8,
153 1, 0.65, 0.2, 0.65, 0.8,
158 double const brack[] = {
160 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
165 double const dbrack[] = {
167 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
169 0.50, 0.05, 0.50, 0.95,
174 double const corner[] = {
176 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
181 double const angle[] = {
183 1, 0, 0.05, 0.5, 1, 1,
188 double const slash[] = {
189 1, 0.95, 0.05, 0.05, 0.95,
194 double const hline[] = {
195 1, 0.00, 0.5, 1.0, 0.5,
200 double const ddot[] = {
201 1, 0.2, 0.5, 0.3, 0.5,
202 1, 0.7, 0.5, 0.8, 0.5,
207 double const dddot[] = {
208 1, 0.1, 0.5, 0.2, 0.5,
209 1, 0.45, 0.5, 0.55, 0.5,
210 1, 0.8, 0.5, 0.9, 0.5,
215 double const ddddot[] = {
216 1, 0.1, 0.5, 0.2, 0.5,
217 1, 0.45, 0.5, 0.55, 0.5,
218 1, 0.8, 0.5, 0.9, 0.5,
219 1, 1.15, 0.5, 1.25, 0.5,
224 double const hline3[] = {
226 1, 0.475, 0, 0.525, 0,
232 double const dline3[] = {
233 1, 0.1, 0.1, 0.15, 0.15,
234 1, 0.475, 0.475, 0.525, 0.525,
235 1, 0.85, 0.85, 0.9, 0.9,
240 double const hlinesmall[] = {
241 1, 0.4, 0.5, 0.6, 0.5,
246 double const ring[] = {
248 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
253 double const vert[] = {
254 1, 0.5, 0.05, 0.5, 0.95,
259 double const Vert[] = {
260 1, 0.3, 0.05, 0.3, 0.95,
261 1, 0.7, 0.05, 0.7, 0.95,
266 double const tilde[] = {
268 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
278 struct named_deco_struct {
284 named_deco_struct deco_table[] = {
286 {"widehat", angle, 3 },
287 {"widetilde", tilde, 0 },
288 {"underbar", hline, 0 },
289 {"underline", hline, 0 },
290 {"overline", hline, 0 },
291 {"underbrace", brace, 1 },
292 {"overbrace", brace, 3 },
293 {"overleftarrow", arrow, 1 },
294 {"overrightarrow", arrow, 3 },
295 {"overleftrightarrow", udarrow, 1 },
296 {"xleftarrow", arrow, 1 },
297 {"xrightarrow", arrow, 3 },
298 {"underleftarrow", arrow, 1 },
299 {"underrightarrow", arrow, 3 },
300 {"underleftrightarrow", udarrow, 1 },
301 {"undertilde", tilde, 0 },
302 {"utilde", tilde, 0 },
309 {"lbrace", brace, 0 },
310 {"rbrace", brace, 2 },
313 {"llbracket", dbrack, 0 },
314 {"rrbracket", dbrack, 2 },
317 {"slash", slash, 0 },
328 {"backslash", slash, 1 },
329 {"langle", angle, 0 },
330 {"lceil", corner, 0 },
331 {"lfloor", corner, 1 },
332 {"rangle", angle, 2 },
333 {"rceil", corner, 3 },
334 {"rfloor", corner, 2 },
335 {"downarrow", arrow, 2 },
336 {"Downarrow", Arrow, 2 },
337 {"uparrow", arrow, 0 },
338 {"Uparrow", Arrow, 0 },
339 {"updownarrow", udarrow, 0 },
340 {"Updownarrow", Udarrow, 0 },
344 {"dddot", dddot, 0 },
345 {"ddddot", ddddot, 0 },
347 {"grave", slash, 1 },
348 {"acute", slash, 0 },
349 {"tilde", tilde, 0 },
351 {"dot", hlinesmall, 0 },
352 {"check", angle, 1 },
353 {"breve", parenth, 1 },
355 {"mathring", ring, 0 },
358 {"dots", hline3, 0 },
359 {"ldots", hline3, 0 },
360 {"cdots", hline3, 0 },
361 {"vdots", hline3, 1 },
362 {"ddots", dline3, 0 },
363 {"adots", dline3, 1 },
364 {"iddots", dline3, 1 },
365 {"dotsb", hline3, 0 },
366 {"dotsc", hline3, 0 },
367 {"dotsi", hline3, 0 },
368 {"dotsm", hline3, 0 },
369 {"dotso", hline3, 0 }
373 map<docstring, deco_struct> deco_list;
375 // sort the table on startup
376 class init_deco_table {
379 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
380 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
384 deco_list[from_ascii(p->name)] = d;
389 static init_deco_table dummy;
392 deco_struct const * search_deco(docstring const & name)
394 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
395 return p == deco_list.end() ? 0 : &(p->second);
402 int mathed_char_width(FontInfo const & font, char_type c)
404 return theFontMetrics(font).width(c);
408 int mathed_char_kerning(FontInfo const & font, char_type c)
410 frontend::FontMetrics const & fm = theFontMetrics(font);
411 return fm.rbearing(c) - fm.width(c);
415 void mathed_string_dim(FontInfo const & font,
419 frontend::FontMetrics const & fm = theFontMetrics(font);
422 for (docstring::const_iterator it = s.begin();
425 dim.asc = max(dim.asc, fm.ascent(*it));
426 dim.des = max(dim.des, fm.descent(*it));
428 dim.wid = fm.width(s);
432 int mathed_string_width(FontInfo const & font, docstring const & s)
434 return theFontMetrics(font).width(s);
438 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
439 docstring const & name)
442 pi.pain.line(x + w/2, y, x + w/2, y + h,
443 Color_cursor, Painter::line_onoffdash);
447 deco_struct const * mds = search_deco(name);
449 lyxerr << "Deco was not found. Programming error?" << endl;
450 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
454 int const n = (w < h) ? w : h;
455 int const r = mds->angle;
456 double const * d = mds->data;
458 if (h > 70 && (name == "(" || name == ")"))
462 Matrix sqmt(r, n, n);
470 for (int i = 0; d[i]; ) {
471 int code = int(d[i++]);
472 if (code & 1) { // code == 1 || code == 3
478 sqmt.transform(xx, yy);
480 mt.transform(xx, yy);
481 mt.transform(x2, y2);
483 int(x + xx + 0.5), int(y + yy + 0.5),
484 int(x + x2 + 0.5), int(y + y2 + 0.5),
485 pi.base.font.color());
489 int const n = int(d[i++]);
490 for (int j = 0; j < n; ++j) {
493 // lyxerr << ' ' << xx << ' ' << yy << ' ';
495 sqmt.transform(xx, yy);
497 mt.transform(xx, yy);
498 xp[j] = int(x + xx + 0.5);
499 yp[j] = int(y + yy + 0.5);
500 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
502 pi.pain.lines(xp, yp, n, pi.base.font.color());
508 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
510 FontInfo font = mi.base.font;
511 augmentFont(font, from_ascii("mathnormal"));
512 mathed_string_dim(font, str, dim);
516 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
518 FontInfo f = pi.base.font;
519 augmentFont(f, from_ascii("mathnormal"));
520 f.setColor(Color_latex);
521 pi.pain.text(x, y, str, f);
525 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
527 FontInfo f = pi.base.font;
528 augmentFont(f, from_ascii("mathnormal"));
529 f.setColor(Color_foreground);
530 pi.pain.text(x, y, str, f);
534 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
536 frontend::FontMetrics const & fm = theFontMetrics(font);
537 asc = fm.maxAscent();
538 des = fm.maxDescent();
551 FontFamily const inh_family = INHERIT_FAMILY;
552 FontSeries const inh_series = INHERIT_SERIES;
553 FontShape const inh_shape = INHERIT_SHAPE;
556 // mathnormal should be the first, otherwise the fallback further down
558 fontinfo fontinfos[] = {
560 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
561 ITALIC_SHAPE, Color_math},
562 {"mathbf", inh_family, BOLD_SERIES,
563 inh_shape, Color_math},
564 {"mathcal", CMSY_FAMILY, inh_series,
565 inh_shape, Color_math},
566 {"mathfrak", EUFRAK_FAMILY, inh_series,
567 inh_shape, Color_math},
568 {"mathrm", ROMAN_FAMILY, inh_series,
569 UP_SHAPE, Color_math},
570 {"mathsf", SANS_FAMILY, inh_series,
571 inh_shape, Color_math},
572 {"mathbb", MSB_FAMILY, inh_series,
573 inh_shape, Color_math},
574 {"mathtt", TYPEWRITER_FAMILY, inh_series,
575 inh_shape, Color_math},
576 {"mathit", inh_family, inh_series,
577 ITALIC_SHAPE, Color_math},
578 {"mathscr", RSFS_FAMILY, inh_series,
579 inh_shape, Color_math},
580 {"cmex", CMEX_FAMILY, inh_series,
581 inh_shape, Color_math},
582 {"cmm", CMM_FAMILY, inh_series,
583 inh_shape, Color_math},
584 {"cmr", CMR_FAMILY, inh_series,
585 inh_shape, Color_math},
586 {"cmsy", CMSY_FAMILY, inh_series,
587 inh_shape, Color_math},
588 {"eufrak", EUFRAK_FAMILY, inh_series,
589 inh_shape, Color_math},
590 {"msa", MSA_FAMILY, inh_series,
591 inh_shape, Color_math},
592 {"msb", MSB_FAMILY, inh_series,
593 inh_shape, Color_math},
594 {"stmry", STMARY_FAMILY, inh_series,
595 inh_shape, Color_math},
596 {"wasy", WASY_FAMILY, inh_series,
597 inh_shape, Color_math},
598 {"esint", ESINT_FAMILY, inh_series,
599 inh_shape, Color_math},
602 {"text", inh_family, inh_series,
603 inh_shape, Color_foreground},
604 {"textbf", inh_family, BOLD_SERIES,
605 inh_shape, Color_foreground},
606 {"textit", inh_family, inh_series,
607 ITALIC_SHAPE, Color_foreground},
608 {"textmd", inh_family, MEDIUM_SERIES,
609 inh_shape, Color_foreground},
610 {"textnormal", inh_family, inh_series,
611 UP_SHAPE, Color_foreground},
612 {"textrm", ROMAN_FAMILY,
613 inh_series, UP_SHAPE,Color_foreground},
614 {"textsc", inh_family, inh_series,
615 SMALLCAPS_SHAPE, Color_foreground},
616 {"textsf", SANS_FAMILY, inh_series,
617 inh_shape, Color_foreground},
618 {"textsl", inh_family, inh_series,
619 SLANTED_SHAPE, Color_foreground},
620 {"texttt", TYPEWRITER_FAMILY, inh_series,
621 inh_shape, Color_foreground},
622 {"textup", inh_family, inh_series,
623 UP_SHAPE, Color_foreground},
626 {"textipa", inh_family, inh_series,
627 inh_shape, Color_foreground},
630 {"ce", inh_family, inh_series,
631 inh_shape, Color_foreground},
632 {"cf", inh_family, inh_series,
633 inh_shape, Color_foreground},
635 // LyX internal usage
636 {"lyxtex", inh_family, inh_series,
637 UP_SHAPE, Color_latex},
638 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
639 inh_shape, Color_math},
640 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
641 inh_shape, Color_math},
642 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
643 UP_SHAPE, Color_foreground},
644 {"lyxnochange", inh_family, inh_series,
645 inh_shape, Color_foreground},
646 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
647 UP_SHAPE, Color_math},
648 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
649 ITALIC_SHAPE, Color_math},
650 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
651 ITALIC_SHAPE, Color_math}
655 fontinfo * lookupFont(docstring const & name0)
657 //lyxerr << "searching font '" << name << "'" << endl;
658 int const n = sizeof(fontinfos) / sizeof(fontinfo);
659 string name = to_utf8(name0);
660 for (int i = 0; i < n; ++i)
661 if (fontinfos[i].cmd_ == name) {
662 //lyxerr << "found '" << i << "'" << endl;
663 return fontinfos + i;
669 fontinfo * searchFont(docstring const & name)
671 fontinfo * f = lookupFont(name);
672 return f ? f : fontinfos;
673 // this should be mathnormal
674 //return searchFont("mathnormal");
678 bool isFontName(docstring const & name)
680 return lookupFont(name);
684 bool isMathFont(docstring const & name)
686 fontinfo * f = lookupFont(name);
687 return f && f->color_ == Color_math;
691 bool isTextFont(docstring const & name)
693 fontinfo * f = lookupFont(name);
694 return f && f->color_ == Color_foreground;
698 FontInfo getFont(docstring const & name)
701 augmentFont(font, name);
706 void fakeFont(docstring const & orig, docstring const & fake)
708 fontinfo * forig = searchFont(orig);
709 fontinfo * ffake = searchFont(fake);
710 if (forig && ffake) {
711 forig->family_ = ffake->family_;
712 forig->series_ = ffake->series_;
713 forig->shape_ = ffake->shape_;
714 forig->color_ = ffake->color_;
716 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
717 << to_utf8(fake) << "'" << endl;
722 void augmentFont(FontInfo & font, docstring const & name)
724 static bool initialized = false;
727 // fake fonts if necessary
728 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
729 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
730 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
731 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
733 fontinfo * info = searchFont(name);
734 if (info->family_ != inh_family)
735 font.setFamily(info->family_);
736 if (info->series_ != inh_series)
737 font.setSeries(info->series_);
738 if (info->shape_ != inh_shape)
739 font.setShape(info->shape_);
740 if (info->color_ != Color_none)
741 font.setColor(info->color_);
745 bool isAlphaSymbol(MathAtom const & at)
747 if (at->asCharInset() ||
748 (at->asSymbolInset() &&
749 at->asSymbolInset()->isOrdAlpha()))
752 if (at->asFontInset()) {
753 MathData const & ar = at->asFontInset()->cell(0);
754 for (size_t i = 0; i < ar.size(); ++i) {
755 if (!(ar[i]->asCharInset() ||
756 (ar[i]->asSymbolInset() &&
757 ar[i]->asSymbolInset()->isOrdAlpha())))
766 docstring asString(MathData const & ar)
775 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
777 bool quiet = pf & Parse::QUIET;
778 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
779 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
783 docstring asString(InsetMath const & inset)
792 docstring asString(MathAtom const & at)