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"
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.1, 0.5, 0.9,
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 dbrack[] = {
166 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
168 0.50, 0.05, 0.50, 0.95,
173 double const corner[] = {
175 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
180 double const angle[] = {
182 1, 0, 0.05, 0.5, 1, 1,
187 double const slash[] = {
188 1, 0.95, 0.05, 0.05, 0.95,
193 double const hline[] = {
194 1, 0.00, 0.5, 1.0, 0.5,
199 double const ddot[] = {
200 1, 0.2, 0.5, 0.3, 0.5,
201 1, 0.7, 0.5, 0.8, 0.5,
206 double const dddot[] = {
207 1, 0.1, 0.5, 0.2, 0.5,
208 1, 0.45, 0.5, 0.55, 0.5,
209 1, 0.8, 0.5, 0.9, 0.5,
214 double const ddddot[] = {
215 1, 0.1, 0.5, 0.2, 0.5,
216 1, 0.45, 0.5, 0.55, 0.5,
217 1, 0.8, 0.5, 0.9, 0.5,
218 1, 1.15, 0.5, 1.25, 0.5,
223 double const hline3[] = {
225 1, 0.475, 0, 0.525, 0,
231 double const dline3[] = {
232 1, 0.1, 0.1, 0.15, 0.15,
233 1, 0.475, 0.475, 0.525, 0.525,
234 1, 0.85, 0.85, 0.9, 0.9,
239 double const hlinesmall[] = {
240 1, 0.4, 0.5, 0.6, 0.5,
245 double const ring[] = {
247 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
252 double const vert[] = {
253 1, 0.5, 0.05, 0.5, 0.95,
258 double const Vert[] = {
259 1, 0.3, 0.05, 0.3, 0.95,
260 1, 0.7, 0.05, 0.7, 0.95,
265 double const tilde[] = {
267 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
277 struct named_deco_struct {
283 named_deco_struct deco_table[] = {
285 {"widehat", angle, 3 },
286 {"widetilde", tilde, 0 },
287 {"underbar", hline, 0 },
288 {"underline", hline, 0 },
289 {"overline", hline, 0 },
290 {"underbrace", brace, 1 },
291 {"overbrace", brace, 3 },
292 {"overleftarrow", arrow, 1 },
293 {"overrightarrow", arrow, 3 },
294 {"overleftrightarrow", udarrow, 1 },
295 {"xleftarrow", arrow, 1 },
296 {"xrightarrow", arrow, 3 },
297 {"underleftarrow", arrow, 1 },
298 {"underrightarrow", arrow, 3 },
299 {"underleftrightarrow", udarrow, 1 },
300 {"undertilde", tilde, 0 },
301 {"utilde", tilde, 0 },
308 {"lbrace", brace, 0 },
309 {"rbrace", brace, 2 },
312 {"llbracket", dbrack, 0 },
313 {"rrbracket", dbrack, 2 },
316 {"slash", slash, 0 },
327 {"backslash", slash, 1 },
328 {"langle", angle, 0 },
329 {"lceil", corner, 0 },
330 {"lfloor", corner, 1 },
331 {"rangle", angle, 2 },
332 {"rceil", corner, 3 },
333 {"rfloor", corner, 2 },
334 {"downarrow", arrow, 2 },
335 {"Downarrow", Arrow, 2 },
336 {"uparrow", arrow, 0 },
337 {"Uparrow", Arrow, 0 },
338 {"updownarrow", udarrow, 0 },
339 {"Updownarrow", Udarrow, 0 },
343 {"dddot", dddot, 0 },
344 {"ddddot", ddddot, 0 },
346 {"grave", slash, 1 },
347 {"acute", slash, 0 },
348 {"tilde", tilde, 0 },
350 {"dot", hlinesmall, 0 },
351 {"check", angle, 1 },
352 {"breve", parenth, 1 },
354 {"mathring", ring, 0 },
357 {"dots", hline3, 0 },
358 {"ldots", hline3, 0 },
359 {"cdots", hline3, 0 },
360 {"vdots", hline3, 1 },
361 {"ddots", dline3, 0 },
362 {"adots", dline3, 1 },
363 {"iddots", dline3, 1 },
364 {"dotsb", hline3, 0 },
365 {"dotsc", hline3, 0 },
366 {"dotsi", hline3, 0 },
367 {"dotsm", hline3, 0 },
368 {"dotso", hline3, 0 }
372 map<docstring, deco_struct> deco_list;
374 // sort the table on startup
375 class init_deco_table {
378 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
379 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
383 deco_list[from_ascii(p->name)] = d;
388 static init_deco_table dummy;
391 deco_struct const * search_deco(docstring const & name)
393 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
394 return p == deco_list.end() ? 0 : &(p->second);
401 int mathed_char_width(FontInfo const & font, char_type c)
403 return theFontMetrics(font).width(c);
407 int mathed_char_kerning(FontInfo const & font, char_type c)
409 frontend::FontMetrics const & fm = theFontMetrics(font);
410 return fm.rbearing(c) - fm.width(c);
414 void mathed_string_dim(FontInfo const & font,
418 frontend::FontMetrics const & fm = theFontMetrics(font);
421 for (docstring::const_iterator it = s.begin();
424 dim.asc = max(dim.asc, fm.ascent(*it));
425 dim.des = max(dim.des, fm.descent(*it));
427 dim.wid = fm.width(s);
431 int mathed_string_width(FontInfo const & font, docstring const & s)
433 return theFontMetrics(font).width(s);
437 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
438 docstring const & name)
441 pi.pain.line(x + w/2, y, x + w/2, y + h,
442 Color_cursor, Painter::line_onoffdash);
446 deco_struct const * mds = search_deco(name);
448 lyxerr << "Deco was not found. Programming error?" << endl;
449 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
453 int const n = (w < h) ? w : h;
454 int const r = mds->angle;
455 double const * d = mds->data;
457 if (h > 70 && (name == "(" || name == ")"))
461 Matrix sqmt(r, n, n);
469 for (int i = 0; d[i]; ) {
470 int code = int(d[i++]);
471 if (code & 1) { // code == 1 || code == 3
477 sqmt.transform(xx, yy);
479 mt.transform(xx, yy);
480 mt.transform(x2, y2);
482 int(x + xx + 0.5), int(y + yy + 0.5),
483 int(x + x2 + 0.5), int(y + y2 + 0.5),
484 pi.base.font.color());
488 int const n = int(d[i++]);
489 for (int j = 0; j < n; ++j) {
492 // lyxerr << ' ' << xx << ' ' << yy << ' ';
494 sqmt.transform(xx, yy);
496 mt.transform(xx, yy);
497 xp[j] = int(x + xx + 0.5);
498 yp[j] = int(y + yy + 0.5);
499 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
501 pi.pain.lines(xp, yp, n, pi.base.font.color());
507 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
509 FontInfo font = mi.base.font;
510 augmentFont(font, from_ascii("mathnormal"));
511 mathed_string_dim(font, str, dim);
515 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
517 FontInfo f = pi.base.font;
518 augmentFont(f, from_ascii("mathnormal"));
519 f.setColor(Color_latex);
520 pi.pain.text(x, y, str, f);
524 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
526 FontInfo f = pi.base.font;
527 augmentFont(f, from_ascii("mathnormal"));
528 f.setColor(Color_foreground);
529 pi.pain.text(x, y, str, f);
533 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
535 frontend::FontMetrics const & fm = theFontMetrics(font);
536 asc = fm.maxAscent();
537 des = fm.maxDescent();
550 FontFamily const inh_family = INHERIT_FAMILY;
551 FontSeries const inh_series = INHERIT_SERIES;
552 FontShape const inh_shape = INHERIT_SHAPE;
555 // mathnormal should be the first, otherwise the fallback further down
557 fontinfo fontinfos[] = {
559 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
560 ITALIC_SHAPE, Color_math},
561 {"mathbf", inh_family, BOLD_SERIES,
562 inh_shape, Color_math},
563 {"mathcal", CMSY_FAMILY, inh_series,
564 inh_shape, Color_math},
565 {"mathfrak", EUFRAK_FAMILY, inh_series,
566 inh_shape, Color_math},
567 {"mathrm", ROMAN_FAMILY, inh_series,
568 UP_SHAPE, Color_math},
569 {"mathsf", SANS_FAMILY, inh_series,
570 inh_shape, Color_math},
571 {"mathbb", MSB_FAMILY, inh_series,
572 inh_shape, Color_math},
573 {"mathtt", TYPEWRITER_FAMILY, inh_series,
574 inh_shape, Color_math},
575 {"mathit", inh_family, inh_series,
576 ITALIC_SHAPE, Color_math},
577 {"mathscr", RSFS_FAMILY, inh_series,
578 inh_shape, Color_math},
579 {"cmex", CMEX_FAMILY, inh_series,
580 inh_shape, Color_math},
581 {"cmm", CMM_FAMILY, inh_series,
582 inh_shape, Color_math},
583 {"cmr", CMR_FAMILY, inh_series,
584 inh_shape, Color_math},
585 {"cmsy", CMSY_FAMILY, inh_series,
586 inh_shape, Color_math},
587 {"eufrak", EUFRAK_FAMILY, inh_series,
588 inh_shape, Color_math},
589 {"msa", MSA_FAMILY, inh_series,
590 inh_shape, Color_math},
591 {"msb", MSB_FAMILY, inh_series,
592 inh_shape, Color_math},
593 {"stmry", STMARY_FAMILY, inh_series,
594 inh_shape, Color_math},
595 {"wasy", WASY_FAMILY, inh_series,
596 inh_shape, Color_math},
597 {"esint", ESINT_FAMILY, inh_series,
598 inh_shape, Color_math},
601 {"text", inh_family, inh_series,
602 inh_shape, Color_foreground},
603 {"textbf", inh_family, BOLD_SERIES,
604 inh_shape, Color_foreground},
605 {"textit", inh_family, inh_series,
606 ITALIC_SHAPE, Color_foreground},
607 {"textmd", inh_family, MEDIUM_SERIES,
608 inh_shape, Color_foreground},
609 {"textnormal", inh_family, inh_series,
610 UP_SHAPE, Color_foreground},
611 {"textrm", ROMAN_FAMILY,
612 inh_series, UP_SHAPE,Color_foreground},
613 {"textsc", inh_family, inh_series,
614 SMALLCAPS_SHAPE, Color_foreground},
615 {"textsf", SANS_FAMILY, inh_series,
616 inh_shape, Color_foreground},
617 {"textsl", inh_family, inh_series,
618 SLANTED_SHAPE, Color_foreground},
619 {"texttt", TYPEWRITER_FAMILY, inh_series,
620 inh_shape, Color_foreground},
621 {"textup", inh_family, inh_series,
622 UP_SHAPE, Color_foreground},
625 {"textipa", inh_family, inh_series,
626 inh_shape, Color_foreground},
629 {"ce", inh_family, inh_series,
630 inh_shape, Color_foreground},
631 {"cf", inh_family, inh_series,
632 inh_shape, Color_foreground},
634 // LyX internal usage
635 {"lyxtex", inh_family, inh_series,
636 UP_SHAPE, Color_latex},
637 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
638 inh_shape, Color_math},
639 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
640 inh_shape, Color_math},
641 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
642 UP_SHAPE, Color_foreground},
643 {"lyxnochange", inh_family, inh_series,
644 inh_shape, Color_foreground},
645 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
646 UP_SHAPE, Color_math},
647 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
648 ITALIC_SHAPE, Color_math},
649 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
650 ITALIC_SHAPE, Color_math}
654 fontinfo * lookupFont(docstring const & name0)
656 //lyxerr << "searching font '" << name << "'" << endl;
657 int const n = sizeof(fontinfos) / sizeof(fontinfo);
658 string name = to_utf8(name0);
659 for (int i = 0; i < n; ++i)
660 if (fontinfos[i].cmd_ == name) {
661 //lyxerr << "found '" << i << "'" << endl;
662 return fontinfos + i;
668 fontinfo * searchFont(docstring const & name)
670 fontinfo * f = lookupFont(name);
671 return f ? f : fontinfos;
672 // this should be mathnormal
673 //return searchFont("mathnormal");
677 bool isFontName(docstring const & name)
679 return lookupFont(name);
683 bool isMathFont(docstring const & name)
685 fontinfo * f = lookupFont(name);
686 return f && f->color_ == Color_math;
690 bool isTextFont(docstring const & name)
692 fontinfo * f = lookupFont(name);
693 return f && f->color_ == Color_foreground;
697 FontInfo getFont(docstring const & name)
700 augmentFont(font, name);
705 void fakeFont(docstring const & orig, docstring const & fake)
707 fontinfo * forig = searchFont(orig);
708 fontinfo * ffake = searchFont(fake);
709 if (forig && ffake) {
710 forig->family_ = ffake->family_;
711 forig->series_ = ffake->series_;
712 forig->shape_ = ffake->shape_;
713 forig->color_ = ffake->color_;
715 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
716 << to_utf8(fake) << "'" << endl;
721 void augmentFont(FontInfo & font, docstring const & name)
723 static bool initialized = false;
726 // fake fonts if necessary
727 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
728 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
729 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
730 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
732 fontinfo * info = searchFont(name);
733 if (info->family_ != inh_family)
734 font.setFamily(info->family_);
735 if (info->series_ != inh_series)
736 font.setSeries(info->series_);
737 if (info->shape_ != inh_shape)
738 font.setShape(info->shape_);
739 if (info->color_ != Color_none)
740 font.setColor(info->color_);
744 bool isAlphaSymbol(MathAtom const & at)
746 if (at->asCharInset() ||
747 (at->asSymbolInset() &&
748 at->asSymbolInset()->isOrdAlpha()))
751 if (at->asFontInset()) {
752 MathData const & ar = at->asFontInset()->cell(0);
753 for (size_t i = 0; i < ar.size(); ++i) {
754 if (!(ar[i]->asCharInset() ||
755 (ar[i]->asSymbolInset() &&
756 ar[i]->asSymbolInset()->isOrdAlpha())))
765 docstring asString(MathData const & ar)
774 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
776 bool quiet = pf & Parse::QUIET;
777 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
778 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
782 docstring asString(InsetMath const & inset)
791 docstring asString(MathAtom const & at)