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", inh_family, LyXFont::MEDIUM_SERIES,
537 LyXFont::UP_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 inh_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 inh_shape, LColor::latex},
602 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
603 inh_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 {"lyxitsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
609 LyXFont::ITALIC_SHAPE, LColor::math},
610 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
611 LyXFont::UP_SHAPE, LColor::foreground},
612 {"lyxnochange", inh_family, inh_series,
613 inh_shape, LColor::foreground},
614 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
615 LyXFont::UP_SHAPE, LColor::math},
616 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
617 LyXFont::ITALIC_SHAPE, LColor::math},
618 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
619 LyXFont::ITALIC_SHAPE, LColor::math}
623 fontinfo * lookupFont(string const & name)
625 //lyxerr << "searching font '" << name << "'" << endl;
626 int const n = sizeof(fontinfos) / sizeof(fontinfo);
627 for (int i = 0; i < n; ++i)
628 if (fontinfos[i].cmd_ == name) {
629 //lyxerr << "found '" << i << "'" << endl;
630 return fontinfos + i;
636 fontinfo * searchFont(string const & name)
638 fontinfo * f = lookupFont(name);
639 return f ? f : fontinfos;
640 // this should be mathnormal
641 //return searchFont("mathnormal");
645 bool isFontName(string const & name)
647 return lookupFont(name);
651 LyXFont getFont(string const & name)
654 augmentFont(font, name);
659 void fakeFont(string const & orig, string const & fake)
661 fontinfo * forig = searchFont(orig);
662 fontinfo * ffake = searchFont(fake);
663 if (forig && ffake) {
664 forig->family_ = ffake->family_;
665 forig->series_ = ffake->series_;
666 forig->shape_ = ffake->shape_;
667 forig->color_ = ffake->color_;
669 lyxerr << "Can't fake font '" << orig << "' with '"
670 << fake << "'" << endl;
675 void augmentFont(LyXFont & font, string const & name)
677 static bool initialized = false;
680 // fake fonts if necessary
681 if (!lyx_gui::font_available(getFont("mathfrak")))
682 fakeFont("mathfrak", "lyxfakefrak");
683 if (!lyx_gui::font_available(getFont("mathcal")))
684 fakeFont("mathcal", "lyxfakecal");
686 fontinfo * info = searchFont(name);
687 if (info->family_ != inh_family)
688 font.setFamily(info->family_);
689 if (info->series_ != inh_series)
690 font.setSeries(info->series_);
691 if (info->shape_ != inh_shape)
692 font.setShape(info->shape_);
693 if (info->color_ != LColor::none)
694 font.setColor(info->color_);
698 string asString(MathArray const & ar)
700 std::ostringstream os;
707 void asArray(string const & str, MathArray & ar)
709 mathed_parse_cell(ar, str);