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"
16 #include "math_data.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"
27 #include "support/std_sstream.h"
39 Matrix(int, double, double);
41 void transform(double &, double &);
48 Matrix::Matrix(int code, double x, double y)
50 double const cs = (code & 1) ? 0 : (1 - code);
51 double const sn = (code & 1) ? (2 - code) : 0;
59 void Matrix::transform(double & x, double & y)
61 double xx = m_[0][0] * x + m_[0][1] * y;
62 double yy = m_[1][0] * x + m_[1][1] * y;
72 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
73 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
77 double const parenthHigh[] = {
79 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
80 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
81 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
82 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
88 double const parenth[] = {
90 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
91 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
92 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
93 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
99 double const brace[] = {
101 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
102 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
103 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
104 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
105 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
106 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
107 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
112 double const arrow[] = {
114 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
115 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
117 3, 0.5000, 0.1500, 0.5000, 0.9500,
122 double const Arrow[] = {
124 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
125 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
127 3, 0.3500, 0.5000, 0.3500, 0.9500,
128 3, 0.6500, 0.5000, 0.6500, 0.9500,
133 double const udarrow[] = {
135 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
137 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
138 1, 0.5, 0.2, 0.5, 0.8,
143 double const Udarrow[] = {
145 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
147 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
148 1, 0.35, 0.2, 0.35, 0.8,
149 1, 0.65, 0.2, 0.65, 0.8,
154 double const brack[] = {
156 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
161 double const corner[] = {
163 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
168 double const angle[] = {
170 1, 0, 0.05, 0.5, 1, 1,
175 double const slash[] = {
176 1, 0.95, 0.05, 0.05, 0.95,
181 double const hline[] = {
182 1, 0.00, 0.5, 1.0, 0.5,
187 double const ddot[] = {
188 1, 0.2, 0.5, 0.3, 0.5,
189 1, 0.7, 0.5, 0.8, 0.5,
194 double const dddot[] = {
195 1, 0.1, 0.5, 0.2, 0.5,
196 1, 0.45, 0.5, 0.55, 0.5,
197 1, 0.8, 0.5, 0.9, 0.5,
202 double const hline3[] = {
204 1, 0.475, 0, 0.525, 0,
210 double const dline3[] = {
211 1, 0.1, 0.1, 0.15, 0.15,
212 1, 0.475, 0.475, 0.525, 0.525,
213 1, 0.85, 0.85, 0.9, 0.9,
218 double const hlinesmall[] = {
219 1, 0.4, 0.5, 0.6, 0.5,
224 double const ring[] = {
226 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
231 double const vert[] = {
232 1, 0.5, 0.05, 0.5, 0.95,
237 double const Vert[] = {
238 1, 0.3, 0.05, 0.3, 0.95,
239 1, 0.7, 0.05, 0.7, 0.95,
244 double const tilde[] = {
246 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
256 struct named_deco_struct {
262 named_deco_struct deco_table[] = {
264 {"widehat", angle, 3 },
265 {"widetilde", tilde, 0 },
266 {"underbar", hline, 0 },
267 {"underline", hline, 0 },
268 {"overline", hline, 0 },
269 {"underbrace", brace, 1 },
270 {"overbrace", brace, 3 },
271 {"overleftarrow", arrow, 1 },
272 {"overrightarrow", arrow, 3 },
273 {"overleftrightarrow", udarrow, 1 },
274 {"xleftarrow", arrow, 1 },
275 {"xrightarrow", arrow, 3 },
276 {"underleftarrow", arrow, 1 },
277 {"underrightarrow", arrow, 3 },
278 {"underleftrightarrow", udarrow, 1 },
292 {"backslash", slash, 1 },
293 {"langle", angle, 0 },
294 {"lceil", corner, 0 },
295 {"lfloor", corner, 1 },
296 {"rangle", angle, 2 },
297 {"rceil", corner, 3 },
298 {"rfloor", corner, 2 },
299 {"downarrow", arrow, 2 },
300 {"Downarrow", Arrow, 2 },
301 {"uparrow", arrow, 0 },
302 {"Uparrow", Arrow, 0 },
303 {"updownarrow", udarrow, 0 },
304 {"Updownarrow", Udarrow, 0 },
308 {"dddot", dddot, 0 },
310 {"grave", slash, 1 },
311 {"acute", slash, 0 },
312 {"tilde", tilde, 0 },
314 {"dot", hlinesmall, 0 },
315 {"check", angle, 1 },
316 {"breve", parenth, 1 },
318 {"mathring", ring, 0 },
321 {"dots", hline3, 0 },
322 {"ldots", hline3, 0 },
323 {"cdots", hline3, 0 },
324 {"vdots", hline3, 1 },
325 {"ddots", dline3, 0 },
326 {"dotsb", hline3, 0 },
327 {"dotsc", hline3, 0 },
328 {"dotsi", hline3, 0 },
329 {"dotsm", hline3, 0 },
330 {"dotso", hline3, 0 }
334 std::map<string, deco_struct> deco_list;
336 // sort the table on startup
337 struct init_deco_table {
339 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
340 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
344 deco_list[p->name]= d;
349 static init_deco_table dummy;
352 deco_struct const * search_deco(string const & name)
354 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
355 return (p == deco_list.end()) ? 0 : &(p->second);
362 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
364 dim.des = font_metrics::descent(c, font);
365 dim.asc = font_metrics::ascent(c, font);
366 dim.wid = mathed_char_width(font, c);
370 int mathed_char_ascent(LyXFont const & font, unsigned char c)
372 return font_metrics::ascent(c, font);
376 int mathed_char_descent(LyXFont const & font, unsigned char c)
378 return font_metrics::descent(c, font);
382 int mathed_char_width(LyXFont const & font, unsigned char c)
384 return font_metrics::width(c, font);
388 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
393 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
394 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
395 dim.des = max(dim.des, font_metrics::descent(*it, font));
398 dim.asc = font_metrics::maxAscent(font);
399 dim.des = font_metrics::maxDescent(font);
401 dim.wid = font_metrics::width(s, font);
405 int mathed_string_width(LyXFont const & font, string const & s)
407 return font_metrics::width(s, font);
411 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
415 pi.pain.line(x + w/2, y, x + w/2, y + h,
416 LColor::cursor, Painter::line_onoffdash);
420 deco_struct const * mds = search_deco(name);
422 lyxerr << "Deco was not found. Programming error?" << endl;
423 lyxerr << "name: '" << name << "'" << endl;
427 int const n = (w < h) ? w : h;
428 int const r = mds->angle;
429 double const * d = mds->data;
431 if (h > 70 && (name == "(" || name == ")"))
435 Matrix sqmt(r, n, n);
443 for (int i = 0; d[i]; ) {
444 int code = int(d[i++]);
445 if (code & 1) { // code == 1 || code == 3
451 sqmt.transform(xx, yy);
453 mt.transform(xx, yy);
454 mt.transform(x2, y2);
456 int(x + xx + 0.5), int(y + yy + 0.5),
457 int(x + x2 + 0.5), int(y + y2 + 0.5),
462 int const n = int(d[i++]);
463 for (int j = 0; j < n; ++j) {
466 // lyxerr << ' ' << xx << ' ' << yy << ' ';
468 sqmt.transform(xx, yy);
470 mt.transform(xx, yy);
471 xp[j] = int(x + xx + 0.5);
472 yp[j] = int(y + yy + 0.5);
473 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
475 pi.pain.lines(xp, yp, n, LColor::math);
481 // In the future maybe we use a better fonts renderer
482 void drawStr(PainterInfo & pi, LyXFont const & font,
483 int x, int y, string const & str)
485 pi.pain.text(x, y, str, font);
489 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
491 LyXFont f = pi.base.font;
492 f.setColor(LColor::latex);
493 pi.pain.text(x, y, str, f);
497 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
499 LyXFont f = pi.base.font;
500 f.setColor(LColor::foreground);
501 pi.pain.text(x, y, str, f);
505 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
507 pi.pain.text(x, y, c, font);
511 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
513 asc = font_metrics::maxAscent(font);
514 des = font_metrics::maxDescent(font);
520 LyXFont::FONT_FAMILY family_;
521 LyXFont::FONT_SERIES series_;
522 LyXFont::FONT_SHAPE shape_;
523 LColor::color color_;
527 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
528 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
529 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
532 // mathnormal should be the first, otherwise the fallback further down
534 fontinfo fontinfos[] = {
536 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
537 LyXFont::ITALIC_SHAPE, LColor::math},
538 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
539 inh_shape, LColor::math},
540 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
545 LyXFont::UP_SHAPE, LColor::math},
546 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
549 inh_shape, LColor::math},
550 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"mathit", inh_family, inh_series,
553 LyXFont::ITALIC_SHAPE, LColor::math},
554 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
555 inh_shape, LColor::none},
556 {"cmm", LyXFont::CMM_FAMILY, inh_series,
557 inh_shape, LColor::none},
558 {"cmr", LyXFont::CMR_FAMILY, inh_series,
559 inh_shape, LColor::none},
560 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
561 inh_shape, LColor::none},
562 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
563 inh_shape, LColor::none},
564 {"msa", LyXFont::MSA_FAMILY, inh_series,
565 inh_shape, LColor::none},
566 {"msb", LyXFont::MSB_FAMILY, inh_series,
567 inh_shape, LColor::none},
568 {"wasy", LyXFont::WASY_FAMILY, inh_series,
569 inh_shape, LColor::none},
572 {"text", inh_family, inh_series,
573 inh_shape, LColor::foreground},
574 {"textbf", inh_family, LyXFont::BOLD_SERIES,
575 inh_shape, LColor::foreground},
576 {"textit", inh_family, inh_series,
577 LyXFont::ITALIC_SHAPE, LColor::foreground},
578 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
579 inh_shape, LColor::foreground},
580 {"textnormal", inh_family, inh_series,
581 LyXFont::UP_SHAPE, LColor::foreground},
582 {"textrm", LyXFont::ROMAN_FAMILY,
583 inh_series,LyXFont::UP_SHAPE,LColor::foreground},
584 {"textsc", inh_family, inh_series,
585 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
586 {"textsf", LyXFont::SANS_FAMILY, inh_series,
587 inh_shape, LColor::foreground},
588 {"textsl", inh_family, inh_series,
589 LyXFont::SLANTED_SHAPE, LColor::foreground},
590 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
591 inh_shape, LColor::foreground},
592 {"textup", inh_family, inh_series,
593 LyXFont::UP_SHAPE, LColor::foreground},
596 {"textipa", inh_family, inh_series,
597 inh_shape, LColor::foreground},
599 // LyX internal usage
600 {"lyxtex", inh_family, inh_series,
601 LyXFont::UP_SHAPE, LColor::latex},
602 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
603 LyXFont::UP_SHAPE, LColor::latex},
604 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
605 inh_shape, LColor::math},
606 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
607 inh_shape, LColor::math},
608 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
609 LyXFont::UP_SHAPE, LColor::foreground},
610 {"lyxnochange", inh_family, inh_series,
611 inh_shape, LColor::foreground},
612 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
613 LyXFont::UP_SHAPE, LColor::math},
614 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
615 LyXFont::ITALIC_SHAPE, LColor::math},
616 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
617 LyXFont::ITALIC_SHAPE, LColor::math}
621 fontinfo * lookupFont(string const & name)
623 //lyxerr << "searching font '" << name << "'" << endl;
624 int const n = sizeof(fontinfos) / sizeof(fontinfo);
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(string const & name)
636 fontinfo * f = lookupFont(name);
637 return f ? f : fontinfos;
638 // this should be mathnormal
639 //return searchFont("mathnormal");
643 bool isFontName(string const & name)
645 return lookupFont(name);
649 LyXFont getFont(string const & name)
652 augmentFont(font, name);
657 void fakeFont(string const & orig, string 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 '" << orig << "' with '"
668 << fake << "'" << endl;
673 void augmentFont(LyXFont & font, string const & name)
675 static bool initialized = false;
678 // fake fonts if necessary
679 if (!lyx_gui::font_available(getFont("mathfrak")))
680 fakeFont("mathfrak", "lyxfakefrak");
681 if (!lyx_gui::font_available(getFont("mathcal")))
682 fakeFont("mathcal", "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_ != LColor::none)
692 font.setColor(info->color_);
696 string asString(MathArray const & ar)
698 std::ostringstream os;
705 void asArray(string const & str, MathArray & ar)
707 mathed_parse_cell(ar, str);