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"
15 #include "math_data.h"
16 #include "math_inset.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"
40 Matrix(int, double, double);
42 void transform(double &, double &);
49 Matrix::Matrix(int code, double x, double y)
51 double const cs = (code & 1) ? 0 : (1 - code);
52 double const sn = (code & 1) ? (2 - code) : 0;
60 void Matrix::transform(double & x, double & y)
62 double xx = m_[0][0] * x + m_[0][1] * y;
63 double yy = m_[1][0] * x + m_[1][1] * y;
73 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
74 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
78 double const parenthHigh[] = {
80 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
81 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
82 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
83 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
89 double const parenth[] = {
91 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
92 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
93 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
94 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
100 double const brace[] = {
102 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
103 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
104 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
105 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
106 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
107 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
108 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
113 double const arrow[] = {
115 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
116 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
118 3, 0.5000, 0.1500, 0.5000, 0.9500,
123 double const Arrow[] = {
125 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
126 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
128 3, 0.3500, 0.5000, 0.3500, 0.9500,
129 3, 0.6500, 0.5000, 0.6500, 0.9500,
134 double const udarrow[] = {
136 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
138 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
139 1, 0.5, 0.2, 0.5, 0.8,
144 double const Udarrow[] = {
146 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
148 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
149 1, 0.35, 0.2, 0.35, 0.8,
150 1, 0.65, 0.2, 0.65, 0.8,
155 double const brack[] = {
157 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
162 double const corner[] = {
164 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
169 double const angle[] = {
171 1, 0, 0.05, 0.5, 1, 1,
176 double const slash[] = {
177 1, 0.95, 0.05, 0.05, 0.95,
182 double const hline[] = {
183 1, 0.00, 0.5, 1.0, 0.5,
188 double const ddot[] = {
189 1, 0.2, 0.5, 0.3, 0.5,
190 1, 0.7, 0.5, 0.8, 0.5,
195 double const dddot[] = {
196 1, 0.1, 0.5, 0.2, 0.5,
197 1, 0.45, 0.5, 0.55, 0.5,
198 1, 0.8, 0.5, 0.9, 0.5,
203 double const hline3[] = {
205 1, 0.475, 0, 0.525, 0,
211 double const dline3[] = {
212 1, 0.1, 0.1, 0.15, 0.15,
213 1, 0.475, 0.475, 0.525, 0.525,
214 1, 0.85, 0.85, 0.9, 0.9,
219 double const hlinesmall[] = {
220 1, 0.4, 0.5, 0.6, 0.5,
225 double const ring[] = {
227 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
232 double const vert[] = {
233 1, 0.5, 0.05, 0.5, 0.95,
238 double const Vert[] = {
239 1, 0.3, 0.05, 0.3, 0.95,
240 1, 0.7, 0.05, 0.7, 0.95,
245 double const tilde[] = {
247 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
257 struct named_deco_struct {
263 named_deco_struct deco_table[] = {
265 {"widehat", angle, 3 },
266 {"widetilde", tilde, 0 },
267 {"underbar", hline, 0 },
268 {"underline", hline, 0 },
269 {"overline", hline, 0 },
270 {"underbrace", brace, 1 },
271 {"overbrace", brace, 3 },
272 {"overleftarrow", arrow, 1 },
273 {"overrightarrow", arrow, 3 },
274 {"overleftrightarrow", udarrow, 1 },
275 {"xleftarrow", arrow, 1 },
276 {"xrightarrow", arrow, 3 },
277 {"underleftarrow", arrow, 1 },
278 {"underrightarrow", arrow, 3 },
279 {"underleftrightarrow", udarrow, 1 },
293 {"backslash", slash, 1 },
294 {"langle", angle, 0 },
295 {"lceil", corner, 0 },
296 {"lfloor", corner, 1 },
297 {"rangle", angle, 2 },
298 {"rceil", corner, 3 },
299 {"rfloor", corner, 2 },
300 {"downarrow", arrow, 2 },
301 {"Downarrow", Arrow, 2 },
302 {"uparrow", arrow, 0 },
303 {"Uparrow", Arrow, 0 },
304 {"updownarrow", udarrow, 0 },
305 {"Updownarrow", Udarrow, 0 },
309 {"dddot", dddot, 0 },
311 {"grave", slash, 1 },
312 {"acute", slash, 0 },
313 {"tilde", tilde, 0 },
315 {"dot", hlinesmall, 0 },
316 {"check", angle, 1 },
317 {"breve", parenth, 1 },
319 {"mathring", ring, 0 },
322 {"dots", hline3, 0 },
323 {"ldots", hline3, 0 },
324 {"cdots", hline3, 0 },
325 {"vdots", hline3, 1 },
326 {"ddots", dline3, 0 },
327 {"dotsb", hline3, 0 },
328 {"dotsc", hline3, 0 },
329 {"dotsi", hline3, 0 },
330 {"dotsm", hline3, 0 },
331 {"dotso", hline3, 0 }
335 std::map<string, deco_struct> deco_list;
337 // sort the table on startup
338 struct init_deco_table {
340 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
341 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
345 deco_list[p->name]= d;
350 static init_deco_table dummy;
353 deco_struct const * search_deco(string const & name)
355 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
356 return (p == deco_list.end()) ? 0 : &(p->second);
363 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
365 dim.des = font_metrics::descent(c, font);
366 dim.asc = font_metrics::ascent(c, font);
367 dim.wid = mathed_char_width(font, c);
371 int mathed_char_ascent(LyXFont const & font, unsigned char c)
373 return font_metrics::ascent(c, font);
377 int mathed_char_descent(LyXFont const & font, unsigned char c)
379 return font_metrics::descent(c, font);
383 int mathed_char_width(LyXFont const & font, unsigned char c)
385 return font_metrics::width(c, font);
389 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
394 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
395 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
396 dim.des = max(dim.des, font_metrics::descent(*it, font));
399 dim.asc = font_metrics::maxAscent(font);
400 dim.des = font_metrics::maxDescent(font);
402 dim.wid = font_metrics::width(s, font);
406 int mathed_string_width(LyXFont const & font, string const & s)
408 return font_metrics::width(s, font);
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 // In the future maybe we use a better fonts renderer
483 void drawStr(PainterInfo & pi, LyXFont const & font,
484 int x, int y, string const & str)
486 pi.pain.text(x, y, str, font);
490 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
492 LyXFont f = pi.base.font;
493 f.setColor(LColor::latex);
494 pi.pain.text(x, y, str, f);
498 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
500 LyXFont f = pi.base.font;
501 f.setColor(LColor::foreground);
502 pi.pain.text(x, y, str, f);
506 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
508 pi.pain.text(x, y, c, font);
512 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
514 asc = font_metrics::maxAscent(font);
515 des = font_metrics::maxDescent(font);
521 LyXFont::FONT_FAMILY family_;
522 LyXFont::FONT_SERIES series_;
523 LyXFont::FONT_SHAPE shape_;
524 LColor::color color_;
528 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
529 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
530 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
533 // mathnormal should be the first, otherwise the fallback further down
535 fontinfo fontinfos[] = {
537 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
538 LyXFont::ITALIC_SHAPE, LColor::math},
539 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
540 inh_shape, LColor::math},
541 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
542 inh_shape, LColor::math},
543 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
544 inh_shape, LColor::math},
545 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
546 LyXFont::UP_SHAPE, LColor::math},
547 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
548 inh_shape, LColor::math},
549 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
550 inh_shape, LColor::math},
551 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
552 inh_shape, LColor::math},
553 {"mathit", inh_family, inh_series,
554 LyXFont::ITALIC_SHAPE, LColor::math},
555 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
556 inh_shape, LColor::math},
557 {"cmm", LyXFont::CMM_FAMILY, inh_series,
558 inh_shape, LColor::math},
559 {"cmr", LyXFont::CMR_FAMILY, inh_series,
560 inh_shape, LColor::math},
561 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
562 inh_shape, LColor::math},
563 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
564 inh_shape, LColor::math},
565 {"msa", LyXFont::MSA_FAMILY, inh_series,
566 inh_shape, LColor::math},
567 {"msb", LyXFont::MSB_FAMILY, inh_series,
568 inh_shape, LColor::math},
569 {"wasy", LyXFont::WASY_FAMILY, inh_series,
570 inh_shape, LColor::none},
573 {"text", inh_family, inh_series,
574 inh_shape, LColor::foreground},
575 {"textbf", inh_family, LyXFont::BOLD_SERIES,
576 inh_shape, LColor::foreground},
577 {"textit", inh_family, inh_series,
578 LyXFont::ITALIC_SHAPE, LColor::foreground},
579 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
580 inh_shape, LColor::foreground},
581 {"textnormal", inh_family, inh_series,
582 LyXFont::UP_SHAPE, LColor::foreground},
583 {"textrm", LyXFont::ROMAN_FAMILY,
584 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
585 {"textsc", inh_family, inh_series,
586 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
587 {"textsf", LyXFont::SANS_FAMILY, inh_series,
588 inh_shape, LColor::foreground},
589 {"textsl", inh_family, inh_series,
590 LyXFont::SLANTED_SHAPE, LColor::foreground},
591 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
592 inh_shape, LColor::foreground},
593 {"textup", inh_family, inh_series,
594 LyXFont::UP_SHAPE, LColor::foreground},
597 {"textipa", inh_family, inh_series,
598 inh_shape, LColor::foreground},
600 // LyX internal usage
601 {"lyxtex", inh_family, inh_series,
602 LyXFont::UP_SHAPE, LColor::latex},
603 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
604 LyXFont::UP_SHAPE, LColor::latex},
605 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
606 inh_shape, LColor::math},
607 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
608 inh_shape, LColor::math},
609 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
610 LyXFont::UP_SHAPE, LColor::foreground},
611 {"lyxnochange", inh_family, inh_series,
612 inh_shape, LColor::foreground},
613 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
614 LyXFont::UP_SHAPE, LColor::math},
615 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
616 LyXFont::ITALIC_SHAPE, LColor::math},
617 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
618 LyXFont::ITALIC_SHAPE, LColor::math}
622 fontinfo * lookupFont(string const & name)
624 //lyxerr << "searching font '" << name << "'" << endl;
625 int const n = sizeof(fontinfos) / sizeof(fontinfo);
626 for (int i = 0; i < n; ++i)
627 if (fontinfos[i].cmd_ == name) {
628 //lyxerr << "found '" << i << "'" << endl;
629 return fontinfos + i;
635 fontinfo * searchFont(string const & name)
637 fontinfo * f = lookupFont(name);
638 return f ? f : fontinfos;
639 // this should be mathnormal
640 //return searchFont("mathnormal");
644 bool isFontName(string const & name)
646 return lookupFont(name);
650 LyXFont getFont(string const & name)
653 augmentFont(font, name);
658 void fakeFont(string const & orig, string const & fake)
660 fontinfo * forig = searchFont(orig);
661 fontinfo * ffake = searchFont(fake);
662 if (forig && ffake) {
663 forig->family_ = ffake->family_;
664 forig->series_ = ffake->series_;
665 forig->shape_ = ffake->shape_;
666 forig->color_ = ffake->color_;
668 lyxerr << "Can't fake font '" << orig << "' with '"
669 << fake << "'" << endl;
674 void augmentFont(LyXFont & font, string const & name)
676 static bool initialized = false;
679 // fake fonts if necessary
680 if (!lyx_gui::font_available(getFont("mathfrak")))
681 fakeFont("mathfrak", "lyxfakefrak");
682 if (!lyx_gui::font_available(getFont("mathcal")))
683 fakeFont("mathcal", "lyxfakecal");
685 fontinfo * info = searchFont(name);
686 if (info->family_ != inh_family)
687 font.setFamily(info->family_);
688 if (info->series_ != inh_series)
689 font.setSeries(info->series_);
690 if (info->shape_ != inh_shape)
691 font.setShape(info->shape_);
692 if (info->color_ != LColor::none)
693 font.setColor(info->color_);
697 string asString(MathArray const & ar)
699 std::ostringstream os;
706 void asArray(string const & str, MathArray & ar)
708 mathed_parse_cell(ar, str);
712 string asString(MathInset const & inset)
714 std::ostringstream os;
721 string asString(MathAtom const & at)
723 std::ostringstream os;