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 // FIXME: The following two don't work on OS X, since the Symbol font
639 // uses a different encoding, and is therefore disabled in
640 // FontLoader::available().
641 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
642 inh_shape, Color_math},
643 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
644 inh_shape, Color_math},
645 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
646 UP_SHAPE, Color_foreground},
647 {"lyxnochange", inh_family, inh_series,
648 inh_shape, Color_foreground},
649 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
650 UP_SHAPE, Color_math},
651 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
652 ITALIC_SHAPE, Color_math},
653 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
654 ITALIC_SHAPE, Color_math}
658 fontinfo * lookupFont(docstring const & name0)
660 //lyxerr << "searching font '" << name << "'" << endl;
661 int const n = sizeof(fontinfos) / sizeof(fontinfo);
662 string name = to_utf8(name0);
663 for (int i = 0; i < n; ++i)
664 if (fontinfos[i].cmd_ == name) {
665 //lyxerr << "found '" << i << "'" << endl;
666 return fontinfos + i;
672 fontinfo * searchFont(docstring const & name)
674 fontinfo * f = lookupFont(name);
675 return f ? f : fontinfos;
676 // this should be mathnormal
677 //return searchFont("mathnormal");
681 bool isFontName(docstring const & name)
683 return lookupFont(name);
687 bool isMathFont(docstring const & name)
689 fontinfo * f = lookupFont(name);
690 return f && f->color_ == Color_math;
694 bool isTextFont(docstring const & name)
696 fontinfo * f = lookupFont(name);
697 return f && f->color_ == Color_foreground;
701 FontInfo getFont(docstring const & name)
704 augmentFont(font, name);
709 void fakeFont(docstring const & orig, docstring const & fake)
711 fontinfo * forig = searchFont(orig);
712 fontinfo * ffake = searchFont(fake);
713 if (forig && ffake) {
714 forig->family_ = ffake->family_;
715 forig->series_ = ffake->series_;
716 forig->shape_ = ffake->shape_;
717 forig->color_ = ffake->color_;
719 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
720 << to_utf8(fake) << "'" << endl;
725 void augmentFont(FontInfo & font, docstring const & name)
727 static bool initialized = false;
730 // fake fonts if necessary
731 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
732 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
733 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
734 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
736 fontinfo * info = searchFont(name);
737 if (info->family_ != inh_family)
738 font.setFamily(info->family_);
739 if (info->series_ != inh_series)
740 font.setSeries(info->series_);
741 if (info->shape_ != inh_shape)
742 font.setShape(info->shape_);
743 if (info->color_ != Color_none)
744 font.setColor(info->color_);
748 bool isAlphaSymbol(MathAtom const & at)
750 if (at->asCharInset() ||
751 (at->asSymbolInset() &&
752 at->asSymbolInset()->isOrdAlpha()))
755 if (at->asFontInset()) {
756 MathData const & ar = at->asFontInset()->cell(0);
757 for (size_t i = 0; i < ar.size(); ++i) {
758 if (!(ar[i]->asCharInset() ||
759 (ar[i]->asSymbolInset() &&
760 ar[i]->asSymbolInset()->isOrdAlpha())))
769 docstring asString(MathData const & ar)
778 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
780 bool quiet = pf & Parse::QUIET;
781 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
782 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
786 docstring asString(InsetMath const & inset)
795 docstring asString(MathAtom const & at)