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 },
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 {"mathscr", RSFS_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"cmex", CMEX_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"cmm", CMM_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"cmr", CMR_FAMILY, inh_series,
556 inh_shape, Color_math},
557 {"cmsy", CMSY_FAMILY, inh_series,
558 inh_shape, Color_math},
559 {"eufrak", EUFRAK_FAMILY, inh_series,
560 inh_shape, Color_math},
561 {"msa", MSA_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"msb", MSB_FAMILY, inh_series,
564 inh_shape, Color_math},
565 {"wasy", WASY_FAMILY, inh_series,
566 inh_shape, Color_math},
567 {"esint", ESINT_FAMILY, inh_series,
568 inh_shape, Color_math},
571 {"text", inh_family, inh_series,
572 inh_shape, Color_foreground},
573 {"textbf", inh_family, BOLD_SERIES,
574 inh_shape, Color_foreground},
575 {"textit", inh_family, inh_series,
576 ITALIC_SHAPE, Color_foreground},
577 {"textmd", inh_family, MEDIUM_SERIES,
578 inh_shape, Color_foreground},
579 {"textnormal", inh_family, inh_series,
580 UP_SHAPE, Color_foreground},
581 {"textrm", ROMAN_FAMILY,
582 inh_series, UP_SHAPE,Color_foreground},
583 {"textsc", inh_family, inh_series,
584 SMALLCAPS_SHAPE, Color_foreground},
585 {"textsf", SANS_FAMILY, inh_series,
586 inh_shape, Color_foreground},
587 {"textsl", inh_family, inh_series,
588 SLANTED_SHAPE, Color_foreground},
589 {"texttt", TYPEWRITER_FAMILY, inh_series,
590 inh_shape, Color_foreground},
591 {"textup", inh_family, inh_series,
592 UP_SHAPE, Color_foreground},
595 {"textipa", inh_family, inh_series,
596 inh_shape, Color_foreground},
599 {"ce", inh_family, inh_series,
600 inh_shape, Color_foreground},
601 {"cf", inh_family, inh_series,
602 inh_shape, Color_foreground},
604 // LyX internal usage
605 {"lyxtex", inh_family, inh_series,
606 UP_SHAPE, Color_latex},
607 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
608 inh_shape, Color_math},
609 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
610 inh_shape, Color_math},
611 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
612 UP_SHAPE, Color_foreground},
613 {"lyxnochange", inh_family, inh_series,
614 inh_shape, Color_foreground},
615 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
616 UP_SHAPE, Color_math},
617 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
618 ITALIC_SHAPE, Color_math},
619 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
620 ITALIC_SHAPE, Color_math}
624 fontinfo * lookupFont(docstring const & name0)
626 //lyxerr << "searching font '" << name << "'" << endl;
627 int const n = sizeof(fontinfos) / sizeof(fontinfo);
628 string name = to_utf8(name0);
629 for (int i = 0; i < n; ++i)
630 if (fontinfos[i].cmd_ == name) {
631 //lyxerr << "found '" << i << "'" << endl;
632 return fontinfos + i;
638 fontinfo * searchFont(docstring const & name)
640 fontinfo * f = lookupFont(name);
641 return f ? f : fontinfos;
642 // this should be mathnormal
643 //return searchFont("mathnormal");
647 bool isFontName(docstring const & name)
649 return lookupFont(name);
653 bool isMathFont(docstring const & name)
655 fontinfo * f = lookupFont(name);
656 return f && f->color_ == Color_math;
660 bool isTextFont(docstring const & name)
662 fontinfo * f = lookupFont(name);
663 return f && f->color_ == Color_foreground;
667 FontInfo getFont(docstring const & name)
670 augmentFont(font, name);
675 void fakeFont(docstring const & orig, docstring const & fake)
677 fontinfo * forig = searchFont(orig);
678 fontinfo * ffake = searchFont(fake);
679 if (forig && ffake) {
680 forig->family_ = ffake->family_;
681 forig->series_ = ffake->series_;
682 forig->shape_ = ffake->shape_;
683 forig->color_ = ffake->color_;
685 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
686 << to_utf8(fake) << "'" << endl;
691 void augmentFont(FontInfo & font, docstring const & name)
693 static bool initialized = false;
696 // fake fonts if necessary
697 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
698 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
699 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
700 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
702 fontinfo * info = searchFont(name);
703 if (info->family_ != inh_family)
704 font.setFamily(info->family_);
705 if (info->series_ != inh_series)
706 font.setSeries(info->series_);
707 if (info->shape_ != inh_shape)
708 font.setShape(info->shape_);
709 if (info->color_ != Color_none)
710 font.setColor(info->color_);
714 docstring asString(MathData const & ar)
723 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
725 bool quiet = pf & Parse::QUIET;
726 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
727 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
731 docstring asString(InsetMath const & inset)
740 docstring asString(MathAtom const & at)