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 "InsetMath.h"
18 #include "MathParser.h"
19 #include "MathStream.h"
21 #include "frontends/FontLoader.h"
22 #include "frontends/FontMetrics.h"
23 #include "frontends/Painter.h"
25 #include "support/debug.h"
26 #include "support/docstream.h"
34 using frontend::Painter;
41 Matrix(int, double, double);
43 void transform(double &, double &);
50 Matrix::Matrix(int code, double x, double y)
52 double const cs = (code & 1) ? 0 : (1 - code);
53 double const sn = (code & 1) ? (2 - code) : 0;
61 void Matrix::transform(double & x, double & y)
63 double xx = m_[0][0] * x + m_[0][1] * y;
64 double yy = m_[1][0] * x + m_[1][1] * y;
74 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
75 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
79 double const parenthHigh[] = {
81 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
82 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
83 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
84 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
90 double const parenth[] = {
92 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
93 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
94 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
95 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
101 double const brace[] = {
103 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
104 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
105 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
106 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
107 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
108 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
109 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
114 double const arrow[] = {
116 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
117 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
119 3, 0.5000, 0.1500, 0.5000, 0.9500,
124 double const Arrow[] = {
126 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
127 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
129 3, 0.3500, 0.5000, 0.3500, 0.9500,
130 3, 0.6500, 0.5000, 0.6500, 0.9500,
135 double const udarrow[] = {
137 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
139 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
140 1, 0.5, 0.2, 0.5, 0.8,
145 double const Udarrow[] = {
147 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
149 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
150 1, 0.35, 0.2, 0.35, 0.8,
151 1, 0.65, 0.2, 0.65, 0.8,
156 double const brack[] = {
158 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
163 double const corner[] = {
165 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
170 double const angle[] = {
172 1, 0, 0.05, 0.5, 1, 1,
177 double const slash[] = {
178 1, 0.95, 0.05, 0.05, 0.95,
183 double const hline[] = {
184 1, 0.00, 0.5, 1.0, 0.5,
189 double const ddot[] = {
190 1, 0.2, 0.5, 0.3, 0.5,
191 1, 0.7, 0.5, 0.8, 0.5,
196 double const dddot[] = {
197 1, 0.1, 0.5, 0.2, 0.5,
198 1, 0.45, 0.5, 0.55, 0.5,
199 1, 0.8, 0.5, 0.9, 0.5,
204 double const ddddot[] = {
205 1, 0.1, 0.5, 0.2, 0.5,
206 1, 0.45, 0.5, 0.55, 0.5,
207 1, 0.8, 0.5, 0.9, 0.5,
208 1, 1.15, 0.5, 1.25, 0.5,
213 double const hline3[] = {
215 1, 0.475, 0, 0.525, 0,
221 double const dline3[] = {
222 1, 0.1, 0.1, 0.15, 0.15,
223 1, 0.475, 0.475, 0.525, 0.525,
224 1, 0.85, 0.85, 0.9, 0.9,
229 double const hlinesmall[] = {
230 1, 0.4, 0.5, 0.6, 0.5,
235 double const ring[] = {
237 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
242 double const vert[] = {
243 1, 0.5, 0.05, 0.5, 0.95,
248 double const Vert[] = {
249 1, 0.3, 0.05, 0.3, 0.95,
250 1, 0.7, 0.05, 0.7, 0.95,
255 double const tilde[] = {
257 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
267 struct named_deco_struct {
273 named_deco_struct deco_table[] = {
275 {"widehat", angle, 3 },
276 {"widetilde", tilde, 0 },
277 {"underbar", hline, 0 },
278 {"underline", hline, 0 },
279 {"overline", hline, 0 },
280 {"underbrace", brace, 1 },
281 {"overbrace", brace, 3 },
282 {"overleftarrow", arrow, 1 },
283 {"overrightarrow", arrow, 3 },
284 {"overleftrightarrow", udarrow, 1 },
285 {"xleftarrow", arrow, 1 },
286 {"xrightarrow", arrow, 3 },
287 {"underleftarrow", arrow, 1 },
288 {"underrightarrow", arrow, 3 },
289 {"underleftrightarrow", udarrow, 1 },
290 {"undertilde", tilde, 0 },
291 {"utilde", tilde, 0 },
298 {"lbrace", brace, 0 },
299 {"rbrace", brace, 2 },
304 {"slash", slash, 0 },
311 {"backslash", slash, 1 },
312 {"langle", angle, 0 },
313 {"lceil", corner, 0 },
314 {"lfloor", corner, 1 },
315 {"rangle", angle, 2 },
316 {"rceil", corner, 3 },
317 {"rfloor", corner, 2 },
318 {"downarrow", arrow, 2 },
319 {"Downarrow", Arrow, 2 },
320 {"uparrow", arrow, 0 },
321 {"Uparrow", Arrow, 0 },
322 {"updownarrow", udarrow, 0 },
323 {"Updownarrow", Udarrow, 0 },
327 {"dddot", dddot, 0 },
328 {"ddddot", ddddot, 0 },
330 {"grave", slash, 1 },
331 {"acute", slash, 0 },
332 {"tilde", tilde, 0 },
334 {"dot", hlinesmall, 0 },
335 {"check", angle, 1 },
336 {"breve", parenth, 1 },
338 {"mathring", ring, 0 },
341 {"dots", hline3, 0 },
342 {"ldots", hline3, 0 },
343 {"cdots", hline3, 0 },
344 {"vdots", hline3, 1 },
345 {"ddots", dline3, 0 },
346 {"adots", dline3, 1 },
347 {"iddots", dline3, 1 },
348 {"dotsb", hline3, 0 },
349 {"dotsc", hline3, 0 },
350 {"dotsi", hline3, 0 },
351 {"dotsm", hline3, 0 },
352 {"dotso", hline3, 0 }
356 map<docstring, deco_struct> deco_list;
358 // sort the table on startup
359 class init_deco_table {
362 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
363 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
367 deco_list[from_ascii(p->name)] = d;
372 static init_deco_table dummy;
375 deco_struct const * search_deco(docstring const & name)
377 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
378 return p == deco_list.end() ? 0 : &(p->second);
385 int mathed_char_width(FontInfo const & font, char_type c)
387 return theFontMetrics(font).width(c);
391 int mathed_char_kerning(FontInfo const & font, char_type c)
393 frontend::FontMetrics const & fm = theFontMetrics(font);
394 return fm.rbearing(c) - fm.width(c);
398 void mathed_string_dim(FontInfo const & font,
402 frontend::FontMetrics const & fm = theFontMetrics(font);
405 for (docstring::const_iterator it = s.begin();
408 dim.asc = max(dim.asc, fm.ascent(*it));
409 dim.des = max(dim.des, fm.descent(*it));
411 dim.wid = fm.width(s);
415 int mathed_string_width(FontInfo const & font, docstring const & s)
417 return theFontMetrics(font).width(s);
421 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
422 docstring const & name)
425 pi.pain.line(x + w/2, y, x + w/2, y + h,
426 Color_cursor, Painter::line_onoffdash);
430 deco_struct const * mds = search_deco(name);
432 lyxerr << "Deco was not found. Programming error?" << endl;
433 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
437 int const n = (w < h) ? w : h;
438 int const r = mds->angle;
439 double const * d = mds->data;
441 if (h > 70 && (name == "(" || name == ")"))
445 Matrix sqmt(r, n, n);
453 for (int i = 0; d[i]; ) {
454 int code = int(d[i++]);
455 if (code & 1) { // code == 1 || code == 3
461 sqmt.transform(xx, yy);
463 mt.transform(xx, yy);
464 mt.transform(x2, y2);
466 int(x + xx + 0.5), int(y + yy + 0.5),
467 int(x + x2 + 0.5), int(y + y2 + 0.5),
468 pi.base.font.color());
472 int const n = int(d[i++]);
473 for (int j = 0; j < n; ++j) {
476 // lyxerr << ' ' << xx << ' ' << yy << ' ';
478 sqmt.transform(xx, yy);
480 mt.transform(xx, yy);
481 xp[j] = int(x + xx + 0.5);
482 yp[j] = int(y + yy + 0.5);
483 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
485 pi.pain.lines(xp, yp, n, pi.base.font.color());
491 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
493 FontInfo font = mi.base.font;
494 augmentFont(font, from_ascii("mathnormal"));
495 mathed_string_dim(font, str, dim);
499 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
501 FontInfo f = pi.base.font;
502 augmentFont(f, from_ascii("mathnormal"));
503 f.setColor(Color_latex);
504 pi.pain.text(x, y, str, f);
508 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
510 FontInfo f = pi.base.font;
511 augmentFont(f, from_ascii("mathnormal"));
512 f.setColor(Color_foreground);
513 pi.pain.text(x, y, str, f);
517 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
519 frontend::FontMetrics const & fm = theFontMetrics(font);
520 asc = fm.maxAscent();
521 des = fm.maxDescent();
534 FontFamily const inh_family = INHERIT_FAMILY;
535 FontSeries const inh_series = INHERIT_SERIES;
536 FontShape const inh_shape = INHERIT_SHAPE;
539 // mathnormal should be the first, otherwise the fallback further down
541 fontinfo fontinfos[] = {
543 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
544 ITALIC_SHAPE, Color_math},
545 {"mathbf", inh_family, BOLD_SERIES,
546 inh_shape, Color_math},
547 {"mathcal", CMSY_FAMILY, inh_series,
548 inh_shape, Color_math},
549 {"mathfrak", EUFRAK_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"mathrm", ROMAN_FAMILY, inh_series,
552 UP_SHAPE, Color_math},
553 {"mathsf", SANS_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"mathbb", MSB_FAMILY, inh_series,
556 inh_shape, Color_math},
557 {"mathtt", TYPEWRITER_FAMILY, inh_series,
558 inh_shape, Color_math},
559 {"mathit", inh_family, inh_series,
560 ITALIC_SHAPE, Color_math},
561 {"mathscr", RSFS_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"cmex", CMEX_FAMILY, inh_series,
564 inh_shape, Color_math},
565 {"cmm", CMM_FAMILY, inh_series,
566 inh_shape, Color_math},
567 {"cmr", CMR_FAMILY, inh_series,
568 inh_shape, Color_math},
569 {"cmsy", CMSY_FAMILY, inh_series,
570 inh_shape, Color_math},
571 {"eufrak", EUFRAK_FAMILY, inh_series,
572 inh_shape, Color_math},
573 {"msa", MSA_FAMILY, inh_series,
574 inh_shape, Color_math},
575 {"msb", MSB_FAMILY, inh_series,
576 inh_shape, Color_math},
577 {"wasy", WASY_FAMILY, inh_series,
578 inh_shape, Color_math},
579 {"esint", ESINT_FAMILY, inh_series,
580 inh_shape, Color_math},
583 {"text", inh_family, inh_series,
584 inh_shape, Color_foreground},
585 {"textbf", inh_family, BOLD_SERIES,
586 inh_shape, Color_foreground},
587 {"textit", inh_family, inh_series,
588 ITALIC_SHAPE, Color_foreground},
589 {"textmd", inh_family, MEDIUM_SERIES,
590 inh_shape, Color_foreground},
591 {"textnormal", inh_family, inh_series,
592 UP_SHAPE, Color_foreground},
593 {"textrm", ROMAN_FAMILY,
594 inh_series, UP_SHAPE,Color_foreground},
595 {"textsc", inh_family, inh_series,
596 SMALLCAPS_SHAPE, Color_foreground},
597 {"textsf", SANS_FAMILY, inh_series,
598 inh_shape, Color_foreground},
599 {"textsl", inh_family, inh_series,
600 SLANTED_SHAPE, Color_foreground},
601 {"texttt", TYPEWRITER_FAMILY, inh_series,
602 inh_shape, Color_foreground},
603 {"textup", inh_family, inh_series,
604 UP_SHAPE, Color_foreground},
607 {"textipa", inh_family, inh_series,
608 inh_shape, Color_foreground},
611 {"ce", inh_family, inh_series,
612 inh_shape, Color_foreground},
613 {"cf", inh_family, inh_series,
614 inh_shape, Color_foreground},
616 // LyX internal usage
617 {"lyxtex", inh_family, inh_series,
618 UP_SHAPE, Color_latex},
619 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
620 inh_shape, Color_math},
621 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
622 inh_shape, Color_math},
623 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
624 UP_SHAPE, Color_foreground},
625 {"lyxnochange", inh_family, inh_series,
626 inh_shape, Color_foreground},
627 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
628 UP_SHAPE, Color_math},
629 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
630 ITALIC_SHAPE, Color_math},
631 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
632 ITALIC_SHAPE, Color_math}
636 fontinfo * lookupFont(docstring const & name0)
638 //lyxerr << "searching font '" << name << "'" << endl;
639 int const n = sizeof(fontinfos) / sizeof(fontinfo);
640 string name = to_utf8(name0);
641 for (int i = 0; i < n; ++i)
642 if (fontinfos[i].cmd_ == name) {
643 //lyxerr << "found '" << i << "'" << endl;
644 return fontinfos + i;
650 fontinfo * searchFont(docstring const & name)
652 fontinfo * f = lookupFont(name);
653 return f ? f : fontinfos;
654 // this should be mathnormal
655 //return searchFont("mathnormal");
659 bool isFontName(docstring const & name)
661 return lookupFont(name);
665 bool isMathFont(docstring const & name)
667 fontinfo * f = lookupFont(name);
668 return f && f->color_ == Color_math;
672 bool isTextFont(docstring const & name)
674 fontinfo * f = lookupFont(name);
675 return f && f->color_ == Color_foreground;
679 FontInfo getFont(docstring const & name)
682 augmentFont(font, name);
687 void fakeFont(docstring const & orig, docstring const & fake)
689 fontinfo * forig = searchFont(orig);
690 fontinfo * ffake = searchFont(fake);
691 if (forig && ffake) {
692 forig->family_ = ffake->family_;
693 forig->series_ = ffake->series_;
694 forig->shape_ = ffake->shape_;
695 forig->color_ = ffake->color_;
697 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
698 << to_utf8(fake) << "'" << endl;
703 void augmentFont(FontInfo & font, docstring const & name)
705 static bool initialized = false;
708 // fake fonts if necessary
709 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
710 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
711 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
712 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
714 fontinfo * info = searchFont(name);
715 if (info->family_ != inh_family)
716 font.setFamily(info->family_);
717 if (info->series_ != inh_series)
718 font.setSeries(info->series_);
719 if (info->shape_ != inh_shape)
720 font.setShape(info->shape_);
721 if (info->color_ != Color_none)
722 font.setColor(info->color_);
726 docstring asString(MathData const & ar)
735 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
737 bool quiet = pf & Parse::QUIET;
738 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
739 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
743 docstring asString(InsetMath const & inset)
752 docstring asString(MathAtom const & at)