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 },
307 {"backslash", slash, 1 },
308 {"langle", angle, 0 },
309 {"lceil", corner, 0 },
310 {"lfloor", corner, 1 },
311 {"rangle", angle, 2 },
312 {"rceil", corner, 3 },
313 {"rfloor", corner, 2 },
314 {"downarrow", arrow, 2 },
315 {"Downarrow", Arrow, 2 },
316 {"uparrow", arrow, 0 },
317 {"Uparrow", Arrow, 0 },
318 {"updownarrow", udarrow, 0 },
319 {"Updownarrow", Udarrow, 0 },
323 {"dddot", dddot, 0 },
324 {"ddddot", ddddot, 0 },
326 {"grave", slash, 1 },
327 {"acute", slash, 0 },
328 {"tilde", tilde, 0 },
330 {"dot", hlinesmall, 0 },
331 {"check", angle, 1 },
332 {"breve", parenth, 1 },
334 {"mathring", ring, 0 },
337 {"dots", hline3, 0 },
338 {"ldots", hline3, 0 },
339 {"cdots", hline3, 0 },
340 {"vdots", hline3, 1 },
341 {"ddots", dline3, 0 },
342 {"adots", dline3, 1 },
343 {"iddots", dline3, 1 },
344 {"dotsb", hline3, 0 },
345 {"dotsc", hline3, 0 },
346 {"dotsi", hline3, 0 },
347 {"dotsm", hline3, 0 },
348 {"dotso", hline3, 0 }
352 map<docstring, deco_struct> deco_list;
354 // sort the table on startup
355 class init_deco_table {
358 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
359 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
363 deco_list[from_ascii(p->name)] = d;
368 static init_deco_table dummy;
371 deco_struct const * search_deco(docstring const & name)
373 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
374 return p == deco_list.end() ? 0 : &(p->second);
381 int mathed_char_width(FontInfo const & font, char_type c)
383 return theFontMetrics(font).width(c);
387 int mathed_char_kerning(FontInfo const & font, char_type c)
389 frontend::FontMetrics const & fm = theFontMetrics(font);
390 return fm.rbearing(c) - fm.width(c);
394 void mathed_string_dim(FontInfo const & font,
398 frontend::FontMetrics const & fm = theFontMetrics(font);
401 for (docstring::const_iterator it = s.begin();
404 dim.asc = max(dim.asc, fm.ascent(*it));
405 dim.des = max(dim.des, fm.descent(*it));
407 dim.wid = fm.width(s);
411 int mathed_string_width(FontInfo const & font, docstring const & s)
413 return theFontMetrics(font).width(s);
417 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
418 docstring const & name)
421 pi.pain.line(x + w/2, y, x + w/2, y + h,
422 Color_cursor, Painter::line_onoffdash);
426 deco_struct const * mds = search_deco(name);
428 lyxerr << "Deco was not found. Programming error?" << endl;
429 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
433 int const n = (w < h) ? w : h;
434 int const r = mds->angle;
435 double const * d = mds->data;
437 if (h > 70 && (name == "(" || name == ")"))
441 Matrix sqmt(r, n, n);
449 for (int i = 0; d[i]; ) {
450 int code = int(d[i++]);
451 if (code & 1) { // code == 1 || code == 3
457 sqmt.transform(xx, yy);
459 mt.transform(xx, yy);
460 mt.transform(x2, y2);
462 int(x + xx + 0.5), int(y + yy + 0.5),
463 int(x + x2 + 0.5), int(y + y2 + 0.5),
468 int const n = int(d[i++]);
469 for (int j = 0; j < n; ++j) {
472 // lyxerr << ' ' << xx << ' ' << yy << ' ';
474 sqmt.transform(xx, yy);
476 mt.transform(xx, yy);
477 xp[j] = int(x + xx + 0.5);
478 yp[j] = int(y + yy + 0.5);
479 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
481 pi.pain.lines(xp, yp, n, Color_math);
487 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
489 FontInfo f = pi.base.font;
490 f.setColor(Color_latex);
491 pi.pain.text(x, y, str, f);
495 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
497 FontInfo f = pi.base.font;
498 f.setColor(Color_foreground);
499 pi.pain.text(x, y, str, f);
503 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
505 frontend::FontMetrics const & fm = theFontMetrics(font);
506 asc = fm.maxAscent();
507 des = fm.maxDescent();
520 FontFamily const inh_family = INHERIT_FAMILY;
521 FontSeries const inh_series = INHERIT_SERIES;
522 FontShape const inh_shape = INHERIT_SHAPE;
525 // mathnormal should be the first, otherwise the fallback further down
527 fontinfo fontinfos[] = {
529 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
530 ITALIC_SHAPE, Color_math},
531 {"mathbf", inh_family, BOLD_SERIES,
532 inh_shape, Color_math},
533 {"mathcal", CMSY_FAMILY, inh_series,
534 inh_shape, Color_math},
535 {"mathfrak", EUFRAK_FAMILY, inh_series,
536 inh_shape, Color_math},
537 {"mathrm", ROMAN_FAMILY, inh_series,
538 UP_SHAPE, Color_math},
539 {"mathsf", SANS_FAMILY, inh_series,
540 inh_shape, Color_math},
541 {"mathbb", MSB_FAMILY, inh_series,
542 inh_shape, Color_math},
543 {"mathtt", TYPEWRITER_FAMILY, inh_series,
544 inh_shape, Color_math},
545 {"mathit", inh_family, inh_series,
546 ITALIC_SHAPE, Color_math},
547 {"cmex", CMEX_FAMILY, inh_series,
548 inh_shape, Color_math},
549 {"cmm", CMM_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"cmr", CMR_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"cmsy", CMSY_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"eufrak", EUFRAK_FAMILY, inh_series,
556 inh_shape, Color_math},
557 {"msa", MSA_FAMILY, inh_series,
558 inh_shape, Color_math},
559 {"msb", MSB_FAMILY, inh_series,
560 inh_shape, Color_math},
561 {"wasy", WASY_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"esint", ESINT_FAMILY, inh_series,
564 inh_shape, Color_math},
567 {"text", inh_family, inh_series,
568 inh_shape, Color_foreground},
569 {"textbf", inh_family, BOLD_SERIES,
570 inh_shape, Color_foreground},
571 {"textit", inh_family, inh_series,
572 ITALIC_SHAPE, Color_foreground},
573 {"textmd", inh_family, MEDIUM_SERIES,
574 inh_shape, Color_foreground},
575 {"textnormal", inh_family, inh_series,
576 UP_SHAPE, Color_foreground},
577 {"textrm", ROMAN_FAMILY,
578 inh_series, UP_SHAPE,Color_foreground},
579 {"textsc", inh_family, inh_series,
580 SMALLCAPS_SHAPE, Color_foreground},
581 {"textsf", SANS_FAMILY, inh_series,
582 inh_shape, Color_foreground},
583 {"textsl", inh_family, inh_series,
584 SLANTED_SHAPE, Color_foreground},
585 {"texttt", TYPEWRITER_FAMILY, inh_series,
586 inh_shape, Color_foreground},
587 {"textup", inh_family, inh_series,
588 UP_SHAPE, Color_foreground},
591 {"textipa", inh_family, inh_series,
592 inh_shape, Color_foreground},
595 {"ce", inh_family, inh_series,
596 inh_shape, Color_foreground},
597 {"cf", inh_family, inh_series,
598 inh_shape, Color_foreground},
600 // LyX internal usage
601 {"lyxtex", inh_family, inh_series,
602 UP_SHAPE, Color_latex},
603 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
604 inh_shape, Color_math},
605 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
606 inh_shape, Color_math},
607 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
608 UP_SHAPE, Color_foreground},
609 {"lyxnochange", inh_family, inh_series,
610 inh_shape, Color_foreground},
611 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
612 UP_SHAPE, Color_math},
613 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
614 ITALIC_SHAPE, Color_math},
615 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
616 ITALIC_SHAPE, Color_math}
620 fontinfo * lookupFont(docstring const & name0)
622 //lyxerr << "searching font '" << name << "'" << endl;
623 int const n = sizeof(fontinfos) / sizeof(fontinfo);
624 string name = to_utf8(name0);
625 for (int i = 0; i < n; ++i)
626 if (fontinfos[i].cmd_ == name) {
627 //lyxerr << "found '" << i << "'" << endl;
628 return fontinfos + i;
634 fontinfo * searchFont(docstring const & name)
636 fontinfo * f = lookupFont(name);
637 return f ? f : fontinfos;
638 // this should be mathnormal
639 //return searchFont("mathnormal");
643 bool isFontName(docstring const & name)
645 return lookupFont(name);
649 FontInfo getFont(docstring const & name)
652 augmentFont(font, name);
657 void fakeFont(docstring const & orig, docstring const & fake)
659 fontinfo * forig = searchFont(orig);
660 fontinfo * ffake = searchFont(fake);
661 if (forig && ffake) {
662 forig->family_ = ffake->family_;
663 forig->series_ = ffake->series_;
664 forig->shape_ = ffake->shape_;
665 forig->color_ = ffake->color_;
667 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
668 << to_utf8(fake) << "'" << endl;
673 void augmentFont(FontInfo & font, docstring const & name)
675 static bool initialized = false;
678 // fake fonts if necessary
679 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
680 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
681 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
682 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
684 fontinfo * info = searchFont(name);
685 if (info->family_ != inh_family)
686 font.setFamily(info->family_);
687 if (info->series_ != inh_series)
688 font.setSeries(info->series_);
689 if (info->shape_ != inh_shape)
690 font.setShape(info->shape_);
691 if (info->color_ != Color_none)
692 font.setColor(info->color_);
696 docstring asString(MathData const & ar)
705 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
707 bool quiet = pf & Parse::QUIET;
708 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
709 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
713 docstring asString(InsetMath const & inset)
722 docstring asString(MathAtom const & at)