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 "InsetMath.h"
16 #include "MathParser.h"
17 #include "MathStream.h"
18 #include "MathSupport.h"
22 #include "frontends/FontLoader.h"
23 #include "frontends/FontMetrics.h"
24 #include "frontends/Painter.h"
32 using frontend::Painter;
43 Matrix(int, double, double);
45 void transform(double &, double &);
52 Matrix::Matrix(int code, double x, double y)
54 double const cs = (code & 1) ? 0 : (1 - code);
55 double const sn = (code & 1) ? (2 - code) : 0;
63 void Matrix::transform(double & x, double & y)
65 double xx = m_[0][0] * x + m_[0][1] * y;
66 double yy = m_[1][0] * x + m_[1][1] * y;
76 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
81 double const parenthHigh[] = {
83 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
92 double const parenth[] = {
94 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
103 double const brace[] = {
105 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
116 double const arrow[] = {
118 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
121 3, 0.5000, 0.1500, 0.5000, 0.9500,
126 double const Arrow[] = {
128 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
131 3, 0.3500, 0.5000, 0.3500, 0.9500,
132 3, 0.6500, 0.5000, 0.6500, 0.9500,
137 double const udarrow[] = {
139 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
141 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
142 1, 0.5, 0.2, 0.5, 0.8,
147 double const Udarrow[] = {
149 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
151 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
152 1, 0.35, 0.2, 0.35, 0.8,
153 1, 0.65, 0.2, 0.65, 0.8,
158 double const brack[] = {
160 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
165 double const corner[] = {
167 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
172 double const angle[] = {
174 1, 0, 0.05, 0.5, 1, 1,
179 double const slash[] = {
180 1, 0.95, 0.05, 0.05, 0.95,
185 double const hline[] = {
186 1, 0.00, 0.5, 1.0, 0.5,
191 double const ddot[] = {
192 1, 0.2, 0.5, 0.3, 0.5,
193 1, 0.7, 0.5, 0.8, 0.5,
198 double const dddot[] = {
199 1, 0.1, 0.5, 0.2, 0.5,
200 1, 0.45, 0.5, 0.55, 0.5,
201 1, 0.8, 0.5, 0.9, 0.5,
206 double const hline3[] = {
208 1, 0.475, 0, 0.525, 0,
214 double const dline3[] = {
215 1, 0.1, 0.1, 0.15, 0.15,
216 1, 0.475, 0.475, 0.525, 0.525,
217 1, 0.85, 0.85, 0.9, 0.9,
222 double const hlinesmall[] = {
223 1, 0.4, 0.5, 0.6, 0.5,
228 double const ring[] = {
230 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
235 double const vert[] = {
236 1, 0.5, 0.05, 0.5, 0.95,
241 double const Vert[] = {
242 1, 0.3, 0.05, 0.3, 0.95,
243 1, 0.7, 0.05, 0.7, 0.95,
248 double const tilde[] = {
250 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
260 struct named_deco_struct {
266 named_deco_struct deco_table[] = {
268 {"widehat", angle, 3 },
269 {"widetilde", tilde, 0 },
270 {"underbar", hline, 0 },
271 {"underline", hline, 0 },
272 {"overline", hline, 0 },
273 {"underbrace", brace, 1 },
274 {"overbrace", brace, 3 },
275 {"overleftarrow", arrow, 1 },
276 {"overrightarrow", arrow, 3 },
277 {"overleftrightarrow", udarrow, 1 },
278 {"xleftarrow", arrow, 1 },
279 {"xrightarrow", arrow, 3 },
280 {"underleftarrow", arrow, 1 },
281 {"underrightarrow", arrow, 3 },
282 {"underleftrightarrow", udarrow, 1 },
289 {"lbrace", brace, 0 },
290 {"rbrace", brace, 2 },
295 {"slash", slash, 0 },
300 {"backslash", slash, 1 },
301 {"langle", angle, 0 },
302 {"lceil", corner, 0 },
303 {"lfloor", corner, 1 },
304 {"rangle", angle, 2 },
305 {"rceil", corner, 3 },
306 {"rfloor", corner, 2 },
307 {"downarrow", arrow, 2 },
308 {"Downarrow", Arrow, 2 },
309 {"uparrow", arrow, 0 },
310 {"Uparrow", Arrow, 0 },
311 {"updownarrow", udarrow, 0 },
312 {"Updownarrow", Udarrow, 0 },
316 {"dddot", dddot, 0 },
318 {"grave", slash, 1 },
319 {"acute", slash, 0 },
320 {"tilde", tilde, 0 },
322 {"dot", hlinesmall, 0 },
323 {"check", angle, 1 },
324 {"breve", parenth, 1 },
326 {"mathring", ring, 0 },
329 {"dots", hline3, 0 },
330 {"ldots", hline3, 0 },
331 {"cdots", hline3, 0 },
332 {"vdots", hline3, 1 },
333 {"ddots", dline3, 0 },
334 {"dotsb", hline3, 0 },
335 {"dotsc", hline3, 0 },
336 {"dotsi", hline3, 0 },
337 {"dotsm", hline3, 0 },
338 {"dotso", hline3, 0 }
342 std::map<docstring, deco_struct> deco_list;
344 // sort the table on startup
345 class init_deco_table {
348 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
349 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
353 deco_list[from_ascii(p->name)] = d;
358 static init_deco_table dummy;
361 deco_struct const * search_deco(docstring const & name)
363 std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
364 return p == deco_list.end() ? 0 : &(p->second);
371 int mathed_char_width(FontInfo const & font, char_type c)
373 return theFontMetrics(font).width(c);
377 int mathed_char_kerning(FontInfo const & font, char_type c)
379 frontend::FontMetrics const & fm = theFontMetrics(font);
380 return fm.rbearing(c) - fm.width(c);
384 void mathed_string_dim(FontInfo const & font,
388 frontend::FontMetrics const & fm = theFontMetrics(font);
391 for (docstring::const_iterator it = s.begin();
394 dim.asc = max(dim.asc, fm.ascent(*it));
395 dim.des = max(dim.des, fm.descent(*it));
397 dim.wid = fm.width(s);
401 int mathed_string_width(FontInfo const & font, docstring const & s)
403 return theFontMetrics(font).width(s);
407 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
408 docstring const & name)
411 pi.pain.line(x + w/2, y, x + w/2, y + h,
412 Color_cursor, Painter::line_onoffdash);
416 deco_struct const * mds = search_deco(name);
418 lyxerr << "Deco was not found. Programming error?" << endl;
419 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
423 int const n = (w < h) ? w : h;
424 int const r = mds->angle;
425 double const * d = mds->data;
427 if (h > 70 && (name == "(" || name == ")"))
431 Matrix sqmt(r, n, n);
439 for (int i = 0; d[i]; ) {
440 int code = int(d[i++]);
441 if (code & 1) { // code == 1 || code == 3
447 sqmt.transform(xx, yy);
449 mt.transform(xx, yy);
450 mt.transform(x2, y2);
452 int(x + xx + 0.5), int(y + yy + 0.5),
453 int(x + x2 + 0.5), int(y + y2 + 0.5),
458 int const n = int(d[i++]);
459 for (int j = 0; j < n; ++j) {
462 // lyxerr << ' ' << xx << ' ' << yy << ' ';
464 sqmt.transform(xx, yy);
466 mt.transform(xx, yy);
467 xp[j] = int(x + xx + 0.5);
468 yp[j] = int(y + yy + 0.5);
469 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
471 pi.pain.lines(xp, yp, n, Color_math);
477 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
479 FontInfo f = pi.base.font;
480 f.setColor(Color_latex);
481 pi.pain.text(x, y, str, f);
485 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
487 FontInfo f = pi.base.font;
488 f.setColor(Color_foreground);
489 pi.pain.text(x, y, str, f);
493 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
495 frontend::FontMetrics const & fm = theFontMetrics(font);
496 asc = fm.maxAscent();
497 des = fm.maxDescent();
510 FontFamily const inh_family = INHERIT_FAMILY;
511 FontSeries const inh_series = INHERIT_SERIES;
512 FontShape const inh_shape = INHERIT_SHAPE;
515 // mathnormal should be the first, otherwise the fallback further down
517 fontinfo fontinfos[] = {
519 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
520 ITALIC_SHAPE, Color_math},
521 {"mathbf", inh_family, BOLD_SERIES,
522 inh_shape, Color_math},
523 {"mathcal", CMSY_FAMILY, inh_series,
524 inh_shape, Color_math},
525 {"mathfrak", EUFRAK_FAMILY, inh_series,
526 inh_shape, Color_math},
527 {"mathrm", ROMAN_FAMILY, inh_series,
528 UP_SHAPE, Color_math},
529 {"mathsf", SANS_FAMILY, inh_series,
530 inh_shape, Color_math},
531 {"mathbb", MSB_FAMILY, inh_series,
532 inh_shape, Color_math},
533 {"mathtt", TYPEWRITER_FAMILY, inh_series,
534 inh_shape, Color_math},
535 {"mathit", inh_family, inh_series,
536 ITALIC_SHAPE, Color_math},
537 {"cmex", CMEX_FAMILY, inh_series,
538 inh_shape, Color_math},
539 {"cmm", CMM_FAMILY, inh_series,
540 inh_shape, Color_math},
541 {"cmr", CMR_FAMILY, inh_series,
542 inh_shape, Color_math},
543 {"cmsy", CMSY_FAMILY, inh_series,
544 inh_shape, Color_math},
545 {"eufrak", EUFRAK_FAMILY, inh_series,
546 inh_shape, Color_math},
547 {"msa", MSA_FAMILY, inh_series,
548 inh_shape, Color_math},
549 {"msb", MSB_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"wasy", WASY_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"esint", ESINT_FAMILY, inh_series,
554 inh_shape, Color_math},
557 {"text", inh_family, inh_series,
558 inh_shape, Color_foreground},
559 {"textbf", inh_family, BOLD_SERIES,
560 inh_shape, Color_foreground},
561 {"textit", inh_family, inh_series,
562 ITALIC_SHAPE, Color_foreground},
563 {"textmd", inh_family, MEDIUM_SERIES,
564 inh_shape, Color_foreground},
565 {"textnormal", inh_family, inh_series,
566 UP_SHAPE, Color_foreground},
567 {"textrm", ROMAN_FAMILY,
568 inh_series, UP_SHAPE,Color_foreground},
569 {"textsc", inh_family, inh_series,
570 SMALLCAPS_SHAPE, Color_foreground},
571 {"textsf", SANS_FAMILY, inh_series,
572 inh_shape, Color_foreground},
573 {"textsl", inh_family, inh_series,
574 SLANTED_SHAPE, Color_foreground},
575 {"texttt", TYPEWRITER_FAMILY, inh_series,
576 inh_shape, Color_foreground},
577 {"textup", inh_family, inh_series,
578 UP_SHAPE, Color_foreground},
581 {"textipa", inh_family, inh_series,
582 inh_shape, Color_foreground},
584 // LyX internal usage
585 {"lyxtex", inh_family, inh_series,
586 UP_SHAPE, Color_latex},
587 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
588 inh_shape, Color_math},
589 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
590 inh_shape, Color_math},
591 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
592 UP_SHAPE, Color_foreground},
593 {"lyxnochange", inh_family, inh_series,
594 inh_shape, Color_foreground},
595 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
596 UP_SHAPE, Color_math},
597 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
598 ITALIC_SHAPE, Color_math},
599 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
600 ITALIC_SHAPE, Color_math}
604 fontinfo * lookupFont(docstring const & name0)
606 //lyxerr << "searching font '" << name << "'" << endl;
607 int const n = sizeof(fontinfos) / sizeof(fontinfo);
608 std::string name = to_utf8(name0);
609 for (int i = 0; i < n; ++i)
610 if (fontinfos[i].cmd_ == name) {
611 //lyxerr << "found '" << i << "'" << endl;
612 return fontinfos + i;
618 fontinfo * searchFont(docstring const & name)
620 fontinfo * f = lookupFont(name);
621 return f ? f : fontinfos;
622 // this should be mathnormal
623 //return searchFont("mathnormal");
627 bool isFontName(docstring const & name)
629 return lookupFont(name);
633 FontInfo getFont(docstring const & name)
636 augmentFont(font, name);
641 void fakeFont(docstring const & orig, docstring const & fake)
643 fontinfo * forig = searchFont(orig);
644 fontinfo * ffake = searchFont(fake);
645 if (forig && ffake) {
646 forig->family_ = ffake->family_;
647 forig->series_ = ffake->series_;
648 forig->shape_ = ffake->shape_;
649 forig->color_ = ffake->color_;
651 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
652 << to_utf8(fake) << "'" << endl;
657 void augmentFont(FontInfo & font, docstring const & name)
659 static bool initialized = false;
662 // fake fonts if necessary
663 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
664 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
665 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
666 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
668 fontinfo * info = searchFont(name);
669 if (info->family_ != inh_family)
670 font.setFamily(info->family_);
671 if (info->series_ != inh_series)
672 font.setSeries(info->series_);
673 if (info->shape_ != inh_shape)
674 font.setShape(info->shape_);
675 if (info->color_ != Color_none)
676 font.setColor(info->color_);
680 docstring asString(MathData const & ar)
689 void asArray(docstring const & str, MathData & ar)
691 mathed_parse_cell(ar, str);
695 docstring asString(InsetMath const & inset)
704 docstring asString(MathAtom const & at)