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_parser.h"
16 #include "math_data.h"
17 #include "frontends/Painter.h"
18 #include "frontends/font_metrics.h"
19 #include "frontends/lyx_gui.h"
21 #include "support/std_sstream.h"
22 #include "math_mathmlstream.h"
28 using std::ostringstream;
35 Matrix(int, double, double);
37 void transform(double &, double &);
44 Matrix::Matrix(int code, double x, double y)
46 double const cs = (code & 1) ? 0 : (1 - code);
47 double const sn = (code & 1) ? (2 - code) : 0;
55 void Matrix::transform(double & x, double & y)
57 double xx = m_[0][0] * x + m_[0][1] * y;
58 double yy = m_[1][0] * x + m_[1][1] * y;
68 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
69 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
73 double const parenthHigh[] = {
75 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
76 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
77 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
78 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
84 double const parenth[] = {
86 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
87 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
88 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
89 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
95 double const brace[] = {
97 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
98 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
99 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
100 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
101 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
102 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
103 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
108 double const arrow[] = {
110 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
111 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
113 3, 0.5000, 0.1500, 0.5000, 0.9500,
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.3500, 0.5000, 0.3500, 0.9500,
124 3, 0.6500, 0.5000, 0.6500, 0.9500,
129 double const udarrow[] = {
131 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
133 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
134 1, 0.5, 0.2, 0.5, 0.8,
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.35, 0.2, 0.35, 0.8,
145 1, 0.65, 0.2, 0.65, 0.8,
150 double const brack[] = {
152 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
157 double const corner[] = {
159 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
164 double const angle[] = {
166 1, 0, 0.05, 0.5, 1, 1,
171 double const slash[] = {
172 1, 0.95, 0.05, 0.05, 0.95,
177 double const hline[] = {
178 1, 0.00, 0.5, 1.0, 0.5,
183 double const ddot[] = {
184 1, 0.2, 0.5, 0.3, 0.5,
185 1, 0.7, 0.5, 0.8, 0.5,
190 double const dddot[] = {
191 1, 0.1, 0.5, 0.2, 0.5,
192 1, 0.45, 0.5, 0.55, 0.5,
193 1, 0.8, 0.5, 0.9, 0.5,
198 double const hline3[] = {
200 1, 0.475, 0, 0.525, 0,
206 double const dline3[] = {
207 1, 0.1, 0.1, 0.15, 0.15,
208 1, 0.475, 0.475, 0.525, 0.525,
209 1, 0.85, 0.85, 0.9, 0.9,
214 double const hlinesmall[] = {
215 1, 0.4, 0.5, 0.6, 0.5,
220 double const ring[] = {
222 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
227 double const vert[] = {
228 1, 0.5, 0.05, 0.5, 0.95,
233 double const Vert[] = {
234 1, 0.3, 0.05, 0.3, 0.95,
235 1, 0.7, 0.05, 0.7, 0.95,
240 double const tilde[] = {
242 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
252 struct named_deco_struct {
258 named_deco_struct deco_table[] = {
260 {"widehat", angle, 3 },
261 {"widetilde", tilde, 0 },
262 {"underbar", hline, 0 },
263 {"underline", hline, 0 },
264 {"overline", hline, 0 },
265 {"underbrace", brace, 1 },
266 {"overbrace", brace, 3 },
267 {"overleftarrow", arrow, 1 },
268 {"overrightarrow", arrow, 3 },
269 {"overleftrightarrow", udarrow, 1 },
270 {"xleftarrow", arrow, 1 },
271 {"xrightarrow", arrow, 3 },
272 {"underleftarrow", arrow, 1 },
273 {"underrightarrow", arrow, 3 },
274 {"underleftrightarrow", udarrow, 1 },
288 {"backslash", slash, 1 },
289 {"langle", angle, 0 },
290 {"lceil", corner, 0 },
291 {"lfloor", corner, 1 },
292 {"rangle", angle, 2 },
293 {"rceil", corner, 3 },
294 {"rfloor", corner, 2 },
295 {"downarrow", arrow, 2 },
296 {"Downarrow", Arrow, 2 },
297 {"uparrow", arrow, 0 },
298 {"Uparrow", Arrow, 0 },
299 {"updownarrow", udarrow, 0 },
300 {"Updownarrow", Udarrow, 0 },
304 {"dddot", dddot, 0 },
306 {"grave", slash, 1 },
307 {"acute", slash, 0 },
308 {"tilde", tilde, 0 },
310 {"dot", hlinesmall, 0 },
311 {"check", angle, 1 },
312 {"breve", parenth, 1 },
314 {"mathring", ring, 0 },
317 {"dots", hline3, 0 },
318 {"ldots", hline3, 0 },
319 {"cdots", hline3, 0 },
320 {"vdots", hline3, 1 },
321 {"ddots", dline3, 0 },
322 {"dotsb", hline3, 0 },
323 {"dotsc", hline3, 0 },
324 {"dotsi", hline3, 0 },
325 {"dotsm", hline3, 0 },
326 {"dotso", hline3, 0 }
330 std::map<string, deco_struct> deco_list;
332 // sort the table on startup
333 struct init_deco_table {
335 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
336 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
340 deco_list[p->name]= d;
345 static init_deco_table dummy;
348 deco_struct const * search_deco(string const & name)
350 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
351 return (p == deco_list.end()) ? 0 : &(p->second);
358 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
360 dim.des = font_metrics::descent(c, font);
361 dim.asc = font_metrics::ascent(c, font);
362 dim.wid = mathed_char_width(font, c);
366 int mathed_char_ascent(LyXFont const & font, unsigned char c)
368 return font_metrics::ascent(c, font);
372 int mathed_char_descent(LyXFont const & font, unsigned char c)
374 return font_metrics::descent(c, font);
378 int mathed_char_width(LyXFont const & font, unsigned char c)
380 return font_metrics::width(c, font);
384 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
389 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
390 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
391 dim.des = max(dim.des, font_metrics::descent(*it, font));
394 dim.asc = font_metrics::maxAscent(font);
395 dim.des = font_metrics::maxDescent(font);
397 dim.wid = font_metrics::width(s, font);
401 int mathed_string_width(LyXFont const & font, string const & s)
403 return font_metrics::width(s, font);
407 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
411 pi.pain.line(x + w/2, y, x + w/2, y + h,
412 LColor::cursor, Painter::line_onoffdash);
416 deco_struct const * mds = search_deco(name);
418 lyxerr << "Deco was not found. Programming error?" << endl;
419 lyxerr << "name: '" << name << "'" << endl;
423 int const n = (w < h) ? w : h;
424 int const r = mds->angle;
425 double const * d = mds->data;
427 if (h > 70 && (name == "(" || name == ")"))
431 Matrix sqmt(r, n, n);
439 for (int i = 0; d[i]; ) {
440 int code = int(d[i++]);
441 if (code & 1) { // code == 1 || code == 3
447 sqmt.transform(xx, yy);
449 mt.transform(xx, yy);
450 mt.transform(x2, y2);
452 int(x + xx + 0.5), int(y + yy + 0.5),
453 int(x + x2 + 0.5), int(y + y2 + 0.5),
458 int const n = int(d[i++]);
459 for (int j = 0; j < n; ++j) {
462 // lyxerr << ' ' << xx << ' ' << yy << ' ';
464 sqmt.transform(xx, yy);
466 mt.transform(xx, yy);
467 xp[j] = int(x + xx + 0.5);
468 yp[j] = int(y + yy + 0.5);
469 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
471 pi.pain.lines(xp, yp, n, LColor::math);
477 // In the future maybe we use a better fonts renderer
478 void drawStr(PainterInfo & pi, LyXFont const & font,
479 int x, int y, string const & str)
481 pi.pain.text(x, y, str, font);
485 void drawStrRed(PainterInfo & pi, int x, int y, string const & str)
487 LyXFont f = pi.base.font;
488 f.setColor(LColor::latex);
489 pi.pain.text(x, y, str, f);
493 void drawStrBlack(PainterInfo & pi, int x, int y, string const & str)
495 LyXFont f = pi.base.font;
496 f.setColor(LColor::foreground);
497 pi.pain.text(x, y, str, f);
501 void drawChar(PainterInfo & pi, LyXFont const & font, int x, int y, char c)
503 pi.pain.text(x, y, c, font);
507 void math_font_max_dim(LyXFont const & font, int & asc, int & des)
509 asc = font_metrics::maxAscent(font);
510 des = font_metrics::maxDescent(font);
516 LyXFont::FONT_FAMILY family_;
517 LyXFont::FONT_SERIES series_;
518 LyXFont::FONT_SHAPE shape_;
519 LColor::color color_;
523 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
524 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
525 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
528 // mathnormal should be the first, otherwise the fallback further down
530 fontinfo fontinfos[] = {
532 {"mathnormal", inh_family, LyXFont::MEDIUM_SERIES,
533 LyXFont::UP_SHAPE, LColor::math},
534 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
535 inh_shape, LColor::math},
536 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
543 inh_shape, LColor::math},
544 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
549 inh_shape, LColor::none},
550 {"cmm", LyXFont::CMM_FAMILY, inh_series,
551 inh_shape, LColor::none},
552 {"cmr", LyXFont::CMR_FAMILY, inh_series,
553 inh_shape, LColor::none},
554 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
555 inh_shape, LColor::none},
556 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
557 inh_shape, LColor::none},
558 {"msa", LyXFont::MSA_FAMILY, inh_series,
559 inh_shape, LColor::none},
560 {"msb", LyXFont::MSB_FAMILY, inh_series,
561 inh_shape, LColor::none},
562 {"wasy", LyXFont::WASY_FAMILY, inh_series,
563 inh_shape, LColor::none},
566 {"text", inh_family, inh_series,
567 inh_shape, LColor::foreground},
568 {"textbf", inh_family, LyXFont::BOLD_SERIES,
569 inh_shape, LColor::foreground},
570 {"textit", inh_family, inh_series,
571 LyXFont::ITALIC_SHAPE, LColor::foreground},
572 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
573 inh_shape, LColor::foreground},
574 {"textnormal", inh_family, inh_series,
575 LyXFont::UP_SHAPE, LColor::foreground},
576 {"textrm", LyXFont::ROMAN_FAMILY,
577 inh_series,LyXFont::UP_SHAPE,LColor::foreground},
578 {"textsc", inh_family, inh_series,
579 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
580 {"textsf", LyXFont::SANS_FAMILY, inh_series,
581 inh_shape, LColor::foreground},
582 {"textsl", inh_family, inh_series,
583 LyXFont::SLANTED_SHAPE, LColor::foreground},
584 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
585 inh_shape, LColor::foreground},
586 {"textup", inh_family, inh_series,
587 LyXFont::UP_SHAPE, LColor::foreground},
590 {"textipa", inh_family, inh_series,
591 inh_shape, LColor::foreground},
593 // LyX internal usage
594 {"lyxtex", inh_family, inh_series,
595 inh_shape, LColor::latex},
596 {"lyxert", LyXFont::TYPEWRITER_FAMILY, inh_series,
597 inh_shape, LColor::latex},
598 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
599 inh_shape, LColor::math},
600 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
601 inh_shape, LColor::math},
602 {"lyxitsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
603 LyXFont::ITALIC_SHAPE, LColor::math},
604 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
605 LyXFont::UP_SHAPE, LColor::foreground},
606 {"lyxnochange", inh_family, inh_series,
607 inh_shape, LColor::foreground},
608 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
609 LyXFont::UP_SHAPE, LColor::math},
610 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
611 LyXFont::ITALIC_SHAPE, LColor::math},
612 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
613 LyXFont::ITALIC_SHAPE, LColor::math}
617 fontinfo * lookupFont(string const & name)
619 //lyxerr << "searching font '" << name << "'" << endl;
620 int const n = sizeof(fontinfos) / sizeof(fontinfo);
621 for (int i = 0; i < n; ++i)
622 if (fontinfos[i].cmd_ == name) {
623 //lyxerr << "found '" << i << "'" << endl;
624 return fontinfos + i;
630 fontinfo * searchFont(string const & name)
632 fontinfo * f = lookupFont(name);
633 return f ? f : fontinfos;
634 // this should be mathnormal
635 //return searchFont("mathnormal");
639 bool isFontName(string const & name)
641 return lookupFont(name);
645 LyXFont getFont(string const & name)
648 augmentFont(font, name);
653 void fakeFont(string const & orig, string const & fake)
655 fontinfo * forig = searchFont(orig);
656 fontinfo * ffake = searchFont(fake);
657 if (forig && ffake) {
658 forig->family_ = ffake->family_;
659 forig->series_ = ffake->series_;
660 forig->shape_ = ffake->shape_;
661 forig->color_ = ffake->color_;
663 lyxerr << "Can't fake font '" << orig << "' with '"
664 << fake << "'" << endl;
669 void augmentFont(LyXFont & font, string const & name)
671 static bool initialized = false;
674 // fake fonts if necessary
675 if (!lyx_gui::font_available(getFont("mathfrak")))
676 fakeFont("mathfrak", "lyxfakefrak");
677 if (!lyx_gui::font_available(getFont("mathcal")))
678 fakeFont("mathcal", "lyxfakecal");
680 fontinfo * info = searchFont(name);
681 if (info->family_ != inh_family)
682 font.setFamily(info->family_);
683 if (info->series_ != inh_series)
684 font.setSeries(info->series_);
685 if (info->shape_ != inh_shape)
686 font.setShape(info->shape_);
687 if (info->color_ != LColor::none)
688 font.setColor(info->color_);
692 string asString(MathArray const & ar)
694 std::ostringstream os;
697 return STRCONV(os.str());
701 void asArray(string const & str, MathArray & ar)
703 mathed_parse_cell(ar, str);