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"
33 using frontend::Painter;
45 Matrix(int, double, double);
47 void transform(double &, double &);
54 Matrix::Matrix(int code, double x, double y)
56 double const cs = (code & 1) ? 0 : (1 - code);
57 double const sn = (code & 1) ? (2 - code) : 0;
65 void Matrix::transform(double & x, double & y)
67 double xx = m_[0][0] * x + m_[0][1] * y;
68 double yy = m_[1][0] * x + m_[1][1] * y;
78 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
79 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
83 double const parenthHigh[] = {
85 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
86 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
87 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
88 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
94 double const parenth[] = {
96 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
97 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
98 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
99 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
105 double const brace[] = {
107 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
108 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
109 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
110 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
111 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
112 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
113 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
118 double const arrow[] = {
120 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
121 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
123 3, 0.5000, 0.1500, 0.5000, 0.9500,
128 double const Arrow[] = {
130 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
131 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
133 3, 0.3500, 0.5000, 0.3500, 0.9500,
134 3, 0.6500, 0.5000, 0.6500, 0.9500,
139 double const udarrow[] = {
141 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
143 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
144 1, 0.5, 0.2, 0.5, 0.8,
149 double const Udarrow[] = {
151 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
153 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
154 1, 0.35, 0.2, 0.35, 0.8,
155 1, 0.65, 0.2, 0.65, 0.8,
160 double const brack[] = {
162 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
167 double const corner[] = {
169 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
174 double const angle[] = {
176 1, 0, 0.05, 0.5, 1, 1,
181 double const slash[] = {
182 1, 0.95, 0.05, 0.05, 0.95,
187 double const hline[] = {
188 1, 0.00, 0.5, 1.0, 0.5,
193 double const ddot[] = {
194 1, 0.2, 0.5, 0.3, 0.5,
195 1, 0.7, 0.5, 0.8, 0.5,
200 double const dddot[] = {
201 1, 0.1, 0.5, 0.2, 0.5,
202 1, 0.45, 0.5, 0.55, 0.5,
203 1, 0.8, 0.5, 0.9, 0.5,
208 double const hline3[] = {
210 1, 0.475, 0, 0.525, 0,
216 double const dline3[] = {
217 1, 0.1, 0.1, 0.15, 0.15,
218 1, 0.475, 0.475, 0.525, 0.525,
219 1, 0.85, 0.85, 0.9, 0.9,
224 double const hlinesmall[] = {
225 1, 0.4, 0.5, 0.6, 0.5,
230 double const ring[] = {
232 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
237 double const vert[] = {
238 1, 0.5, 0.05, 0.5, 0.95,
243 double const Vert[] = {
244 1, 0.3, 0.05, 0.3, 0.95,
245 1, 0.7, 0.05, 0.7, 0.95,
250 double const tilde[] = {
252 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
262 struct named_deco_struct {
268 named_deco_struct deco_table[] = {
270 {"widehat", angle, 3 },
271 {"widetilde", tilde, 0 },
272 {"underbar", hline, 0 },
273 {"underline", hline, 0 },
274 {"overline", hline, 0 },
275 {"underbrace", brace, 1 },
276 {"overbrace", brace, 3 },
277 {"overleftarrow", arrow, 1 },
278 {"overrightarrow", arrow, 3 },
279 {"overleftrightarrow", udarrow, 1 },
280 {"xleftarrow", arrow, 1 },
281 {"xrightarrow", arrow, 3 },
282 {"underleftarrow", arrow, 1 },
283 {"underrightarrow", arrow, 3 },
284 {"underleftrightarrow", udarrow, 1 },
291 {"lbrace", brace, 0 },
292 {"rbrace", brace, 2 },
300 {"backslash", slash, 1 },
301 {"langle", angle, 0 },
302 {"lceil", corner, 0 },
303 {"lfloor", corner, 1 },
304 {"rangle", angle, 2 },
305 {"rceil", corner, 3 },
306 {"rfloor", corner, 2 },
307 {"downarrow", arrow, 2 },
308 {"Downarrow", Arrow, 2 },
309 {"uparrow", arrow, 0 },
310 {"Uparrow", Arrow, 0 },
311 {"updownarrow", udarrow, 0 },
312 {"Updownarrow", Udarrow, 0 },
316 {"dddot", dddot, 0 },
318 {"grave", slash, 1 },
319 {"acute", slash, 0 },
320 {"tilde", tilde, 0 },
322 {"dot", hlinesmall, 0 },
323 {"check", angle, 1 },
324 {"breve", parenth, 1 },
326 {"mathring", ring, 0 },
329 {"dots", hline3, 0 },
330 {"ldots", hline3, 0 },
331 {"cdots", hline3, 0 },
332 {"vdots", hline3, 1 },
333 {"ddots", dline3, 0 },
334 {"dotsb", hline3, 0 },
335 {"dotsc", hline3, 0 },
336 {"dotsi", hline3, 0 },
337 {"dotsm", hline3, 0 },
338 {"dotso", hline3, 0 }
342 std::map<string, deco_struct> deco_list;
344 // sort the table on startup
345 class init_deco_table {
348 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
349 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
353 deco_list[p->name]= d;
358 static init_deco_table dummy;
361 deco_struct const * search_deco(string const & name)
363 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
364 return (p == deco_list.end()) ? 0 : &(p->second);
371 void mathed_char_dim(LyXFont const & font, char_type c, Dimension & dim)
373 frontend::FontMetrics const & fm = theFontMetrics(font);
374 dim.des = fm.descent(c);
375 dim.asc = fm.ascent(c);
376 dim.wid = fm.width(c);
380 int mathed_char_width(LyXFont const & font, char_type c)
382 return theFontMetrics(font).width(c);
386 void mathed_string_dim(LyXFont const & font,
387 vector<char_type> const & s,
390 frontend::FontMetrics const & fm = theFontMetrics(font);
393 for (vector<char_type>::const_iterator it = s.begin();
396 dim.asc = max(dim.asc, fm.ascent(*it));
397 dim.des = max(dim.des, fm.descent(*it));
399 dim.wid = fm.width(&s[0], s.size());
403 int mathed_string_width(LyXFont const & font, docstring const & s)
405 return theFontMetrics(font).width(s);
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, docstring const & str)
481 LyXFont f = pi.base.font;
482 f.setColor(LColor::latex);
483 pi.pain.text(x, y, str, f);
487 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
489 LyXFont f = pi.base.font;
490 f.setColor(LColor::foreground);
491 pi.pain.text(x, y, str, f);
495 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
497 frontend::FontMetrics const & fm = theFontMetrics(font);
498 asc = fm.maxAscent();
499 des = fm.maxDescent();
505 LyXFont::FONT_FAMILY family_;
506 LyXFont::FONT_SERIES series_;
507 LyXFont::FONT_SHAPE shape_;
508 LColor::color color_;
512 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
513 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
514 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
517 // mathnormal should be the first, otherwise the fallback further down
519 fontinfo fontinfos[] = {
521 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
522 LyXFont::ITALIC_SHAPE, LColor::math},
523 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
524 inh_shape, LColor::math},
525 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
526 inh_shape, LColor::math},
527 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
528 inh_shape, LColor::math},
529 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
530 LyXFont::UP_SHAPE, LColor::math},
531 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
532 inh_shape, LColor::math},
533 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
534 inh_shape, LColor::math},
535 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
536 inh_shape, LColor::math},
537 {"mathit", inh_family, inh_series,
538 LyXFont::ITALIC_SHAPE, LColor::math},
539 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
540 inh_shape, LColor::math},
541 {"cmm", LyXFont::CMM_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"cmr", LyXFont::CMR_FAMILY, inh_series,
544 inh_shape, LColor::math},
545 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
546 inh_shape, LColor::math},
547 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"msa", LyXFont::MSA_FAMILY, inh_series,
550 inh_shape, LColor::math},
551 {"msb", LyXFont::MSB_FAMILY, inh_series,
552 inh_shape, LColor::math},
553 {"wasy", LyXFont::WASY_FAMILY, inh_series,
554 inh_shape, LColor::none},
557 {"text", inh_family, inh_series,
558 inh_shape, LColor::foreground},
559 {"textbf", inh_family, LyXFont::BOLD_SERIES,
560 inh_shape, LColor::foreground},
561 {"textit", inh_family, inh_series,
562 LyXFont::ITALIC_SHAPE, LColor::foreground},
563 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
564 inh_shape, LColor::foreground},
565 {"textnormal", inh_family, inh_series,
566 LyXFont::UP_SHAPE, LColor::foreground},
567 {"textrm", LyXFont::ROMAN_FAMILY,
568 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
569 {"textsc", inh_family, inh_series,
570 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
571 {"textsf", LyXFont::SANS_FAMILY, inh_series,
572 inh_shape, LColor::foreground},
573 {"textsl", inh_family, inh_series,
574 LyXFont::SLANTED_SHAPE, LColor::foreground},
575 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
576 inh_shape, LColor::foreground},
577 {"textup", inh_family, inh_series,
578 LyXFont::UP_SHAPE, LColor::foreground},
581 {"textipa", inh_family, inh_series,
582 inh_shape, LColor::foreground},
584 // LyX internal usage
585 {"lyxtex", inh_family, inh_series,
586 LyXFont::UP_SHAPE, LColor::latex},
587 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
588 inh_shape, LColor::math},
589 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
590 inh_shape, LColor::math},
591 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
592 LyXFont::UP_SHAPE, LColor::foreground},
593 {"lyxnochange", inh_family, inh_series,
594 inh_shape, LColor::foreground},
595 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
596 LyXFont::UP_SHAPE, LColor::math},
597 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
598 LyXFont::ITALIC_SHAPE, LColor::math},
599 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
600 LyXFont::ITALIC_SHAPE, LColor::math}
604 fontinfo * lookupFont(string const & name)
606 //lyxerr << "searching font '" << name << "'" << endl;
607 int const n = sizeof(fontinfos) / sizeof(fontinfo);
608 for (int i = 0; i < n; ++i)
609 if (fontinfos[i].cmd_ == name) {
610 //lyxerr << "found '" << i << "'" << endl;
611 return fontinfos + i;
617 fontinfo * searchFont(string const & name)
619 fontinfo * f = lookupFont(name);
620 return f ? f : fontinfos;
621 // this should be mathnormal
622 //return searchFont("mathnormal");
626 bool isFontName(string const & name)
628 return lookupFont(name);
632 LyXFont getFont(string const & name)
635 augmentFont(font, name);
640 void fakeFont(string const & orig, string const & fake)
642 fontinfo * forig = searchFont(orig);
643 fontinfo * ffake = searchFont(fake);
644 if (forig && ffake) {
645 forig->family_ = ffake->family_;
646 forig->series_ = ffake->series_;
647 forig->shape_ = ffake->shape_;
648 forig->color_ = ffake->color_;
650 lyxerr << "Can't fake font '" << orig << "' with '"
651 << fake << "'" << endl;
656 void augmentFont(LyXFont & font, string const & name)
658 static bool initialized = false;
661 // fake fonts if necessary
662 if (!theFontLoader().available(getFont("mathfrak")))
663 fakeFont("mathfrak", "lyxfakefrak");
664 if (!theFontLoader().available(getFont("mathcal")))
665 fakeFont("mathcal", "lyxfakecal");
667 fontinfo * info = searchFont(name);
668 if (info->family_ != inh_family)
669 font.setFamily(info->family_);
670 if (info->series_ != inh_series)
671 font.setSeries(info->series_);
672 if (info->shape_ != inh_shape)
673 font.setShape(info->shape_);
674 if (info->color_ != LColor::none)
675 font.setColor(info->color_);
679 string asString(MathArray const & ar)
685 return to_utf8(os.str());
689 void asArray(docstring const & str, MathArray & ar)
691 mathed_parse_cell(ar, to_utf8(str));
695 string asString(InsetMath const & inset)
701 return to_utf8(os.str());
705 string asString(MathAtom const & at)
711 return to_utf8(os.str());