A bit more re-organization.
[lyx.git] / src / mathed / MathSupport.cpp
blob99930ae4bd8107d9b23c2c8d1e587ee6e69d443e
1 /**
2 * \file MathSupport.cpp
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
7 * \author André Pönitz
9 * Full author contact details are available in file CREDITS.
12 #include <config.h>
14 #include "MathSupport.h"
16 #include "InsetMath.h"
17 #include "MathData.h"
18 #include "MathParser.h"
19 #include "MathStream.h"
21 #include "frontends/FontLoader.h"
22 #include "frontends/FontMetrics.h"
23 #include "frontends/Painter.h"
25 #include "support/debug.h"
26 #include "support/docstream.h"
28 #include <map>
30 using namespace std;
32 namespace lyx {
34 using frontend::Painter;
37 ///
38 class Matrix {
39 public:
40 ///
41 Matrix(int, double, double);
42 ///
43 void transform(double &, double &);
44 private:
45 ///
46 double m_[2][2];
50 Matrix::Matrix(int code, double x, double y)
52 double const cs = (code & 1) ? 0 : (1 - code);
53 double const sn = (code & 1) ? (2 - code) : 0;
54 m_[0][0] = cs * x;
55 m_[0][1] = sn * x;
56 m_[1][0] = -sn * y;
57 m_[1][1] = cs * y;
61 void Matrix::transform(double & x, double & y)
63 double xx = m_[0][0] * x + m_[0][1] * y;
64 double yy = m_[1][0] * x + m_[1][1] * y;
65 x = xx;
66 y = yy;
71 namespace {
74 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
75 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
79 double const parenthHigh[] = {
80 2, 13,
81 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
82 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
83 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
84 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
85 0.9840, 0.9986,
90 double const parenth[] = {
91 2, 13,
92 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
93 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
94 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
95 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
96 0.9930, 0.9919,
101 double const brace[] = {
102 2, 21,
103 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
104 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
105 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
106 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
107 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
108 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
109 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
114 double const arrow[] = {
115 4, 7,
116 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
117 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
118 0.9500, 0.7500,
119 3, 0.5000, 0.1500, 0.5000, 0.9500,
124 double const Arrow[] = {
125 4, 7,
126 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
127 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
128 0.9500, 0.7500,
129 3, 0.3500, 0.5000, 0.3500, 0.9500,
130 3, 0.6500, 0.5000, 0.6500, 0.9500,
135 double const udarrow[] = {
136 2, 3,
137 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
138 2, 3,
139 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
140 1, 0.5, 0.2, 0.5, 0.8,
145 double const Udarrow[] = {
146 2, 3,
147 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
148 2, 3,
149 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
150 1, 0.35, 0.2, 0.35, 0.8,
151 1, 0.65, 0.2, 0.65, 0.8,
156 double const brack[] = {
157 2, 4,
158 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
163 double const corner[] = {
164 2, 3,
165 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
170 double const angle[] = {
171 2, 3,
172 1, 0, 0.05, 0.5, 1, 1,
177 double const slash[] = {
178 1, 0.95, 0.05, 0.05, 0.95,
183 double const hline[] = {
184 1, 0.00, 0.5, 1.0, 0.5,
189 double const ddot[] = {
190 1, 0.2, 0.5, 0.3, 0.5,
191 1, 0.7, 0.5, 0.8, 0.5,
196 double const dddot[] = {
197 1, 0.1, 0.5, 0.2, 0.5,
198 1, 0.45, 0.5, 0.55, 0.5,
199 1, 0.8, 0.5, 0.9, 0.5,
204 double const ddddot[] = {
205 1, 0.0, 0.5, 0.1, 0.5,
206 1, 0.3, 0.5, 0.4, 0.5,
207 1, 0.6, 0.5, 0.7, 0.5,
208 1, 0.9, 0.5, 1.0, 0.5,
213 double const hline3[] = {
214 1, 0.1, 0, 0.15, 0,
215 1, 0.475, 0, 0.525, 0,
216 1, 0.85, 0, 0.9, 0,
221 double const dline3[] = {
222 1, 0.1, 0.1, 0.15, 0.15,
223 1, 0.475, 0.475, 0.525, 0.525,
224 1, 0.85, 0.85, 0.9, 0.9,
229 double const hlinesmall[] = {
230 1, 0.4, 0.5, 0.6, 0.5,
235 double const ring[] = {
236 2, 5,
237 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8,
242 double const vert[] = {
243 1, 0.5, 0.05, 0.5, 0.95,
248 double const Vert[] = {
249 1, 0.3, 0.05, 0.3, 0.95,
250 1, 0.7, 0.05, 0.7, 0.95,
255 double const tilde[] = {
256 2, 4,
257 0.00, 0.8, 0.25, 0.2, 0.75, 0.8, 1.00, 0.2,
262 struct deco_struct {
263 double const * data;
264 int angle;
267 struct named_deco_struct {
268 char const * name;
269 double const * data;
270 int angle;
273 named_deco_struct deco_table[] = {
274 // Decorations
275 {"widehat", angle, 3 },
276 {"widetilde", tilde, 0 },
277 {"underbar", hline, 0 },
278 {"underline", hline, 0 },
279 {"overline", hline, 0 },
280 {"underbrace", brace, 1 },
281 {"overbrace", brace, 3 },
282 {"overleftarrow", arrow, 1 },
283 {"overrightarrow", arrow, 3 },
284 {"overleftrightarrow", udarrow, 1 },
285 {"xleftarrow", arrow, 1 },
286 {"xrightarrow", arrow, 3 },
287 {"underleftarrow", arrow, 1 },
288 {"underrightarrow", arrow, 3 },
289 {"underleftrightarrow", udarrow, 1 },
291 // Delimiters
292 {"(", parenth, 0 },
293 {")", parenth, 2 },
294 {"{", brace, 0 },
295 {"}", brace, 2 },
296 {"lbrace", brace, 0 },
297 {"rbrace", brace, 2 },
298 {"[", brack, 0 },
299 {"]", brack, 2 },
300 {"|", vert, 0 },
301 {"/", slash, 0 },
302 {"slash", slash, 0 },
303 {"vert", vert, 0 },
304 {"Vert", Vert, 0 },
305 {"'", slash, 1 },
306 {"\\", slash, 1 },
307 {"backslash", slash, 1 },
308 {"langle", angle, 0 },
309 {"lceil", corner, 0 },
310 {"lfloor", corner, 1 },
311 {"rangle", angle, 2 },
312 {"rceil", corner, 3 },
313 {"rfloor", corner, 2 },
314 {"downarrow", arrow, 2 },
315 {"Downarrow", Arrow, 2 },
316 {"uparrow", arrow, 0 },
317 {"Uparrow", Arrow, 0 },
318 {"updownarrow", udarrow, 0 },
319 {"Updownarrow", Udarrow, 0 },
321 // Accents
322 {"ddot", ddot, 0 },
323 {"dddot", dddot, 0 },
324 {"ddddot", ddddot, 0 },
325 {"hat", angle, 3 },
326 {"grave", slash, 1 },
327 {"acute", slash, 0 },
328 {"tilde", tilde, 0 },
329 {"bar", hline, 0 },
330 {"dot", hlinesmall, 0 },
331 {"check", angle, 1 },
332 {"breve", parenth, 1 },
333 {"vec", arrow, 3 },
334 {"mathring", ring, 0 },
336 // Dots
337 {"dots", hline3, 0 },
338 {"ldots", hline3, 0 },
339 {"cdots", hline3, 0 },
340 {"vdots", hline3, 1 },
341 {"ddots", dline3, 0 },
342 {"adots", dline3, 1 },
343 {"iddots", dline3, 1 },
344 {"dotsb", hline3, 0 },
345 {"dotsc", hline3, 0 },
346 {"dotsi", hline3, 0 },
347 {"dotsm", hline3, 0 },
348 {"dotso", hline3, 0 }
352 map<docstring, deco_struct> deco_list;
354 // sort the table on startup
355 class init_deco_table {
356 public:
357 init_deco_table() {
358 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
359 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
360 deco_struct d;
361 d.data = p->data;
362 d.angle = p->angle;
363 deco_list[from_ascii(p->name)] = d;
368 static init_deco_table dummy;
371 deco_struct const * search_deco(docstring const & name)
373 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
374 return p == deco_list.end() ? 0 : &(p->second);
378 } // namespace anon
381 int mathed_char_width(FontInfo const & font, char_type c)
383 return theFontMetrics(font).width(c);
387 int mathed_char_kerning(FontInfo const & font, char_type c)
389 frontend::FontMetrics const & fm = theFontMetrics(font);
390 return fm.rbearing(c) - fm.width(c);
394 void mathed_string_dim(FontInfo const & font,
395 docstring const & s,
396 Dimension & dim)
398 frontend::FontMetrics const & fm = theFontMetrics(font);
399 dim.asc = 0;
400 dim.des = 0;
401 for (docstring::const_iterator it = s.begin();
402 it != s.end();
403 ++it) {
404 dim.asc = max(dim.asc, fm.ascent(*it));
405 dim.des = max(dim.des, fm.descent(*it));
407 dim.wid = fm.width(s);
411 int mathed_string_width(FontInfo const & font, docstring const & s)
413 return theFontMetrics(font).width(s);
417 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
418 docstring const & name)
420 if (name == ".") {
421 pi.pain.line(x + w/2, y, x + w/2, y + h,
422 Color_cursor, Painter::line_onoffdash);
423 return;
426 deco_struct const * mds = search_deco(name);
427 if (!mds) {
428 lyxerr << "Deco was not found. Programming error?" << endl;
429 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
430 return;
433 int const n = (w < h) ? w : h;
434 int const r = mds->angle;
435 double const * d = mds->data;
437 if (h > 70 && (name == "(" || name == ")"))
438 d = parenthHigh;
440 Matrix mt(r, w, h);
441 Matrix sqmt(r, n, n);
443 if (r > 0 && r < 3)
444 y += h;
446 if (r >= 2)
447 x += w;
449 for (int i = 0; d[i]; ) {
450 int code = int(d[i++]);
451 if (code & 1) { // code == 1 || code == 3
452 double xx = d[i++];
453 double yy = d[i++];
454 double x2 = d[i++];
455 double y2 = d[i++];
456 if (code == 3)
457 sqmt.transform(xx, yy);
458 else
459 mt.transform(xx, yy);
460 mt.transform(x2, y2);
461 pi.pain.line(
462 int(x + xx + 0.5), int(y + yy + 0.5),
463 int(x + x2 + 0.5), int(y + y2 + 0.5),
464 Color_math);
465 } else {
466 int xp[32];
467 int yp[32];
468 int const n = int(d[i++]);
469 for (int j = 0; j < n; ++j) {
470 double xx = d[i++];
471 double yy = d[i++];
472 // lyxerr << ' ' << xx << ' ' << yy << ' ';
473 if (code == 4)
474 sqmt.transform(xx, yy);
475 else
476 mt.transform(xx, yy);
477 xp[j] = int(x + xx + 0.5);
478 yp[j] = int(y + yy + 0.5);
479 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
481 pi.pain.lines(xp, yp, n, Color_math);
487 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
489 FontInfo f = pi.base.font;
490 f.setColor(Color_latex);
491 pi.pain.text(x, y, str, f);
495 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
497 FontInfo f = pi.base.font;
498 f.setColor(Color_foreground);
499 pi.pain.text(x, y, str, f);
503 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
505 frontend::FontMetrics const & fm = theFontMetrics(font);
506 asc = fm.maxAscent();
507 des = fm.maxDescent();
511 struct fontinfo {
512 string cmd_;
513 FontFamily family_;
514 FontSeries series_;
515 FontShape shape_;
516 ColorCode color_;
520 FontFamily const inh_family = INHERIT_FAMILY;
521 FontSeries const inh_series = INHERIT_SERIES;
522 FontShape const inh_shape = INHERIT_SHAPE;
525 // mathnormal should be the first, otherwise the fallback further down
526 // does not work
527 fontinfo fontinfos[] = {
528 // math fonts
529 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
530 ITALIC_SHAPE, Color_math},
531 {"mathbf", inh_family, BOLD_SERIES,
532 inh_shape, Color_math},
533 {"mathcal", CMSY_FAMILY, inh_series,
534 inh_shape, Color_math},
535 {"mathfrak", EUFRAK_FAMILY, inh_series,
536 inh_shape, Color_math},
537 {"mathrm", ROMAN_FAMILY, inh_series,
538 UP_SHAPE, Color_math},
539 {"mathsf", SANS_FAMILY, inh_series,
540 inh_shape, Color_math},
541 {"mathbb", MSB_FAMILY, inh_series,
542 inh_shape, Color_math},
543 {"mathtt", TYPEWRITER_FAMILY, inh_series,
544 inh_shape, Color_math},
545 {"mathit", inh_family, inh_series,
546 ITALIC_SHAPE, Color_math},
547 {"cmex", CMEX_FAMILY, inh_series,
548 inh_shape, Color_math},
549 {"cmm", CMM_FAMILY, inh_series,
550 inh_shape, Color_math},
551 {"cmr", CMR_FAMILY, inh_series,
552 inh_shape, Color_math},
553 {"cmsy", CMSY_FAMILY, inh_series,
554 inh_shape, Color_math},
555 {"eufrak", EUFRAK_FAMILY, inh_series,
556 inh_shape, Color_math},
557 {"msa", MSA_FAMILY, inh_series,
558 inh_shape, Color_math},
559 {"msb", MSB_FAMILY, inh_series,
560 inh_shape, Color_math},
561 {"wasy", WASY_FAMILY, inh_series,
562 inh_shape, Color_math},
563 {"esint", ESINT_FAMILY, inh_series,
564 inh_shape, Color_math},
566 // Text fonts
567 {"text", inh_family, inh_series,
568 inh_shape, Color_foreground},
569 {"textbf", inh_family, BOLD_SERIES,
570 inh_shape, Color_foreground},
571 {"textit", inh_family, inh_series,
572 ITALIC_SHAPE, Color_foreground},
573 {"textmd", inh_family, MEDIUM_SERIES,
574 inh_shape, Color_foreground},
575 {"textnormal", inh_family, inh_series,
576 UP_SHAPE, Color_foreground},
577 {"textrm", ROMAN_FAMILY,
578 inh_series, UP_SHAPE,Color_foreground},
579 {"textsc", inh_family, inh_series,
580 SMALLCAPS_SHAPE, Color_foreground},
581 {"textsf", SANS_FAMILY, inh_series,
582 inh_shape, Color_foreground},
583 {"textsl", inh_family, inh_series,
584 SLANTED_SHAPE, Color_foreground},
585 {"texttt", TYPEWRITER_FAMILY, inh_series,
586 inh_shape, Color_foreground},
587 {"textup", inh_family, inh_series,
588 UP_SHAPE, Color_foreground},
590 // TIPA support
591 {"textipa", inh_family, inh_series,
592 inh_shape, Color_foreground},
594 // mhchem support
595 {"ce", inh_family, inh_series,
596 inh_shape, Color_foreground},
597 {"cf", inh_family, inh_series,
598 inh_shape, Color_foreground},
600 // LyX internal usage
601 {"lyxtex", inh_family, inh_series,
602 UP_SHAPE, Color_latex},
603 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
604 inh_shape, Color_math},
605 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
606 inh_shape, Color_math},
607 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
608 UP_SHAPE, Color_foreground},
609 {"lyxnochange", inh_family, inh_series,
610 inh_shape, Color_foreground},
611 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
612 UP_SHAPE, Color_math},
613 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
614 ITALIC_SHAPE, Color_math},
615 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
616 ITALIC_SHAPE, Color_math}
620 fontinfo * lookupFont(docstring const & name0)
622 //lyxerr << "searching font '" << name << "'" << endl;
623 int const n = sizeof(fontinfos) / sizeof(fontinfo);
624 string name = to_utf8(name0);
625 for (int i = 0; i < n; ++i)
626 if (fontinfos[i].cmd_ == name) {
627 //lyxerr << "found '" << i << "'" << endl;
628 return fontinfos + i;
630 return 0;
634 fontinfo * searchFont(docstring const & name)
636 fontinfo * f = lookupFont(name);
637 return f ? f : fontinfos;
638 // this should be mathnormal
639 //return searchFont("mathnormal");
643 bool isFontName(docstring const & name)
645 return lookupFont(name);
649 FontInfo getFont(docstring const & name)
651 FontInfo font;
652 augmentFont(font, name);
653 return font;
657 void fakeFont(docstring const & orig, docstring const & fake)
659 fontinfo * forig = searchFont(orig);
660 fontinfo * ffake = searchFont(fake);
661 if (forig && ffake) {
662 forig->family_ = ffake->family_;
663 forig->series_ = ffake->series_;
664 forig->shape_ = ffake->shape_;
665 forig->color_ = ffake->color_;
666 } else {
667 lyxerr << "Can't fake font '" << to_utf8(orig) << "' with '"
668 << to_utf8(fake) << "'" << endl;
673 void augmentFont(FontInfo & font, docstring const & name)
675 static bool initialized = false;
676 if (!initialized) {
677 initialized = true;
678 // fake fonts if necessary
679 if (!theFontLoader().available(getFont(from_ascii("mathfrak"))))
680 fakeFont(from_ascii("mathfrak"), from_ascii("lyxfakefrak"));
681 if (!theFontLoader().available(getFont(from_ascii("mathcal"))))
682 fakeFont(from_ascii("mathcal"), from_ascii("lyxfakecal"));
684 fontinfo * info = searchFont(name);
685 if (info->family_ != inh_family)
686 font.setFamily(info->family_);
687 if (info->series_ != inh_series)
688 font.setSeries(info->series_);
689 if (info->shape_ != inh_shape)
690 font.setShape(info->shape_);
691 if (info->color_ != Color_none)
692 font.setColor(info->color_);
696 docstring asString(MathData const & ar)
698 odocstringstream os;
699 WriteStream ws(os);
700 ws << ar;
701 return os.str();
705 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
707 bool quiet = pf & Parse::QUIET;
708 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet))
709 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
713 docstring asString(InsetMath const & inset)
715 odocstringstream os;
716 WriteStream ws(os);
717 inset.write(ws);
718 return os.str();
722 docstring asString(MathAtom const & at)
724 odocstringstream os;
725 WriteStream ws(os);
726 at->write(ws);
727 return os.str();
731 } // namespace lyx