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/Application.h"
24 #include "frontends/FontLoader.h"
25 #include "frontends/FontMetrics.h"
26 #include "frontends/Painter.h"
32 using lyx::frontend::Painter;
43 Matrix(int, double, double);
45 void transform(double &, double &);
52 Matrix::Matrix(int code, double x, double y)
54 double const cs = (code & 1) ? 0 : (1 - code);
55 double const sn = (code & 1) ? (2 - code) : 0;
63 void Matrix::transform(double & x, double & y)
65 double xx = m_[0][0] * x + m_[0][1] * y;
66 double yy = m_[1][0] * x + m_[1][1] * y;
76 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
77 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
81 double const parenthHigh[] = {
83 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
84 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
85 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
86 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
92 double const parenth[] = {
94 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
95 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
96 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
97 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
103 double const brace[] = {
105 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
106 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
107 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
108 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
109 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
110 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
111 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
116 double const arrow[] = {
118 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
119 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
121 3, 0.5000, 0.1500, 0.5000, 0.9500,
126 double const Arrow[] = {
128 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
129 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
131 3, 0.3500, 0.5000, 0.3500, 0.9500,
132 3, 0.6500, 0.5000, 0.6500, 0.9500,
137 double const udarrow[] = {
139 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
141 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
142 1, 0.5, 0.2, 0.5, 0.8,
147 double const Udarrow[] = {
149 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
151 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
152 1, 0.35, 0.2, 0.35, 0.8,
153 1, 0.65, 0.2, 0.65, 0.8,
158 double const brack[] = {
160 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
165 double const corner[] = {
167 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
172 double const angle[] = {
174 1, 0, 0.05, 0.5, 1, 1,
179 double const slash[] = {
180 1, 0.95, 0.05, 0.05, 0.95,
185 double const hline[] = {
186 1, 0.00, 0.5, 1.0, 0.5,
191 double const ddot[] = {
192 1, 0.2, 0.5, 0.3, 0.5,
193 1, 0.7, 0.5, 0.8, 0.5,
198 double const dddot[] = {
199 1, 0.1, 0.5, 0.2, 0.5,
200 1, 0.45, 0.5, 0.55, 0.5,
201 1, 0.8, 0.5, 0.9, 0.5,
206 double const hline3[] = {
208 1, 0.475, 0, 0.525, 0,
214 double const dline3[] = {
215 1, 0.1, 0.1, 0.15, 0.15,
216 1, 0.475, 0.475, 0.525, 0.525,
217 1, 0.85, 0.85, 0.9, 0.9,
222 double const hlinesmall[] = {
223 1, 0.4, 0.5, 0.6, 0.5,
228 double const ring[] = {
230 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
235 double const vert[] = {
236 1, 0.5, 0.05, 0.5, 0.95,
241 double const Vert[] = {
242 1, 0.3, 0.05, 0.3, 0.95,
243 1, 0.7, 0.05, 0.7, 0.95,
248 double const tilde[] = {
250 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
260 struct named_deco_struct {
266 named_deco_struct deco_table[] = {
268 {"widehat", angle, 3 },
269 {"widetilde", tilde, 0 },
270 {"underbar", hline, 0 },
271 {"underline", hline, 0 },
272 {"overline", hline, 0 },
273 {"underbrace", brace, 1 },
274 {"overbrace", brace, 3 },
275 {"overleftarrow", arrow, 1 },
276 {"overrightarrow", arrow, 3 },
277 {"overleftrightarrow", udarrow, 1 },
278 {"xleftarrow", arrow, 1 },
279 {"xrightarrow", arrow, 3 },
280 {"underleftarrow", arrow, 1 },
281 {"underrightarrow", arrow, 3 },
282 {"underleftrightarrow", udarrow, 1 },
289 {"lbrace", brace, 0 },
290 {"rbrace", brace, 2 },
298 {"backslash", slash, 1 },
299 {"langle", angle, 0 },
300 {"lceil", corner, 0 },
301 {"lfloor", corner, 1 },
302 {"rangle", angle, 2 },
303 {"rceil", corner, 3 },
304 {"rfloor", corner, 2 },
305 {"downarrow", arrow, 2 },
306 {"Downarrow", Arrow, 2 },
307 {"uparrow", arrow, 0 },
308 {"Uparrow", Arrow, 0 },
309 {"updownarrow", udarrow, 0 },
310 {"Updownarrow", Udarrow, 0 },
314 {"dddot", dddot, 0 },
316 {"grave", slash, 1 },
317 {"acute", slash, 0 },
318 {"tilde", tilde, 0 },
320 {"dot", hlinesmall, 0 },
321 {"check", angle, 1 },
322 {"breve", parenth, 1 },
324 {"mathring", ring, 0 },
327 {"dots", hline3, 0 },
328 {"ldots", hline3, 0 },
329 {"cdots", hline3, 0 },
330 {"vdots", hline3, 1 },
331 {"ddots", dline3, 0 },
332 {"dotsb", hline3, 0 },
333 {"dotsc", hline3, 0 },
334 {"dotsi", hline3, 0 },
335 {"dotsm", hline3, 0 },
336 {"dotso", hline3, 0 }
340 std::map<string, deco_struct> deco_list;
342 // sort the table on startup
343 class init_deco_table {
346 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
347 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
351 deco_list[p->name]= d;
356 static init_deco_table dummy;
359 deco_struct const * search_deco(string const & name)
361 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
362 return (p == deco_list.end()) ? 0 : &(p->second);
369 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
371 lyx::frontend::FontMetrics const & fm =
372 theApp->fontLoader().metrics(font);
373 dim.des = fm.descent(c);
374 dim.asc = fm.ascent(c);
375 dim.wid = fm.width(c);
379 int mathed_char_width(LyXFont const & font, unsigned char c)
381 return theApp->fontLoader().metrics(font).width(c);
385 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
387 lyx::frontend::FontMetrics const & fm =
388 theApp->fontLoader().metrics(font);
392 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
393 dim.asc = max(dim.asc, fm.ascent(*it));
394 dim.des = max(dim.des, fm.descent(*it));
397 dim.asc = fm.maxAscent();
398 dim.des = fm.maxDescent();
400 docstring ds(s.begin(), s.end());
401 dim.wid = fm.width(ds);
405 int mathed_string_width(LyXFont const & font, string const & s)
407 docstring ds(s.begin(), s.end());
408 return theApp->fontLoader().metrics(font).width(ds);
412 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
416 pi.pain.line(x + w/2, y, x + w/2, y + h,
417 LColor::cursor, Painter::line_onoffdash);
421 deco_struct const * mds = search_deco(name);
423 lyxerr << "Deco was not found. Programming error?" << endl;
424 lyxerr << "name: '" << name << "'" << endl;
428 int const n = (w < h) ? w : h;
429 int const r = mds->angle;
430 double const * d = mds->data;
432 if (h > 70 && (name == "(" || name == ")"))
436 Matrix sqmt(r, n, n);
444 for (int i = 0; d[i]; ) {
445 int code = int(d[i++]);
446 if (code & 1) { // code == 1 || code == 3
452 sqmt.transform(xx, yy);
454 mt.transform(xx, yy);
455 mt.transform(x2, y2);
457 int(x + xx + 0.5), int(y + yy + 0.5),
458 int(x + x2 + 0.5), int(y + y2 + 0.5),
463 int const n = int(d[i++]);
464 for (int j = 0; j < n; ++j) {
467 // lyxerr << ' ' << xx << ' ' << yy << ' ';
469 sqmt.transform(xx, yy);
471 mt.transform(xx, yy);
472 xp[j] = int(x + xx + 0.5);
473 yp[j] = int(y + yy + 0.5);
474 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
476 pi.pain.lines(xp, yp, n, LColor::math);
482 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
484 LyXFont f = pi.base.font;
485 f.setColor(LColor::latex);
486 docstring dstr(str.begin(), str.end());
487 pi.pain.text(x, y, dstr, f);
491 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
493 LyXFont f = pi.base.font;
494 f.setColor(LColor::foreground);
495 docstring dstr(str.begin(), str.end());
496 pi.pain.text(x, y, dstr, f);
500 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
502 lyx::frontend::FontMetrics const & fm =
503 theApp->fontLoader().metrics(font);
504 asc = fm.maxAscent();
505 des = fm.maxDescent();
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 (!theApp->fontLoader().available(getFont("mathfrak")))
669 fakeFont("mathfrak", "lyxfakefrak");
670 if (!theApp->fontLoader().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(InsetMath const & inset)
702 std::ostringstream os;
709 string asString(MathAtom const & at)
711 std::ostringstream os;