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 {"utilde", tilde, 0 },
297 {"lbrace", brace, 0 },
298 {"rbrace", brace, 2 },
303 {"slash", slash, 0 },
310 {"backslash", slash, 1 },
311 {"langle", angle, 0 },
312 {"lceil", corner, 0 },
313 {"lfloor", corner, 1 },
314 {"rangle", angle, 2 },
315 {"rceil", corner, 3 },
316 {"rfloor", corner, 2 },
317 {"downarrow", arrow, 2 },
318 {"Downarrow", Arrow, 2 },
319 {"uparrow", arrow, 0 },
320 {"Uparrow", Arrow, 0 },
321 {"updownarrow", udarrow, 0 },
322 {"Updownarrow", Udarrow, 0 },
326 {"dddot", dddot, 0 },
327 {"ddddot", ddddot, 0 },
329 {"grave", slash, 1 },
330 {"acute", slash, 0 },
331 {"tilde", tilde, 0 },
333 {"dot", hlinesmall, 0 },
334 {"check", angle, 1 },
335 {"breve", parenth, 1 },
337 {"mathring", ring, 0 },
340 {"dots", hline3, 0 },
341 {"ldots", hline3, 0 },
342 {"cdots", hline3, 0 },
343 {"vdots", hline3, 1 },
344 {"ddots", dline3, 0 },
345 {"adots", dline3, 1 },
346 {"iddots", dline3, 1 },
347 {"dotsb", hline3, 0 },
348 {"dotsc", hline3, 0 },
349 {"dotsi", hline3, 0 },
350 {"dotsm", hline3, 0 },
351 {"dotso", hline3, 0 }
355 map<docstring, deco_struct> deco_list;
357 // sort the table on startup
358 class init_deco_table {
361 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
362 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
366 deco_list[from_ascii(p->name)] = d;
371 static init_deco_table dummy;
374 deco_struct const * search_deco(docstring const & name)
376 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
377 return p == deco_list.end() ? 0 : &(p->second);
384 int mathed_char_width(FontInfo const & font, char_type c)
386 return theFontMetrics(font).width(c);
390 int mathed_char_kerning(FontInfo const & font, char_type c)
392 frontend::FontMetrics const & fm = theFontMetrics(font);
393 return fm.rbearing(c) - fm.width(c);
397 void mathed_string_dim(FontInfo const & font,
401 frontend::FontMetrics const & fm = theFontMetrics(font);
404 for (docstring::const_iterator it = s.begin();
407 dim.asc = max(dim.asc, fm.ascent(*it));
408 dim.des = max(dim.des, fm.descent(*it));
410 dim.wid = fm.width(s);
414 int mathed_string_width(FontInfo const & font, docstring const & s)
416 return theFontMetrics(font).width(s);
420 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
421 docstring const & name)
424 pi.pain.line(x + w/2, y, x + w/2, y + h,
425 Color_cursor, Painter::line_onoffdash);
429 deco_struct const * mds = search_deco(name);
431 lyxerr << "Deco was not found. Programming error?" << endl;
432 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
436 int const n = (w < h) ? w : h;
437 int const r = mds->angle;
438 double const * d = mds->data;
440 if (h > 70 && (name == "(" || name == ")"))
444 Matrix sqmt(r, n, n);
452 for (int i = 0; d[i]; ) {
453 int code = int(d[i++]);
454 if (code & 1) { // code == 1 || code == 3
460 sqmt.transform(xx, yy);
462 mt.transform(xx, yy);
463 mt.transform(x2, y2);
465 int(x + xx + 0.5), int(y + yy + 0.5),
466 int(x + x2 + 0.5), int(y + y2 + 0.5),
467 pi.base.font.color());
471 int const n = int(d[i++]);
472 for (int j = 0; j < n; ++j) {
475 // lyxerr << ' ' << xx << ' ' << yy << ' ';
477 sqmt.transform(xx, yy);
479 mt.transform(xx, yy);
480 xp[j] = int(x + xx + 0.5);
481 yp[j] = int(y + yy + 0.5);
482 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
484 pi.pain.lines(xp, yp, n, pi.base.font.color());
490 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
492 FontInfo f = pi.base.font;
493 f.setColor(Color_latex);
494 pi.pain.text(x, y, str, f);
498 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
500 FontInfo f = pi.base.font;
501 f.setColor(Color_foreground);
502 pi.pain.text(x, y, str, f);
506 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
508 frontend::FontMetrics const & fm = theFontMetrics(font);
509 asc = fm.maxAscent();
510 des = fm.maxDescent();
523 FontFamily const inh_family = INHERIT_FAMILY;
524 FontSeries const inh_series = INHERIT_SERIES;
525 FontShape const inh_shape = INHERIT_SHAPE;
528 // mathnormal should be the first, otherwise the fallback further down
530 fontinfo fontinfos[] = {
532 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
533 ITALIC_SHAPE, Color_math},
534 {"mathbf", inh_family, BOLD_SERIES,
535 inh_shape, Color_math},
536 {"mathcal", CMSY_FAMILY, inh_series,
537 inh_shape, Color_math},
538 {"mathfrak", EUFRAK_FAMILY, inh_series,
539 inh_shape, Color_math},
540 {"mathrm", ROMAN_FAMILY, inh_series,
541 UP_SHAPE, Color_math},
542 {"mathsf", SANS_FAMILY, inh_series,
543 inh_shape, Color_math},
544 {"mathbb", MSB_FAMILY, inh_series,
545 inh_shape, Color_math},
546 {"mathtt", TYPEWRITER_FAMILY, inh_series,
547 inh_shape, Color_math},
548 {"mathit", inh_family, inh_series,
549 ITALIC_SHAPE, Color_math},
550 {"mathscr", RSFS_FAMILY, inh_series,
551 inh_shape, Color_math},
552 {"cmex", CMEX_FAMILY, inh_series,
553 inh_shape, Color_math},
554 {"cmm", CMM_FAMILY, inh_series,
555 inh_shape, Color_math},
556 {"cmr", CMR_FAMILY, inh_series,
557 inh_shape, Color_math},
558 {"cmsy", CMSY_FAMILY, inh_series,
559 inh_shape, Color_math},
560 {"eufrak", EUFRAK_FAMILY, inh_series,
561 inh_shape, Color_math},
562 {"msa", MSA_FAMILY, inh_series,
563 inh_shape, Color_math},
564 {"msb", MSB_FAMILY, inh_series,
565 inh_shape, Color_math},
566 {"wasy", WASY_FAMILY, inh_series,
567 inh_shape, Color_math},
568 {"esint", ESINT_FAMILY, inh_series,
569 inh_shape, Color_math},
572 {"text", inh_family, inh_series,
573 inh_shape, Color_foreground},
574 {"textbf", inh_family, BOLD_SERIES,
575 inh_shape, Color_foreground},
576 {"textit", inh_family, inh_series,
577 ITALIC_SHAPE, Color_foreground},
578 {"textmd", inh_family, MEDIUM_SERIES,
579 inh_shape, Color_foreground},
580 {"textnormal", inh_family, inh_series,
581 UP_SHAPE, Color_foreground},
582 {"textrm", ROMAN_FAMILY,
583 inh_series, UP_SHAPE,Color_foreground},
584 {"textsc", inh_family, inh_series,
585 SMALLCAPS_SHAPE, Color_foreground},
586 {"textsf", SANS_FAMILY, inh_series,
587 inh_shape, Color_foreground},
588 {"textsl", inh_family, inh_series,
589 SLANTED_SHAPE, Color_foreground},
590 {"texttt", TYPEWRITER_FAMILY, inh_series,
591 inh_shape, Color_foreground},
592 {"textup", inh_family, inh_series,
593 UP_SHAPE, Color_foreground},
596 {"textipa", inh_family, inh_series,
597 inh_shape, Color_foreground},
600 {"ce", inh_family, inh_series,
601 inh_shape, Color_foreground},
602 {"cf", inh_family, inh_series,
603 inh_shape, Color_foreground},
605 // LyX internal usage
606 {"lyxtex", inh_family, inh_series,
607 UP_SHAPE, Color_latex},
608 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
609 inh_shape, Color_math},
610 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
611 inh_shape, Color_math},
612 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
613 UP_SHAPE, Color_foreground},
614 {"lyxnochange", inh_family, inh_series,
615 inh_shape, Color_foreground},
616 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
617 UP_SHAPE, Color_math},
618 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
619 ITALIC_SHAPE, Color_math},
620 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
621 ITALIC_SHAPE, Color_math}
625 fontinfo * lookupFont(docstring const & name0)
627 //lyxerr << "searching font '" << name << "'" << endl;
628 int const n = sizeof(fontinfos) / sizeof(fontinfo);
629 string name = to_utf8(name0);
630 for (int i = 0; i < n; ++i)
631 if (fontinfos[i].cmd_ == name) {
632 //lyxerr << "found '" << i << "'" << endl;
633 return fontinfos + i;
639 fontinfo * searchFont(docstring const & name)
641 fontinfo * f = lookupFont(name);
642 return f ? f : fontinfos;
643 // this should be mathnormal
644 //return searchFont("mathnormal");
648 bool isFontName(docstring const & name)
650 return lookupFont(name);
654 bool isMathFont(docstring const & name)
656 fontinfo * f = lookupFont(name);
657 return f && f->color_ == Color_math;
661 bool isTextFont(docstring const & name)
663 fontinfo * f = lookupFont(name);
664 return f && f->color_ == Color_foreground;
668 FontInfo getFont(docstring const & name)
671 augmentFont(font, name);
676 void fakeFont(docstring const & orig, docstring const & fake)
678 fontinfo * forig = searchFont(orig);
679 fontinfo * ffake = searchFont(fake);
680 if (forig && ffake) {
681 forig->family_ = ffake->family_;
682 forig->series_ = ffake->series_;
683 forig->shape_ = ffake->shape_;
684 forig->color_ = ffake->color_;
686 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
687 << to_utf8(fake) << "'" << endl;
692 void augmentFont(FontInfo & font, docstring const & name)
694 static bool initialized = false;
697 // fake fonts if necessary
698 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
699 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
700 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
701 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
703 fontinfo * info = searchFont(name);
704 if (info->family_ != inh_family)
705 font.setFamily(info->family_);
706 if (info->series_ != inh_series)
707 font.setSeries(info->series_);
708 if (info->shape_ != inh_shape)
709 font.setShape(info->shape_);
710 if (info->color_ != Color_none)
711 font.setColor(info->color_);
715 docstring asString(MathData const & ar)
724 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
726 bool quiet = pf & Parse::QUIET;
727 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
728 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
732 docstring asString(InsetMath const & inset)
741 docstring asString(MathAtom const & at)