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 "math_support.h"
15 #include "math_data.h"
16 #include "math_inset.h"
17 #include "math_mathmlstream.h"
18 #include "math_parser.h"
23 #include "frontends/Painter.h"
24 #include "frontends/font_metrics.h"
25 #include "frontends/lyx_gui.h"
30 using lyx::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 hline3[] = {
206 1, 0.475, 0, 0.525, 0,
212 double const dline3[] = {
213 1, 0.1, 0.1, 0.15, 0.15,
214 1, 0.475, 0.475, 0.525, 0.525,
215 1, 0.85, 0.85, 0.9, 0.9,
220 double const hlinesmall[] = {
221 1, 0.4, 0.5, 0.6, 0.5,
226 double const ring[] = {
228 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
233 double const vert[] = {
234 1, 0.5, 0.05, 0.5, 0.95,
239 double const Vert[] = {
240 1, 0.3, 0.05, 0.3, 0.95,
241 1, 0.7, 0.05, 0.7, 0.95,
246 double const tilde[] = {
248 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
258 struct named_deco_struct {
264 named_deco_struct deco_table[] = {
266 {"widehat", angle, 3 },
267 {"widetilde", tilde, 0 },
268 {"underbar", hline, 0 },
269 {"underline", hline, 0 },
270 {"overline", hline, 0 },
271 {"underbrace", brace, 1 },
272 {"overbrace", brace, 3 },
273 {"overleftarrow", arrow, 1 },
274 {"overrightarrow", arrow, 3 },
275 {"overleftrightarrow", udarrow, 1 },
276 {"xleftarrow", arrow, 1 },
277 {"xrightarrow", arrow, 3 },
278 {"underleftarrow", arrow, 1 },
279 {"underrightarrow", arrow, 3 },
280 {"underleftrightarrow", udarrow, 1 },
287 {"lbrace", brace, 0 },
288 {"rbrace", brace, 2 },
296 {"backslash", slash, 1 },
297 {"langle", angle, 0 },
298 {"lceil", corner, 0 },
299 {"lfloor", corner, 1 },
300 {"rangle", angle, 2 },
301 {"rceil", corner, 3 },
302 {"rfloor", corner, 2 },
303 {"downarrow", arrow, 2 },
304 {"Downarrow", Arrow, 2 },
305 {"uparrow", arrow, 0 },
306 {"Uparrow", Arrow, 0 },
307 {"updownarrow", udarrow, 0 },
308 {"Updownarrow", Udarrow, 0 },
312 {"dddot", dddot, 0 },
314 {"grave", slash, 1 },
315 {"acute", slash, 0 },
316 {"tilde", tilde, 0 },
318 {"dot", hlinesmall, 0 },
319 {"check", angle, 1 },
320 {"breve", parenth, 1 },
322 {"mathring", ring, 0 },
325 {"dots", hline3, 0 },
326 {"ldots", hline3, 0 },
327 {"cdots", hline3, 0 },
328 {"vdots", hline3, 1 },
329 {"ddots", dline3, 0 },
330 {"dotsb", hline3, 0 },
331 {"dotsc", hline3, 0 },
332 {"dotsi", hline3, 0 },
333 {"dotsm", hline3, 0 },
334 {"dotso", hline3, 0 }
338 std::map<string, deco_struct> deco_list;
340 // sort the table on startup
341 class init_deco_table {
344 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
345 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
349 deco_list[p->name]= d;
354 static init_deco_table dummy;
357 deco_struct const * search_deco(string const & name)
359 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
360 return (p == deco_list.end()) ? 0 : &(p->second);
367 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
369 dim.des = font_metrics::descent(c, font);
370 dim.asc = font_metrics::ascent(c, font);
371 dim.wid = mathed_char_width(font, c);
375 int mathed_char_ascent(LyXFont const & font, unsigned char c)
377 return font_metrics::ascent(c, font);
381 int mathed_char_descent(LyXFont const & font, unsigned char c)
383 return font_metrics::descent(c, font);
387 int mathed_char_width(LyXFont const & font, unsigned char c)
389 return font_metrics::width(c, font);
393 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
398 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
399 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
400 dim.des = max(dim.des, font_metrics::descent(*it, font));
403 dim.asc = font_metrics::maxAscent(font);
404 dim.des = font_metrics::maxDescent(font);
406 dim.wid = font_metrics::width(s, font);
410 int mathed_string_width(LyXFont const & font, string const & s)
412 return font_metrics::width(s, font);
416 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
420 pi.pain.line(x + w/2, y, x + w/2, y + h,
421 LColor::cursor, Painter::line_onoffdash);
425 deco_struct const * mds = search_deco(name);
427 lyxerr << "Deco was not found. Programming error?" << endl;
428 lyxerr << "name: '" << name << "'" << endl;
432 int const n = (w < h) ? w : h;
433 int const r = mds->angle;
434 double const * d = mds->data;
436 if (h > 70 && (name == "(" || name == ")"))
440 Matrix sqmt(r, n, n);
448 for (int i = 0; d[i]; ) {
449 int code = int(d[i++]);
450 if (code & 1) { // code == 1 || code == 3
456 sqmt.transform(xx, yy);
458 mt.transform(xx, yy);
459 mt.transform(x2, y2);
461 int(x + xx + 0.5), int(y + yy + 0.5),
462 int(x + x2 + 0.5), int(y + y2 + 0.5),
467 int const n = int(d[i++]);
468 for (int j = 0; j < n; ++j) {
471 // lyxerr << ' ' << xx << ' ' << yy << ' ';
473 sqmt.transform(xx, yy);
475 mt.transform(xx, yy);
476 xp[j] = int(x + xx + 0.5);
477 yp[j] = int(y + yy + 0.5);
478 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
480 pi.pain.lines(xp, yp, n, LColor::math);
486 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
488 LyXFont f = pi.base.font;
489 f.setColor(LColor::latex);
490 pi.pain.text(x, y, str, f);
494 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
496 LyXFont f = pi.base.font;
497 f.setColor(LColor::foreground);
498 pi.pain.text(x, y, str, f);
502 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
504 asc = font_metrics::maxAscent(font);
505 des = font_metrics::maxDescent(font);
511 LyXFont::FONT_FAMILY family_;
512 LyXFont::FONT_SERIES series_;
513 LyXFont::FONT_SHAPE shape_;
514 LColor::color color_;
518 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
519 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
520 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
523 // mathnormal should be the first, otherwise the fallback further down
525 fontinfo fontinfos[] = {
527 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
528 LyXFont::ITALIC_SHAPE, LColor::math},
529 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
530 inh_shape, LColor::math},
531 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
532 inh_shape, LColor::math},
533 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
534 inh_shape, LColor::math},
535 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
536 LyXFont::UP_SHAPE, LColor::math},
537 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
538 inh_shape, LColor::math},
539 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
540 inh_shape, LColor::math},
541 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"mathit", inh_family, inh_series,
544 LyXFont::ITALIC_SHAPE, LColor::math},
545 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
546 inh_shape, LColor::math},
547 {"cmm", LyXFont::CMM_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"cmr", LyXFont::CMR_FAMILY, inh_series,
550 inh_shape, LColor::math},
551 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
552 inh_shape, LColor::math},
553 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
554 inh_shape, LColor::math},
555 {"msa", LyXFont::MSA_FAMILY, inh_series,
556 inh_shape, LColor::math},
557 {"msb", LyXFont::MSB_FAMILY, inh_series,
558 inh_shape, LColor::math},
559 {"wasy", LyXFont::WASY_FAMILY, inh_series,
560 inh_shape, LColor::none},
563 {"text", inh_family, inh_series,
564 inh_shape, LColor::foreground},
565 {"textbf", inh_family, LyXFont::BOLD_SERIES,
566 inh_shape, LColor::foreground},
567 {"textit", inh_family, inh_series,
568 LyXFont::ITALIC_SHAPE, LColor::foreground},
569 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
570 inh_shape, LColor::foreground},
571 {"textnormal", inh_family, inh_series,
572 LyXFont::UP_SHAPE, LColor::foreground},
573 {"textrm", LyXFont::ROMAN_FAMILY,
574 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
575 {"textsc", inh_family, inh_series,
576 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
577 {"textsf", LyXFont::SANS_FAMILY, inh_series,
578 inh_shape, LColor::foreground},
579 {"textsl", inh_family, inh_series,
580 LyXFont::SLANTED_SHAPE, LColor::foreground},
581 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
582 inh_shape, LColor::foreground},
583 {"textup", inh_family, inh_series,
584 LyXFont::UP_SHAPE, LColor::foreground},
587 {"textipa", inh_family, inh_series,
588 inh_shape, LColor::foreground},
590 // LyX internal usage
591 {"lyxtex", inh_family, inh_series,
592 LyXFont::UP_SHAPE, LColor::latex},
593 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
594 inh_shape, LColor::math},
595 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
596 inh_shape, LColor::math},
597 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
598 LyXFont::UP_SHAPE, LColor::foreground},
599 {"lyxnochange", inh_family, inh_series,
600 inh_shape, LColor::foreground},
601 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
602 LyXFont::UP_SHAPE, LColor::math},
603 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
604 LyXFont::ITALIC_SHAPE, LColor::math},
605 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
606 LyXFont::ITALIC_SHAPE, LColor::math}
610 fontinfo * lookupFont(string const & name)
612 //lyxerr << "searching font '" << name << "'" << endl;
613 int const n = sizeof(fontinfos) / sizeof(fontinfo);
614 for (int i = 0; i < n; ++i)
615 if (fontinfos[i].cmd_ == name) {
616 //lyxerr << "found '" << i << "'" << endl;
617 return fontinfos + i;
623 fontinfo * searchFont(string const & name)
625 fontinfo * f = lookupFont(name);
626 return f ? f : fontinfos;
627 // this should be mathnormal
628 //return searchFont("mathnormal");
632 bool isFontName(string const & name)
634 return lookupFont(name);
638 LyXFont getFont(string const & name)
641 augmentFont(font, name);
646 void fakeFont(string const & orig, string const & fake)
648 fontinfo * forig = searchFont(orig);
649 fontinfo * ffake = searchFont(fake);
650 if (forig && ffake) {
651 forig->family_ = ffake->family_;
652 forig->series_ = ffake->series_;
653 forig->shape_ = ffake->shape_;
654 forig->color_ = ffake->color_;
656 lyxerr << "Can't fake font '" << orig << "' with '"
657 << fake << "'" << endl;
662 void augmentFont(LyXFont & font, string const & name)
664 static bool initialized = false;
667 // fake fonts if necessary
668 if (!lyx_gui::font_available(getFont("mathfrak")))
669 fakeFont("mathfrak", "lyxfakefrak");
670 if (!lyx_gui::font_available(getFont("mathcal")))
671 fakeFont("mathcal", "lyxfakecal");
673 fontinfo * info = searchFont(name);
674 if (info->family_ != inh_family)
675 font.setFamily(info->family_);
676 if (info->series_ != inh_series)
677 font.setSeries(info->series_);
678 if (info->shape_ != inh_shape)
679 font.setShape(info->shape_);
680 if (info->color_ != LColor::none)
681 font.setColor(info->color_);
685 string asString(MathArray const & ar)
687 std::ostringstream os;
694 void asArray(string const & str, MathArray & ar)
696 mathed_parse_cell(ar, str);
700 string asString(MathInset const & inset)
702 std::ostringstream os;
709 string asString(MathAtom const & at)
711 std::ostringstream os;