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"
17 #include "MathMLStream.h"
18 #include "MathParser.h"
23 #include "frontends/FontLoader.h"
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
31 using lyx::frontend::Painter;
42 Matrix(int, double, double);
44 void transform(double &, double &);
51 Matrix::Matrix(int code, double x, double y)
53 double const cs = (code & 1) ? 0 : (1 - code);
54 double const sn = (code & 1) ? (2 - code) : 0;
62 void Matrix::transform(double & x, double & y)
64 double xx = m_[0][0] * x + m_[0][1] * y;
65 double yy = m_[1][0] * x + m_[1][1] * y;
75 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
76 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
80 double const parenthHigh[] = {
82 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
83 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
84 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
85 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
91 double const parenth[] = {
93 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
94 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
95 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
96 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
102 double const brace[] = {
104 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
105 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
106 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
107 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
108 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
109 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
110 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
115 double const arrow[] = {
117 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
118 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
120 3, 0.5000, 0.1500, 0.5000, 0.9500,
125 double const Arrow[] = {
127 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
128 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
130 3, 0.3500, 0.5000, 0.3500, 0.9500,
131 3, 0.6500, 0.5000, 0.6500, 0.9500,
136 double const udarrow[] = {
138 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
140 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
141 1, 0.5, 0.2, 0.5, 0.8,
146 double const Udarrow[] = {
148 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
150 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
151 1, 0.35, 0.2, 0.35, 0.8,
152 1, 0.65, 0.2, 0.65, 0.8,
157 double const brack[] = {
159 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
164 double const corner[] = {
166 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
171 double const angle[] = {
173 1, 0, 0.05, 0.5, 1, 1,
178 double const slash[] = {
179 1, 0.95, 0.05, 0.05, 0.95,
184 double const hline[] = {
185 1, 0.00, 0.5, 1.0, 0.5,
190 double const ddot[] = {
191 1, 0.2, 0.5, 0.3, 0.5,
192 1, 0.7, 0.5, 0.8, 0.5,
197 double const dddot[] = {
198 1, 0.1, 0.5, 0.2, 0.5,
199 1, 0.45, 0.5, 0.55, 0.5,
200 1, 0.8, 0.5, 0.9, 0.5,
205 double const hline3[] = {
207 1, 0.475, 0, 0.525, 0,
213 double const dline3[] = {
214 1, 0.1, 0.1, 0.15, 0.15,
215 1, 0.475, 0.475, 0.525, 0.525,
216 1, 0.85, 0.85, 0.9, 0.9,
221 double const hlinesmall[] = {
222 1, 0.4, 0.5, 0.6, 0.5,
227 double const ring[] = {
229 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
234 double const vert[] = {
235 1, 0.5, 0.05, 0.5, 0.95,
240 double const Vert[] = {
241 1, 0.3, 0.05, 0.3, 0.95,
242 1, 0.7, 0.05, 0.7, 0.95,
247 double const tilde[] = {
249 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
259 struct named_deco_struct {
265 named_deco_struct deco_table[] = {
267 {"widehat", angle, 3 },
268 {"widetilde", tilde, 0 },
269 {"underbar", hline, 0 },
270 {"underline", hline, 0 },
271 {"overline", hline, 0 },
272 {"underbrace", brace, 1 },
273 {"overbrace", brace, 3 },
274 {"overleftarrow", arrow, 1 },
275 {"overrightarrow", arrow, 3 },
276 {"overleftrightarrow", udarrow, 1 },
277 {"xleftarrow", arrow, 1 },
278 {"xrightarrow", arrow, 3 },
279 {"underleftarrow", arrow, 1 },
280 {"underrightarrow", arrow, 3 },
281 {"underleftrightarrow", udarrow, 1 },
288 {"lbrace", brace, 0 },
289 {"rbrace", brace, 2 },
297 {"backslash", slash, 1 },
298 {"langle", angle, 0 },
299 {"lceil", corner, 0 },
300 {"lfloor", corner, 1 },
301 {"rangle", angle, 2 },
302 {"rceil", corner, 3 },
303 {"rfloor", corner, 2 },
304 {"downarrow", arrow, 2 },
305 {"Downarrow", Arrow, 2 },
306 {"uparrow", arrow, 0 },
307 {"Uparrow", Arrow, 0 },
308 {"updownarrow", udarrow, 0 },
309 {"Updownarrow", Udarrow, 0 },
313 {"dddot", dddot, 0 },
315 {"grave", slash, 1 },
316 {"acute", slash, 0 },
317 {"tilde", tilde, 0 },
319 {"dot", hlinesmall, 0 },
320 {"check", angle, 1 },
321 {"breve", parenth, 1 },
323 {"mathring", ring, 0 },
326 {"dots", hline3, 0 },
327 {"ldots", hline3, 0 },
328 {"cdots", hline3, 0 },
329 {"vdots", hline3, 1 },
330 {"ddots", dline3, 0 },
331 {"dotsb", hline3, 0 },
332 {"dotsc", hline3, 0 },
333 {"dotsi", hline3, 0 },
334 {"dotsm", hline3, 0 },
335 {"dotso", hline3, 0 }
339 std::map<string, deco_struct> deco_list;
341 // sort the table on startup
342 class init_deco_table {
345 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
346 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
350 deco_list[p->name]= d;
355 static init_deco_table dummy;
358 deco_struct const * search_deco(string const & name)
360 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
361 return (p == deco_list.end()) ? 0 : &(p->second);
368 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
370 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
371 dim.des = fm.descent(c);
372 dim.asc = fm.ascent(c);
373 dim.wid = fm.width(c);
377 int mathed_char_width(LyXFont const & font, unsigned char c)
379 return theFontMetrics(font).width(c);
383 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
385 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
389 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
390 dim.asc = max(dim.asc, fm.ascent(*it));
391 dim.des = max(dim.des, fm.descent(*it));
394 dim.asc = fm.maxAscent();
395 dim.des = fm.maxDescent();
397 docstring ds(s.begin(), s.end());
398 dim.wid = fm.width(ds);
402 int mathed_string_width(LyXFont const & font, string const & s)
404 docstring ds(s.begin(), s.end());
405 return theFontMetrics(font).width(ds);
409 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
413 pi.pain.line(x + w/2, y, x + w/2, y + h,
414 LColor::cursor, Painter::line_onoffdash);
418 deco_struct const * mds = search_deco(name);
420 lyxerr << "Deco was not found. Programming error?" << endl;
421 lyxerr << "name: '" << 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, LColor::math);
479 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
481 LyXFont f = pi.base.font;
482 f.setColor(LColor::latex);
483 docstring dstr(str.begin(), str.end());
484 pi.pain.text(x, y, dstr, f);
488 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
490 LyXFont f = pi.base.font;
491 f.setColor(LColor::foreground);
492 docstring dstr(str.begin(), str.end());
493 pi.pain.text(x, y, dstr, f);
497 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
499 lyx::frontend::FontMetrics const & fm = theFontMetrics(font);
500 asc = fm.maxAscent();
501 des = fm.maxDescent();
507 LyXFont::FONT_FAMILY family_;
508 LyXFont::FONT_SERIES series_;
509 LyXFont::FONT_SHAPE shape_;
510 LColor::color color_;
514 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
515 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
516 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
519 // mathnormal should be the first, otherwise the fallback further down
521 fontinfo fontinfos[] = {
523 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
524 LyXFont::ITALIC_SHAPE, LColor::math},
525 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
526 inh_shape, LColor::math},
527 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
528 inh_shape, LColor::math},
529 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
530 inh_shape, LColor::math},
531 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
532 LyXFont::UP_SHAPE, LColor::math},
533 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
534 inh_shape, LColor::math},
535 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
536 inh_shape, LColor::math},
537 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
538 inh_shape, LColor::math},
539 {"mathit", inh_family, inh_series,
540 LyXFont::ITALIC_SHAPE, LColor::math},
541 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"cmm", LyXFont::CMM_FAMILY, inh_series,
544 inh_shape, LColor::math},
545 {"cmr", LyXFont::CMR_FAMILY, inh_series,
546 inh_shape, LColor::math},
547 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
550 inh_shape, LColor::math},
551 {"msa", LyXFont::MSA_FAMILY, inh_series,
552 inh_shape, LColor::math},
553 {"msb", LyXFont::MSB_FAMILY, inh_series,
554 inh_shape, LColor::math},
555 {"wasy", LyXFont::WASY_FAMILY, inh_series,
556 inh_shape, LColor::none},
559 {"text", inh_family, inh_series,
560 inh_shape, LColor::foreground},
561 {"textbf", inh_family, LyXFont::BOLD_SERIES,
562 inh_shape, LColor::foreground},
563 {"textit", inh_family, inh_series,
564 LyXFont::ITALIC_SHAPE, LColor::foreground},
565 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
566 inh_shape, LColor::foreground},
567 {"textnormal", inh_family, inh_series,
568 LyXFont::UP_SHAPE, LColor::foreground},
569 {"textrm", LyXFont::ROMAN_FAMILY,
570 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
571 {"textsc", inh_family, inh_series,
572 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
573 {"textsf", LyXFont::SANS_FAMILY, inh_series,
574 inh_shape, LColor::foreground},
575 {"textsl", inh_family, inh_series,
576 LyXFont::SLANTED_SHAPE, LColor::foreground},
577 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
578 inh_shape, LColor::foreground},
579 {"textup", inh_family, inh_series,
580 LyXFont::UP_SHAPE, LColor::foreground},
583 {"textipa", inh_family, inh_series,
584 inh_shape, LColor::foreground},
586 // LyX internal usage
587 {"lyxtex", inh_family, inh_series,
588 LyXFont::UP_SHAPE, LColor::latex},
589 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
590 inh_shape, LColor::math},
591 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
592 inh_shape, LColor::math},
593 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
594 LyXFont::UP_SHAPE, LColor::foreground},
595 {"lyxnochange", inh_family, inh_series,
596 inh_shape, LColor::foreground},
597 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
598 LyXFont::UP_SHAPE, LColor::math},
599 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
600 LyXFont::ITALIC_SHAPE, LColor::math},
601 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
602 LyXFont::ITALIC_SHAPE, LColor::math}
606 fontinfo * lookupFont(string const & name)
608 //lyxerr << "searching font '" << name << "'" << endl;
609 int const n = sizeof(fontinfos) / sizeof(fontinfo);
610 for (int i = 0; i < n; ++i)
611 if (fontinfos[i].cmd_ == name) {
612 //lyxerr << "found '" << i << "'" << endl;
613 return fontinfos + i;
619 fontinfo * searchFont(string const & name)
621 fontinfo * f = lookupFont(name);
622 return f ? f : fontinfos;
623 // this should be mathnormal
624 //return searchFont("mathnormal");
628 bool isFontName(string const & name)
630 return lookupFont(name);
634 LyXFont getFont(string const & name)
637 augmentFont(font, name);
642 void fakeFont(string const & orig, string const & fake)
644 fontinfo * forig = searchFont(orig);
645 fontinfo * ffake = searchFont(fake);
646 if (forig && ffake) {
647 forig->family_ = ffake->family_;
648 forig->series_ = ffake->series_;
649 forig->shape_ = ffake->shape_;
650 forig->color_ = ffake->color_;
652 lyxerr << "Can't fake font '" << orig << "' with '"
653 << fake << "'" << endl;
658 void augmentFont(LyXFont & font, string const & name)
660 static bool initialized = false;
663 // fake fonts if necessary
664 if (!theFontLoader().available(getFont("mathfrak")))
665 fakeFont("mathfrak", "lyxfakefrak");
666 if (!theFontLoader().available(getFont("mathcal")))
667 fakeFont("mathcal", "lyxfakecal");
669 fontinfo * info = searchFont(name);
670 if (info->family_ != inh_family)
671 font.setFamily(info->family_);
672 if (info->series_ != inh_series)
673 font.setSeries(info->series_);
674 if (info->shape_ != inh_shape)
675 font.setShape(info->shape_);
676 if (info->color_ != LColor::none)
677 font.setColor(info->color_);
681 string asString(MathArray const & ar)
683 std::ostringstream os;
690 void asArray(string const & str, MathArray & ar)
692 mathed_parse_cell(ar, str);
696 string asString(InsetMath const & inset)
698 std::ostringstream os;
705 string asString(MathAtom const & at)
707 std::ostringstream os;