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 },
323 {"backslash", slash, 1 },
324 {"langle", angle, 0 },
325 {"lceil", corner, 0 },
326 {"lfloor", corner, 1 },
327 {"rangle", angle, 2 },
328 {"rceil", corner, 3 },
329 {"rfloor", corner, 2 },
330 {"downarrow", arrow, 2 },
331 {"Downarrow", Arrow, 2 },
332 {"uparrow", arrow, 0 },
333 {"Uparrow", Arrow, 0 },
334 {"updownarrow", udarrow, 0 },
335 {"Updownarrow", Udarrow, 0 },
339 {"dddot", dddot, 0 },
340 {"ddddot", ddddot, 0 },
342 {"grave", slash, 1 },
343 {"acute", slash, 0 },
344 {"tilde", tilde, 0 },
346 {"dot", hlinesmall, 0 },
347 {"check", angle, 1 },
348 {"breve", parenth, 1 },
350 {"mathring", ring, 0 },
353 {"dots", hline3, 0 },
354 {"ldots", hline3, 0 },
355 {"cdots", hline3, 0 },
356 {"vdots", hline3, 1 },
357 {"ddots", dline3, 0 },
358 {"adots", dline3, 1 },
359 {"iddots", dline3, 1 },
360 {"dotsb", hline3, 0 },
361 {"dotsc", hline3, 0 },
362 {"dotsi", hline3, 0 },
363 {"dotsm", hline3, 0 },
364 {"dotso", hline3, 0 }
368 map<docstring, deco_struct> deco_list;
370 // sort the table on startup
371 class init_deco_table {
374 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
375 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
379 deco_list[from_ascii(p->name)] = d;
384 static init_deco_table dummy;
387 deco_struct const * search_deco(docstring const & name)
389 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
390 return p == deco_list.end() ? 0 : &(p->second);
397 int mathed_char_width(FontInfo const & font, char_type c)
399 return theFontMetrics(font).width(c);
403 int mathed_char_kerning(FontInfo const & font, char_type c)
405 frontend::FontMetrics const & fm = theFontMetrics(font);
406 return fm.rbearing(c) - fm.width(c);
410 void mathed_string_dim(FontInfo const & font,
414 frontend::FontMetrics const & fm = theFontMetrics(font);
417 for (docstring::const_iterator it = s.begin();
420 dim.asc = max(dim.asc, fm.ascent(*it));
421 dim.des = max(dim.des, fm.descent(*it));
423 dim.wid = fm.width(s);
427 int mathed_string_width(FontInfo const & font, docstring const & s)
429 return theFontMetrics(font).width(s);
433 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
434 docstring const & name)
437 pi.pain.line(x + w/2, y, x + w/2, y + h,
438 Color_cursor, Painter::line_onoffdash);
442 deco_struct const * mds = search_deco(name);
444 lyxerr << "Deco was not found. Programming error?" << endl;
445 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
449 int const n = (w < h) ? w : h;
450 int const r = mds->angle;
451 double const * d = mds->data;
453 if (h > 70 && (name == "(" || name == ")"))
457 Matrix sqmt(r, n, n);
465 for (int i = 0; d[i]; ) {
466 int code = int(d[i++]);
467 if (code & 1) { // code == 1 || code == 3
473 sqmt.transform(xx, yy);
475 mt.transform(xx, yy);
476 mt.transform(x2, y2);
478 int(x + xx + 0.5), int(y + yy + 0.5),
479 int(x + x2 + 0.5), int(y + y2 + 0.5),
480 pi.base.font.color());
484 int const n = int(d[i++]);
485 for (int j = 0; j < n; ++j) {
488 // lyxerr << ' ' << xx << ' ' << yy << ' ';
490 sqmt.transform(xx, yy);
492 mt.transform(xx, yy);
493 xp[j] = int(x + xx + 0.5);
494 yp[j] = int(y + yy + 0.5);
495 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
497 pi.pain.lines(xp, yp, n, pi.base.font.color());
503 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
505 FontInfo font = mi.base.font;
506 augmentFont(font, from_ascii("mathnormal"));
507 mathed_string_dim(font, str, dim);
511 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
513 FontInfo f = pi.base.font;
514 augmentFont(f, from_ascii("mathnormal"));
515 f.setColor(Color_latex);
516 pi.pain.text(x, y, str, f);
520 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
522 FontInfo f = pi.base.font;
523 augmentFont(f, from_ascii("mathnormal"));
524 f.setColor(Color_foreground);
525 pi.pain.text(x, y, str, f);
529 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
531 frontend::FontMetrics const & fm = theFontMetrics(font);
532 asc = fm.maxAscent();
533 des = fm.maxDescent();
546 FontFamily const inh_family = INHERIT_FAMILY;
547 FontSeries const inh_series = INHERIT_SERIES;
548 FontShape const inh_shape = INHERIT_SHAPE;
551 // mathnormal should be the first, otherwise the fallback further down
553 fontinfo fontinfos[] = {
555 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
556 ITALIC_SHAPE, Color_math},
557 {"mathbf", inh_family, BOLD_SERIES,
558 inh_shape, Color_math},
559 {"mathcal", CMSY_FAMILY, inh_series,
560 inh_shape, Color_math},
561 {"mathfrak", EUFRAK_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"mathrm", ROMAN_FAMILY, inh_series,
564 UP_SHAPE, Color_math},
565 {"mathsf", SANS_FAMILY, inh_series,
566 inh_shape, Color_math},
567 {"mathbb", MSB_FAMILY, inh_series,
568 inh_shape, Color_math},
569 {"mathtt", TYPEWRITER_FAMILY, inh_series,
570 inh_shape, Color_math},
571 {"mathit", inh_family, inh_series,
572 ITALIC_SHAPE, Color_math},
573 {"mathscr", RSFS_FAMILY, inh_series,
574 inh_shape, Color_math},
575 {"cmex", CMEX_FAMILY, inh_series,
576 inh_shape, Color_math},
577 {"cmm", CMM_FAMILY, inh_series,
578 inh_shape, Color_math},
579 {"cmr", CMR_FAMILY, inh_series,
580 inh_shape, Color_math},
581 {"cmsy", CMSY_FAMILY, inh_series,
582 inh_shape, Color_math},
583 {"eufrak", EUFRAK_FAMILY, inh_series,
584 inh_shape, Color_math},
585 {"msa", MSA_FAMILY, inh_series,
586 inh_shape, Color_math},
587 {"msb", MSB_FAMILY, inh_series,
588 inh_shape, Color_math},
589 {"stmry", STMARY_FAMILY, inh_series,
590 inh_shape, Color_math},
591 {"wasy", WASY_FAMILY, inh_series,
592 inh_shape, Color_math},
593 {"esint", ESINT_FAMILY, inh_series,
594 inh_shape, Color_math},
597 {"text", inh_family, inh_series,
598 inh_shape, Color_foreground},
599 {"textbf", inh_family, BOLD_SERIES,
600 inh_shape, Color_foreground},
601 {"textit", inh_family, inh_series,
602 ITALIC_SHAPE, Color_foreground},
603 {"textmd", inh_family, MEDIUM_SERIES,
604 inh_shape, Color_foreground},
605 {"textnormal", inh_family, inh_series,
606 UP_SHAPE, Color_foreground},
607 {"textrm", ROMAN_FAMILY,
608 inh_series, UP_SHAPE,Color_foreground},
609 {"textsc", inh_family, inh_series,
610 SMALLCAPS_SHAPE, Color_foreground},
611 {"textsf", SANS_FAMILY, inh_series,
612 inh_shape, Color_foreground},
613 {"textsl", inh_family, inh_series,
614 SLANTED_SHAPE, Color_foreground},
615 {"texttt", TYPEWRITER_FAMILY, inh_series,
616 inh_shape, Color_foreground},
617 {"textup", inh_family, inh_series,
618 UP_SHAPE, Color_foreground},
621 {"textipa", inh_family, inh_series,
622 inh_shape, Color_foreground},
625 {"ce", inh_family, inh_series,
626 inh_shape, Color_foreground},
627 {"cf", inh_family, inh_series,
628 inh_shape, Color_foreground},
630 // LyX internal usage
631 {"lyxtex", inh_family, inh_series,
632 UP_SHAPE, Color_latex},
633 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
634 inh_shape, Color_math},
635 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
636 inh_shape, Color_math},
637 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
638 UP_SHAPE, Color_foreground},
639 {"lyxnochange", inh_family, inh_series,
640 inh_shape, Color_foreground},
641 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
642 UP_SHAPE, Color_math},
643 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
644 ITALIC_SHAPE, Color_math},
645 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
646 ITALIC_SHAPE, Color_math}
650 fontinfo * lookupFont(docstring const & name0)
652 //lyxerr << "searching font '" << name << "'" << endl;
653 int const n = sizeof(fontinfos) / sizeof(fontinfo);
654 string name = to_utf8(name0);
655 for (int i = 0; i < n; ++i)
656 if (fontinfos[i].cmd_ == name) {
657 //lyxerr << "found '" << i << "'" << endl;
658 return fontinfos + i;
664 fontinfo * searchFont(docstring const & name)
666 fontinfo * f = lookupFont(name);
667 return f ? f : fontinfos;
668 // this should be mathnormal
669 //return searchFont("mathnormal");
673 bool isFontName(docstring const & name)
675 return lookupFont(name);
679 bool isMathFont(docstring const & name)
681 fontinfo * f = lookupFont(name);
682 return f && f->color_ == Color_math;
686 bool isTextFont(docstring const & name)
688 fontinfo * f = lookupFont(name);
689 return f && f->color_ == Color_foreground;
693 FontInfo getFont(docstring const & name)
696 augmentFont(font, name);
701 void fakeFont(docstring const & orig, docstring const & fake)
703 fontinfo * forig = searchFont(orig);
704 fontinfo * ffake = searchFont(fake);
705 if (forig && ffake) {
706 forig->family_ = ffake->family_;
707 forig->series_ = ffake->series_;
708 forig->shape_ = ffake->shape_;
709 forig->color_ = ffake->color_;
711 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
712 << to_utf8(fake) << "'" << endl;
717 void augmentFont(FontInfo & font, docstring const & name)
719 static bool initialized = false;
722 // fake fonts if necessary
723 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
724 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
725 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
726 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
728 fontinfo * info = searchFont(name);
729 if (info->family_ != inh_family)
730 font.setFamily(info->family_);
731 if (info->series_ != inh_series)
732 font.setSeries(info->series_);
733 if (info->shape_ != inh_shape)
734 font.setShape(info->shape_);
735 if (info->color_ != Color_none)
736 font.setColor(info->color_);
740 bool isAlphaSymbol(MathAtom const & at)
742 if (at->asCharInset() ||
743 (at->asSymbolInset() &&
744 at->asSymbolInset()->isOrdAlpha()))
747 if (at->asFontInset()) {
748 MathData const & ar = at->asFontInset()->cell(0);
749 for (size_t i = 0; i < ar.size(); ++i) {
750 if (!(ar[i]->asCharInset() ||
751 (ar[i]->asSymbolInset() &&
752 ar[i]->asSymbolInset()->isOrdAlpha())))
761 docstring asString(MathData const & ar)
770 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
772 bool quiet = pf & Parse::QUIET;
773 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
774 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
778 docstring asString(InsetMath const & inset)
787 docstring asString(MathAtom const & at)