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 },
286 {"lbrace", brace, 0 },
287 {"rbrace", brace, 2 },
295 {"backslash", slash, 1 },
296 {"langle", angle, 0 },
297 {"lceil", corner, 0 },
298 {"lfloor", corner, 1 },
299 {"rangle", angle, 2 },
300 {"rceil", corner, 3 },
301 {"rfloor", corner, 2 },
302 {"downarrow", arrow, 2 },
303 {"Downarrow", Arrow, 2 },
304 {"uparrow", arrow, 0 },
305 {"Uparrow", Arrow, 0 },
306 {"updownarrow", udarrow, 0 },
307 {"Updownarrow", Udarrow, 0 },
311 {"dddot", dddot, 0 },
313 {"grave", slash, 1 },
314 {"acute", slash, 0 },
315 {"tilde", tilde, 0 },
317 {"dot", hlinesmall, 0 },
318 {"check", angle, 1 },
319 {"breve", parenth, 1 },
321 {"mathring", ring, 0 },
324 {"dots", hline3, 0 },
325 {"ldots", hline3, 0 },
326 {"cdots", hline3, 0 },
327 {"vdots", hline3, 1 },
328 {"ddots", dline3, 0 },
329 {"dotsb", hline3, 0 },
330 {"dotsc", hline3, 0 },
331 {"dotsi", hline3, 0 },
332 {"dotsm", hline3, 0 },
333 {"dotso", hline3, 0 }
337 std::map<string, deco_struct> deco_list;
339 // sort the table on startup
340 class init_deco_table {
343 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
344 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
348 deco_list[p->name]= d;
353 static init_deco_table dummy;
356 deco_struct const * search_deco(string const & name)
358 std::map<string, deco_struct>::const_iterator p = deco_list.find(name);
359 return (p == deco_list.end()) ? 0 : &(p->second);
366 void mathed_char_dim(LyXFont const & font, unsigned char c, Dimension & dim)
368 dim.des = font_metrics::descent(c, font);
369 dim.asc = font_metrics::ascent(c, font);
370 dim.wid = mathed_char_width(font, c);
374 int mathed_char_ascent(LyXFont const & font, unsigned char c)
376 return font_metrics::ascent(c, font);
380 int mathed_char_descent(LyXFont const & font, unsigned char c)
382 return font_metrics::descent(c, font);
386 int mathed_char_width(LyXFont const & font, unsigned char c)
388 return font_metrics::width(c, font);
392 void mathed_string_dim(LyXFont const & font, string const & s, Dimension & dim)
397 for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
398 dim.asc = max(dim.asc, font_metrics::ascent(*it, font));
399 dim.des = max(dim.des, font_metrics::descent(*it, font));
402 dim.asc = font_metrics::maxAscent(font);
403 dim.des = font_metrics::maxDescent(font);
405 dim.wid = font_metrics::width(s, font);
409 int mathed_string_width(LyXFont const & font, string const & s)
411 return font_metrics::width(s, font);
415 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
419 pi.pain.line(x + w/2, y, x + w/2, y + h,
420 LColor::cursor, Painter::line_onoffdash);
424 deco_struct const * mds = search_deco(name);
426 lyxerr << "Deco was not found. Programming error?" << endl;
427 lyxerr << "name: '" << name << "'" << endl;
431 int const n = (w < h) ? w : h;
432 int const r = mds->angle;
433 double const * d = mds->data;
435 if (h > 70 && (name == "(" || name == ")"))
439 Matrix sqmt(r, n, n);
447 for (int i = 0; d[i]; ) {
448 int code = int(d[i++]);
449 if (code & 1) { // code == 1 || code == 3
455 sqmt.transform(xx, yy);
457 mt.transform(xx, yy);
458 mt.transform(x2, y2);
460 int(x + xx + 0.5), int(y + yy + 0.5),
461 int(x + x2 + 0.5), int(y + y2 + 0.5),
466 int const n = int(d[i++]);
467 for (int j = 0; j < n; ++j) {
470 // lyxerr << ' ' << xx << ' ' << yy << ' ';
472 sqmt.transform(xx, yy);
474 mt.transform(xx, yy);
475 xp[j] = int(x + xx + 0.5);
476 yp[j] = int(y + yy + 0.5);
477 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
479 pi.pain.lines(xp, yp, n, LColor::math);
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 math_font_max_dim(LyXFont const & font, int & asc, int & des)
503 asc = font_metrics::maxAscent(font);
504 des = font_metrics::maxDescent(font);
510 LyXFont::FONT_FAMILY family_;
511 LyXFont::FONT_SERIES series_;
512 LyXFont::FONT_SHAPE shape_;
513 LColor::color color_;
517 LyXFont::FONT_FAMILY const inh_family = LyXFont::INHERIT_FAMILY;
518 LyXFont::FONT_SERIES const inh_series = LyXFont::INHERIT_SERIES;
519 LyXFont::FONT_SHAPE const inh_shape = LyXFont::INHERIT_SHAPE;
522 // mathnormal should be the first, otherwise the fallback further down
524 fontinfo fontinfos[] = {
526 {"mathnormal", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
527 LyXFont::ITALIC_SHAPE, LColor::math},
528 {"mathbf", inh_family, LyXFont::BOLD_SERIES,
529 inh_shape, LColor::math},
530 {"mathcal", LyXFont::CMSY_FAMILY, inh_series,
531 inh_shape, LColor::math},
532 {"mathfrak", LyXFont::EUFRAK_FAMILY, inh_series,
533 inh_shape, LColor::math},
534 {"mathrm", LyXFont::ROMAN_FAMILY, inh_series,
535 LyXFont::UP_SHAPE, LColor::math},
536 {"mathsf", LyXFont::SANS_FAMILY, inh_series,
537 inh_shape, LColor::math},
538 {"mathbb", LyXFont::MSB_FAMILY, inh_series,
539 inh_shape, LColor::math},
540 {"mathtt", LyXFont::TYPEWRITER_FAMILY, inh_series,
541 inh_shape, LColor::math},
542 {"mathit", inh_family, inh_series,
543 LyXFont::ITALIC_SHAPE, LColor::math},
544 {"cmex", LyXFont::CMEX_FAMILY, inh_series,
545 inh_shape, LColor::math},
546 {"cmm", LyXFont::CMM_FAMILY, inh_series,
547 inh_shape, LColor::math},
548 {"cmr", LyXFont::CMR_FAMILY, inh_series,
549 inh_shape, LColor::math},
550 {"cmsy", LyXFont::CMSY_FAMILY, inh_series,
551 inh_shape, LColor::math},
552 {"eufrak", LyXFont::EUFRAK_FAMILY, inh_series,
553 inh_shape, LColor::math},
554 {"msa", LyXFont::MSA_FAMILY, inh_series,
555 inh_shape, LColor::math},
556 {"msb", LyXFont::MSB_FAMILY, inh_series,
557 inh_shape, LColor::math},
558 {"wasy", LyXFont::WASY_FAMILY, inh_series,
559 inh_shape, LColor::none},
562 {"text", inh_family, inh_series,
563 inh_shape, LColor::foreground},
564 {"textbf", inh_family, LyXFont::BOLD_SERIES,
565 inh_shape, LColor::foreground},
566 {"textit", inh_family, inh_series,
567 LyXFont::ITALIC_SHAPE, LColor::foreground},
568 {"textmd", inh_family, LyXFont::MEDIUM_SERIES,
569 inh_shape, LColor::foreground},
570 {"textnormal", inh_family, inh_series,
571 LyXFont::UP_SHAPE, LColor::foreground},
572 {"textrm", LyXFont::ROMAN_FAMILY,
573 inh_series, LyXFont::UP_SHAPE,LColor::foreground},
574 {"textsc", inh_family, inh_series,
575 LyXFont::SMALLCAPS_SHAPE, LColor::foreground},
576 {"textsf", LyXFont::SANS_FAMILY, inh_series,
577 inh_shape, LColor::foreground},
578 {"textsl", inh_family, inh_series,
579 LyXFont::SLANTED_SHAPE, LColor::foreground},
580 {"texttt", LyXFont::TYPEWRITER_FAMILY, inh_series,
581 inh_shape, LColor::foreground},
582 {"textup", inh_family, inh_series,
583 LyXFont::UP_SHAPE, LColor::foreground},
586 {"textipa", inh_family, inh_series,
587 inh_shape, LColor::foreground},
589 // LyX internal usage
590 {"lyxtex", inh_family, inh_series,
591 LyXFont::UP_SHAPE, LColor::latex},
592 {"lyxsymbol", LyXFont::SYMBOL_FAMILY, inh_series,
593 inh_shape, LColor::math},
594 {"lyxboldsymbol", LyXFont::SYMBOL_FAMILY, LyXFont::BOLD_SERIES,
595 inh_shape, LColor::math},
596 {"lyxblacktext", LyXFont::ROMAN_FAMILY, LyXFont::MEDIUM_SERIES,
597 LyXFont::UP_SHAPE, LColor::foreground},
598 {"lyxnochange", inh_family, inh_series,
599 inh_shape, LColor::foreground},
600 {"lyxfakebb", LyXFont::TYPEWRITER_FAMILY, LyXFont::BOLD_SERIES,
601 LyXFont::UP_SHAPE, LColor::math},
602 {"lyxfakecal", LyXFont::SANS_FAMILY, LyXFont::MEDIUM_SERIES,
603 LyXFont::ITALIC_SHAPE, LColor::math},
604 {"lyxfakefrak", LyXFont::ROMAN_FAMILY, LyXFont::BOLD_SERIES,
605 LyXFont::ITALIC_SHAPE, LColor::math}
609 fontinfo * lookupFont(string const & name)
611 //lyxerr << "searching font '" << name << "'" << endl;
612 int const n = sizeof(fontinfos) / sizeof(fontinfo);
613 for (int i = 0; i < n; ++i)
614 if (fontinfos[i].cmd_ == name) {
615 //lyxerr << "found '" << i << "'" << endl;
616 return fontinfos + i;
622 fontinfo * searchFont(string const & name)
624 fontinfo * f = lookupFont(name);
625 return f ? f : fontinfos;
626 // this should be mathnormal
627 //return searchFont("mathnormal");
631 bool isFontName(string const & name)
633 return lookupFont(name);
637 LyXFont getFont(string const & name)
640 augmentFont(font, name);
645 void fakeFont(string const & orig, string const & fake)
647 fontinfo * forig = searchFont(orig);
648 fontinfo * ffake = searchFont(fake);
649 if (forig && ffake) {
650 forig->family_ = ffake->family_;
651 forig->series_ = ffake->series_;
652 forig->shape_ = ffake->shape_;
653 forig->color_ = ffake->color_;
655 lyxerr << "Can't fake font '" << orig << "' with '"
656 << fake << "'" << endl;
661 void augmentFont(LyXFont & font, string const & name)
663 static bool initialized = false;
666 // fake fonts if necessary
667 if (!lyx_gui::font_available(getFont("mathfrak")))
668 fakeFont("mathfrak", "lyxfakefrak");
669 if (!lyx_gui::font_available(getFont("mathcal")))
670 fakeFont("mathcal", "lyxfakecal");
672 fontinfo * info = searchFont(name);
673 if (info->family_ != inh_family)
674 font.setFamily(info->family_);
675 if (info->series_ != inh_series)
676 font.setSeries(info->series_);
677 if (info->shape_ != inh_shape)
678 font.setShape(info->shape_);
679 if (info->color_ != LColor::none)
680 font.setColor(info->color_);
684 string asString(MathArray const & ar)
686 std::ostringstream os;
693 void asArray(string const & str, MathArray & ar)
695 mathed_parse_cell(ar, str);
699 string asString(MathInset const & inset)
701 std::ostringstream os;
708 string asString(MathAtom const & at)
710 std::ostringstream os;