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 "support/debug.h"
23 #include "support/docstream.h"
25 #include "frontends/FontLoader.h"
26 #include "frontends/FontMetrics.h"
27 #include "frontends/Painter.h"
35 using frontend::Painter;
45 Matrix(int, double, double);
47 void transform(double &, double &);
54 Matrix::Matrix(int code, double x, double y)
56 double const cs = (code & 1) ? 0 : (1 - code);
57 double const sn = (code & 1) ? (2 - code) : 0;
65 void Matrix::transform(double & x, double & y)
67 double xx = m_[0][0] * x + m_[0][1] * y;
68 double yy = m_[1][0] * x + m_[1][1] * y;
78 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
79 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
83 double const parenthHigh[] = {
85 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
86 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
87 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
88 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
94 double const parenth[] = {
96 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
97 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
98 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
99 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
105 double const brace[] = {
107 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
108 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
109 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
110 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
111 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
112 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
113 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
118 double const arrow[] = {
120 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
121 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
123 3, 0.5000, 0.1500, 0.5000, 0.9500,
128 double const Arrow[] = {
130 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
131 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
133 3, 0.3500, 0.5000, 0.3500, 0.9500,
134 3, 0.6500, 0.5000, 0.6500, 0.9500,
139 double const udarrow[] = {
141 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
143 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
144 1, 0.5, 0.2, 0.5, 0.8,
149 double const Udarrow[] = {
151 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
153 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
154 1, 0.35, 0.2, 0.35, 0.8,
155 1, 0.65, 0.2, 0.65, 0.8,
160 double const brack[] = {
162 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
167 double const corner[] = {
169 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
174 double const angle[] = {
176 1, 0, 0.05, 0.5, 1, 1,
181 double const slash[] = {
182 1, 0.95, 0.05, 0.05, 0.95,
187 double const hline[] = {
188 1, 0.00, 0.5, 1.0, 0.5,
193 double const ddot[] = {
194 1, 0.2, 0.5, 0.3, 0.5,
195 1, 0.7, 0.5, 0.8, 0.5,
200 double const dddot[] = {
201 1, 0.1, 0.5, 0.2, 0.5,
202 1, 0.45, 0.5, 0.55, 0.5,
203 1, 0.8, 0.5, 0.9, 0.5,
208 double const hline3[] = {
210 1, 0.475, 0, 0.525, 0,
216 double const dline3[] = {
217 1, 0.1, 0.1, 0.15, 0.15,
218 1, 0.475, 0.475, 0.525, 0.525,
219 1, 0.85, 0.85, 0.9, 0.9,
224 double const hlinesmall[] = {
225 1, 0.4, 0.5, 0.6, 0.5,
230 double const ring[] = {
232 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
237 double const vert[] = {
238 1, 0.5, 0.05, 0.5, 0.95,
243 double const Vert[] = {
244 1, 0.3, 0.05, 0.3, 0.95,
245 1, 0.7, 0.05, 0.7, 0.95,
250 double const tilde[] = {
252 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
262 struct named_deco_struct {
268 named_deco_struct deco_table[] = {
270 {"widehat", angle, 3 },
271 {"widetilde", tilde, 0 },
272 {"underbar", hline, 0 },
273 {"underline", hline, 0 },
274 {"overline", hline, 0 },
275 {"underbrace", brace, 1 },
276 {"overbrace", brace, 3 },
277 {"overleftarrow", arrow, 1 },
278 {"overrightarrow", arrow, 3 },
279 {"overleftrightarrow", udarrow, 1 },
280 {"xleftarrow", arrow, 1 },
281 {"xrightarrow", arrow, 3 },
282 {"underleftarrow", arrow, 1 },
283 {"underrightarrow", arrow, 3 },
284 {"underleftrightarrow", udarrow, 1 },
291 {"lbrace", brace, 0 },
292 {"rbrace", brace, 2 },
297 {"slash", slash, 0 },
302 {"backslash", slash, 1 },
303 {"langle", angle, 0 },
304 {"lceil", corner, 0 },
305 {"lfloor", corner, 1 },
306 {"rangle", angle, 2 },
307 {"rceil", corner, 3 },
308 {"rfloor", corner, 2 },
309 {"downarrow", arrow, 2 },
310 {"Downarrow", Arrow, 2 },
311 {"uparrow", arrow, 0 },
312 {"Uparrow", Arrow, 0 },
313 {"updownarrow", udarrow, 0 },
314 {"Updownarrow", Udarrow, 0 },
318 {"dddot", dddot, 0 },
320 {"grave", slash, 1 },
321 {"acute", slash, 0 },
322 {"tilde", tilde, 0 },
324 {"dot", hlinesmall, 0 },
325 {"check", angle, 1 },
326 {"breve", parenth, 1 },
328 {"mathring", ring, 0 },
331 {"dots", hline3, 0 },
332 {"ldots", hline3, 0 },
333 {"cdots", hline3, 0 },
334 {"vdots", hline3, 1 },
335 {"ddots", dline3, 0 },
336 {"dotsb", hline3, 0 },
337 {"dotsc", hline3, 0 },
338 {"dotsi", hline3, 0 },
339 {"dotsm", hline3, 0 },
340 {"dotso", hline3, 0 }
344 std::map<docstring, deco_struct> deco_list;
346 // sort the table on startup
347 class init_deco_table {
350 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
351 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
355 deco_list[from_ascii(p->name)] = d;
360 static init_deco_table dummy;
363 deco_struct const * search_deco(docstring const & name)
365 std::map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
366 return p == deco_list.end() ? 0 : &(p->second);
373 int mathed_char_width(FontInfo const & font, char_type c)
375 return theFontMetrics(font).width(c);
379 int mathed_char_kerning(FontInfo const & font, char_type c)
381 frontend::FontMetrics const & fm = theFontMetrics(font);
382 return fm.rbearing(c) - fm.width(c);
386 void mathed_string_dim(FontInfo const & font,
390 frontend::FontMetrics const & fm = theFontMetrics(font);
393 for (docstring::const_iterator it = s.begin();
396 dim.asc = max(dim.asc, fm.ascent(*it));
397 dim.des = max(dim.des, fm.descent(*it));
399 dim.wid = fm.width(s);
403 int mathed_string_width(FontInfo const & font, docstring const & s)
405 return theFontMetrics(font).width(s);
409 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
410 docstring const & name)
413 pi.pain.line(x + w/2, y, x + w/2, y + h,
414 Color_cursor, Painter::line_onoffdash);
418 deco_struct const * mds = search_deco(name);
420 lyxerr << "Deco was not found. Programming error?" << endl;
421 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
425 int const n = (w < h) ? w : h;
426 int const r = mds->angle;
427 double const * d = mds->data;
429 if (h > 70 && (name == "(" || name == ")"))
433 Matrix sqmt(r, n, n);
441 for (int i = 0; d[i]; ) {
442 int code = int(d[i++]);
443 if (code & 1) { // code == 1 || code == 3
449 sqmt.transform(xx, yy);
451 mt.transform(xx, yy);
452 mt.transform(x2, y2);
454 int(x + xx + 0.5), int(y + yy + 0.5),
455 int(x + x2 + 0.5), int(y + y2 + 0.5),
460 int const n = int(d[i++]);
461 for (int j = 0; j < n; ++j) {
464 // lyxerr << ' ' << xx << ' ' << yy << ' ';
466 sqmt.transform(xx, yy);
468 mt.transform(xx, yy);
469 xp[j] = int(x + xx + 0.5);
470 yp[j] = int(y + yy + 0.5);
471 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
473 pi.pain.lines(xp, yp, n, Color_math);
479 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
481 FontInfo f = pi.base.font;
482 f.setColor(Color_latex);
483 pi.pain.text(x, y, str, f);
487 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
489 FontInfo f = pi.base.font;
490 f.setColor(Color_foreground);
491 pi.pain.text(x, y, str, f);
495 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
497 frontend::FontMetrics const & fm = theFontMetrics(font);
498 asc = fm.maxAscent();
499 des = fm.maxDescent();
512 FontFamily const inh_family = INHERIT_FAMILY;
513 FontSeries const inh_series = INHERIT_SERIES;
514 FontShape const inh_shape = INHERIT_SHAPE;
517 // mathnormal should be the first, otherwise the fallback further down
519 fontinfo fontinfos[] = {
521 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
522 ITALIC_SHAPE, Color_math},
523 {"mathbf", inh_family, BOLD_SERIES,
524 inh_shape, Color_math},
525 {"mathcal", CMSY_FAMILY, inh_series,
526 inh_shape, Color_math},
527 {"mathfrak", EUFRAK_FAMILY, inh_series,
528 inh_shape, Color_math},
529 {"mathrm", ROMAN_FAMILY, inh_series,
530 UP_SHAPE, Color_math},
531 {"mathsf", SANS_FAMILY, inh_series,
532 inh_shape, Color_math},
533 {"mathbb", MSB_FAMILY, inh_series,
534 inh_shape, Color_math},
535 {"mathtt", TYPEWRITER_FAMILY, inh_series,
536 inh_shape, Color_math},
537 {"mathit", inh_family, inh_series,
538 ITALIC_SHAPE, Color_math},
539 {"cmex", CMEX_FAMILY, inh_series,
540 inh_shape, Color_math},
541 {"cmm", CMM_FAMILY, inh_series,
542 inh_shape, Color_math},
543 {"cmr", CMR_FAMILY, inh_series,
544 inh_shape, Color_math},
545 {"cmsy", CMSY_FAMILY, inh_series,
546 inh_shape, Color_math},
547 {"eufrak", EUFRAK_FAMILY, inh_series,
548 inh_shape, Color_math},
549 {"msa", MSA_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"msb", MSB_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"wasy", WASY_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"esint", ESINT_FAMILY, inh_series,
556 inh_shape, Color_math},
559 {"text", inh_family, inh_series,
560 inh_shape, Color_foreground},
561 {"textbf", inh_family, BOLD_SERIES,
562 inh_shape, Color_foreground},
563 {"textit", inh_family, inh_series,
564 ITALIC_SHAPE, Color_foreground},
565 {"textmd", inh_family, MEDIUM_SERIES,
566 inh_shape, Color_foreground},
567 {"textnormal", inh_family, inh_series,
568 UP_SHAPE, Color_foreground},
569 {"textrm", ROMAN_FAMILY,
570 inh_series, UP_SHAPE,Color_foreground},
571 {"textsc", inh_family, inh_series,
572 SMALLCAPS_SHAPE, Color_foreground},
573 {"textsf", SANS_FAMILY, inh_series,
574 inh_shape, Color_foreground},
575 {"textsl", inh_family, inh_series,
576 SLANTED_SHAPE, Color_foreground},
577 {"texttt", TYPEWRITER_FAMILY, inh_series,
578 inh_shape, Color_foreground},
579 {"textup", inh_family, inh_series,
580 UP_SHAPE, Color_foreground},
583 {"textipa", inh_family, inh_series,
584 inh_shape, Color_foreground},
586 // LyX internal usage
587 {"lyxtex", inh_family, inh_series,
588 UP_SHAPE, Color_latex},
589 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
590 inh_shape, Color_math},
591 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
592 inh_shape, Color_math},
593 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
594 UP_SHAPE, Color_foreground},
595 {"lyxnochange", inh_family, inh_series,
596 inh_shape, Color_foreground},
597 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
598 UP_SHAPE, Color_math},
599 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
600 ITALIC_SHAPE, Color_math},
601 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
602 ITALIC_SHAPE, Color_math}
606 fontinfo * lookupFont(docstring const & name0)
608 //lyxerr << "searching font '" << name << "'" << endl;
609 int const n = sizeof(fontinfos) / sizeof(fontinfo);
610 std::string name = to_utf8(name0);
611 for (int i = 0; i < n; ++i)
612 if (fontinfos[i].cmd_ == name) {
613 //lyxerr << "found '" << i << "'" << endl;
614 return fontinfos + i;
620 fontinfo * searchFont(docstring const & name)
622 fontinfo * f = lookupFont(name);
623 return f ? f : fontinfos;
624 // this should be mathnormal
625 //return searchFont("mathnormal");
629 bool isFontName(docstring const & name)
631 return lookupFont(name);
635 FontInfo getFont(docstring const & name)
638 augmentFont(font, name);
643 void fakeFont(docstring const & orig, docstring const & fake)
645 fontinfo * forig = searchFont(orig);
646 fontinfo * ffake = searchFont(fake);
647 if (forig && ffake) {
648 forig->family_ = ffake->family_;
649 forig->series_ = ffake->series_;
650 forig->shape_ = ffake->shape_;
651 forig->color_ = ffake->color_;
653 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
654 << to_utf8(fake) << "'" << endl;
659 void augmentFont(FontInfo & font, docstring const & name)
661 static bool initialized = false;
664 // fake fonts if necessary
665 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
666 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
667 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
668 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
670 fontinfo * info = searchFont(name);
671 if (info->family_ != inh_family)
672 font.setFamily(info->family_);
673 if (info->series_ != inh_series)
674 font.setSeries(info->series_);
675 if (info->shape_ != inh_shape)
676 font.setShape(info->shape_);
677 if (info->color_ != Color_none)
678 font.setColor(info->color_);
682 docstring asString(MathData const & ar)
691 void asArray(docstring const & str, MathData & ar)
693 mathed_parse_cell(ar, str);
697 docstring asString(InsetMath const & inset)
706 docstring asString(MathAtom const & at)