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.0, 0.5, 0.1, 0.5,
206 1, 0.3, 0.5, 0.4, 0.5,
207 1, 0.6, 0.5, 0.7, 0.5,
208 1, 0.9, 0.5, 1.0, 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 },
296 {"lbrace", brace, 0 },
297 {"rbrace", brace, 2 },
302 {"slash", slash, 0 },
309 {"backslash", slash, 1 },
310 {"langle", angle, 0 },
311 {"lceil", corner, 0 },
312 {"lfloor", corner, 1 },
313 {"rangle", angle, 2 },
314 {"rceil", corner, 3 },
315 {"rfloor", corner, 2 },
316 {"downarrow", arrow, 2 },
317 {"Downarrow", Arrow, 2 },
318 {"uparrow", arrow, 0 },
319 {"Uparrow", Arrow, 0 },
320 {"updownarrow", udarrow, 0 },
321 {"Updownarrow", Udarrow, 0 },
325 {"dddot", dddot, 0 },
326 {"ddddot", ddddot, 0 },
328 {"grave", slash, 1 },
329 {"acute", slash, 0 },
330 {"tilde", tilde, 0 },
332 {"dot", hlinesmall, 0 },
333 {"check", angle, 1 },
334 {"breve", parenth, 1 },
336 {"mathring", ring, 0 },
339 {"dots", hline3, 0 },
340 {"ldots", hline3, 0 },
341 {"cdots", hline3, 0 },
342 {"vdots", hline3, 1 },
343 {"ddots", dline3, 0 },
344 {"adots", dline3, 1 },
345 {"iddots", dline3, 1 },
346 {"dotsb", hline3, 0 },
347 {"dotsc", hline3, 0 },
348 {"dotsi", hline3, 0 },
349 {"dotsm", hline3, 0 },
350 {"dotso", hline3, 0 }
354 map<docstring, deco_struct> deco_list;
356 // sort the table on startup
357 class init_deco_table {
360 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
361 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
365 deco_list[from_ascii(p->name)] = d;
370 static init_deco_table dummy;
373 deco_struct const * search_deco(docstring const & name)
375 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
376 return p == deco_list.end() ? 0 : &(p->second);
383 int mathed_char_width(FontInfo const & font, char_type c)
385 return theFontMetrics(font).width(c);
389 int mathed_char_kerning(FontInfo const & font, char_type c)
391 frontend::FontMetrics const & fm = theFontMetrics(font);
392 return fm.rbearing(c) - fm.width(c);
396 void mathed_string_dim(FontInfo const & font,
400 frontend::FontMetrics const & fm = theFontMetrics(font);
403 for (docstring::const_iterator it = s.begin();
406 dim.asc = max(dim.asc, fm.ascent(*it));
407 dim.des = max(dim.des, fm.descent(*it));
409 dim.wid = fm.width(s);
413 int mathed_string_width(FontInfo const & font, docstring const & s)
415 return theFontMetrics(font).width(s);
419 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
420 docstring const & name)
423 pi.pain.line(x + w/2, y, x + w/2, y + h,
424 Color_cursor, Painter::line_onoffdash);
428 deco_struct const * mds = search_deco(name);
430 lyxerr << "Deco was not found. Programming error?" << endl;
431 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
435 int const n = (w < h) ? w : h;
436 int const r = mds->angle;
437 double const * d = mds->data;
439 if (h > 70 && (name == "(" || name == ")"))
443 Matrix sqmt(r, n, n);
451 for (int i = 0; d[i]; ) {
452 int code = int(d[i++]);
453 if (code & 1) { // code == 1 || code == 3
459 sqmt.transform(xx, yy);
461 mt.transform(xx, yy);
462 mt.transform(x2, y2);
464 int(x + xx + 0.5), int(y + yy + 0.5),
465 int(x + x2 + 0.5), int(y + y2 + 0.5),
466 pi.base.font.color());
470 int const n = int(d[i++]);
471 for (int j = 0; j < n; ++j) {
474 // lyxerr << ' ' << xx << ' ' << yy << ' ';
476 sqmt.transform(xx, yy);
478 mt.transform(xx, yy);
479 xp[j] = int(x + xx + 0.5);
480 yp[j] = int(y + yy + 0.5);
481 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
483 pi.pain.lines(xp, yp, n, pi.base.font.color());
489 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
491 FontInfo f = pi.base.font;
492 f.setColor(Color_latex);
493 pi.pain.text(x, y, str, f);
497 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
499 FontInfo f = pi.base.font;
500 f.setColor(Color_foreground);
501 pi.pain.text(x, y, str, f);
505 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
507 frontend::FontMetrics const & fm = theFontMetrics(font);
508 asc = fm.maxAscent();
509 des = fm.maxDescent();
522 FontFamily const inh_family = INHERIT_FAMILY;
523 FontSeries const inh_series = INHERIT_SERIES;
524 FontShape const inh_shape = INHERIT_SHAPE;
527 // mathnormal should be the first, otherwise the fallback further down
529 fontinfo fontinfos[] = {
531 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
532 ITALIC_SHAPE, Color_math},
533 {"mathbf", inh_family, BOLD_SERIES,
534 inh_shape, Color_math},
535 {"mathcal", CMSY_FAMILY, inh_series,
536 inh_shape, Color_math},
537 {"mathfrak", EUFRAK_FAMILY, inh_series,
538 inh_shape, Color_math},
539 {"mathrm", ROMAN_FAMILY, inh_series,
540 UP_SHAPE, Color_math},
541 {"mathsf", SANS_FAMILY, inh_series,
542 inh_shape, Color_math},
543 {"mathbb", MSB_FAMILY, inh_series,
544 inh_shape, Color_math},
545 {"mathtt", TYPEWRITER_FAMILY, inh_series,
546 inh_shape, Color_math},
547 {"mathit", inh_family, inh_series,
548 ITALIC_SHAPE, Color_math},
549 {"cmex", CMEX_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"cmm", CMM_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"cmr", CMR_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"cmsy", CMSY_FAMILY, inh_series,
556 inh_shape, Color_math},
557 {"eufrak", EUFRAK_FAMILY, inh_series,
558 inh_shape, Color_math},
559 {"msa", MSA_FAMILY, inh_series,
560 inh_shape, Color_math},
561 {"msb", MSB_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"wasy", WASY_FAMILY, inh_series,
564 inh_shape, Color_math},
565 {"esint", ESINT_FAMILY, inh_series,
566 inh_shape, Color_math},
569 {"text", inh_family, inh_series,
570 inh_shape, Color_foreground},
571 {"textbf", inh_family, BOLD_SERIES,
572 inh_shape, Color_foreground},
573 {"textit", inh_family, inh_series,
574 ITALIC_SHAPE, Color_foreground},
575 {"textmd", inh_family, MEDIUM_SERIES,
576 inh_shape, Color_foreground},
577 {"textnormal", inh_family, inh_series,
578 UP_SHAPE, Color_foreground},
579 {"textrm", ROMAN_FAMILY,
580 inh_series, UP_SHAPE,Color_foreground},
581 {"textsc", inh_family, inh_series,
582 SMALLCAPS_SHAPE, Color_foreground},
583 {"textsf", SANS_FAMILY, inh_series,
584 inh_shape, Color_foreground},
585 {"textsl", inh_family, inh_series,
586 SLANTED_SHAPE, Color_foreground},
587 {"texttt", TYPEWRITER_FAMILY, inh_series,
588 inh_shape, Color_foreground},
589 {"textup", inh_family, inh_series,
590 UP_SHAPE, Color_foreground},
593 {"textipa", inh_family, inh_series,
594 inh_shape, Color_foreground},
597 {"ce", inh_family, inh_series,
598 inh_shape, Color_foreground},
599 {"cf", inh_family, inh_series,
600 inh_shape, Color_foreground},
602 // LyX internal usage
603 {"lyxtex", inh_family, inh_series,
604 UP_SHAPE, Color_latex},
605 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
606 inh_shape, Color_math},
607 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
608 inh_shape, Color_math},
609 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
610 UP_SHAPE, Color_foreground},
611 {"lyxnochange", inh_family, inh_series,
612 inh_shape, Color_foreground},
613 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
614 UP_SHAPE, Color_math},
615 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
616 ITALIC_SHAPE, Color_math},
617 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
618 ITALIC_SHAPE, Color_math}
622 fontinfo * lookupFont(docstring const & name0)
624 //lyxerr << "searching font '" << name << "'" << endl;
625 int const n = sizeof(fontinfos) / sizeof(fontinfo);
626 string name = to_utf8(name0);
627 for (int i = 0; i < n; ++i)
628 if (fontinfos[i].cmd_ == name) {
629 //lyxerr << "found '" << i << "'" << endl;
630 return fontinfos + i;
636 fontinfo * searchFont(docstring const & name)
638 fontinfo * f = lookupFont(name);
639 return f ? f : fontinfos;
640 // this should be mathnormal
641 //return searchFont("mathnormal");
645 bool isFontName(docstring const & name)
647 return lookupFont(name);
651 bool isMathFont(docstring const & name)
653 fontinfo * f = lookupFont(name);
654 return f && f->color_ == Color_math;
658 bool isTextFont(docstring const & name)
660 fontinfo * f = lookupFont(name);
661 return f && f->color_ == Color_foreground;
665 FontInfo getFont(docstring const & name)
668 augmentFont(font, name);
673 void fakeFont(docstring const & orig, docstring const & fake)
675 fontinfo * forig = searchFont(orig);
676 fontinfo * ffake = searchFont(fake);
677 if (forig && ffake) {
678 forig->family_ = ffake->family_;
679 forig->series_ = ffake->series_;
680 forig->shape_ = ffake->shape_;
681 forig->color_ = ffake->color_;
683 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
684 << to_utf8(fake) << "'" << endl;
689 void augmentFont(FontInfo & font, docstring const & name)
691 static bool initialized = false;
694 // fake fonts if necessary
695 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
696 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
697 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
698 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
700 fontinfo * info = searchFont(name);
701 if (info->family_ != inh_family)
702 font.setFamily(info->family_);
703 if (info->series_ != inh_series)
704 font.setSeries(info->series_);
705 if (info->shape_ != inh_shape)
706 font.setShape(info->shape_);
707 if (info->color_ != Color_none)
708 font.setColor(info->color_);
712 docstring asString(MathData const & ar)
721 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
723 bool quiet = pf & Parse::QUIET;
724 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
725 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
729 docstring asString(InsetMath const & inset)
738 docstring asString(MathAtom const & at)