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
9 * Full author contact details are available in file CREDITS.
14 #include "MathSupport.h"
16 #include "InsetMathFont.h"
17 #include "InsetMathSymbol.h"
19 #include "MathFactory.h"
20 #include "MathParser.h"
21 #include "MathStream.h"
24 #include "LaTeXFeatures.h"
25 #include "MetricsInfo.h"
27 #include "frontends/FontLoader.h"
28 #include "frontends/FontMetrics.h"
29 #include "frontends/Painter.h"
31 #include "support/Changer.h"
32 #include "support/debug.h"
33 #include "support/docstream.h"
34 #include "support/lassert.h"
35 #include "support/Length.h"
36 #include "support/textutils.h"
45 using frontend::Painter;
52 Matrix(int, double, double);
54 void transform(double &, double &);
61 Matrix::Matrix(int code, double x, double y)
63 double const cs = (code & 1) ? 0 : (1 - code);
64 double const sn = (code & 1) ? (2 - code) : 0;
72 void Matrix::transform(double & x, double & y)
74 double xx = m_[0][0] * x + m_[0][1] * y;
75 double yy = m_[1][0] * x + m_[1][1] * y;
85 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
86 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
87 * 5 = rounded thick line (i.e. dot for short line),
88 * 6 = shifted square polyline drawn at the other end
92 double const parenthHigh[] = {
94 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
95 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
96 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
97 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
103 double const parenth[] = {
105 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
106 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
107 0.0141, 0.5000, 0.0634, 0.6379, 0.2183, 0.7667,
108 0.3380, 0.8286, 0.5141, 0.8874, 0.7324, 0.9422,
114 double const breve[] = {
116 0.100, 0.400, 0.125, 0.550, 0.200, 0.700, 0.400, 0.800,
117 0.600, 0.800, 0.800, 0.700, 0.875, 0.550, 0.900, 0.400,
122 double const brace[] = {
124 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
125 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
126 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
127 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
128 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
129 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
130 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
135 double const mapsto[] = {
137 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
138 1, 0.015, 0.475, 0.945, 0.475,
139 1, 0.015, 0.015, 0.015, 0.985,
144 double const lhook[] = {
146 1.40, -0.30, 1.10, 0.00, 0.60, 0.35,
147 0.00, 0.60, 0.60, 0.85, 1.10, 1.20,
149 3, 0.05, 0.6, 1.0, 0.6,
151 0.65, -0.40, 0.95, -0.35, 1.15, -0.10,
152 1.15, 0.25, 0.95, 0.50, 0.65, 0.60,
157 double const rhook[] = {
159 0.50, -0.40, 0.20, -0.35, 0.00, -0.10,
160 0.00, 0.25, 0.20, 0.50, 0.50, 0.60,
161 3, 0.55, 0.60, 1.00, 0.60,
163 0.00, -0.30, 0.30, 0.00, 0.80, 0.35, 1.40, 0.60,
164 0.80, 0.85, 0.30, 1.20, 0.00, 1.50,
169 double const LRArrow[] = {
171 1.300, -0.300, 1.100, 0.000, 0.600, 0.350,
172 0.000, 0.600, 0.600, 0.850, 1.100, 1.200,
175 -0.300, -0.300, -0.100, 0.000, 0.400, 0.350,
176 1.000, 0.600, 0.400, 0.850, -0.100, 1.200,
178 3, 0.85, 1.0, 1.0, 1.0,
179 3, 0.85, 0.2, 1.0, 0.2,
184 double const LArrow[] = {
186 1.300, -0.300, 1.100, 0.000, 0.600, 0.350,
187 0.000, 0.600, 0.600, 0.850, 1.100, 1.200,
189 3, 0.85, 1.0, 1.0, 1.0,
190 3, 0.85, 0.2, 1.0, 0.2,
195 double const lharpoondown[] = {
197 0.0, 0.6, 0.6, 0.85, 1.1, 1.2, 1.4, 1.5,
198 3, 0.05, 0.6, 1.0, 0.6,
203 double const lharpoonup[] = {
205 0.0, 0.6, 0.6, 0.35, 1.1, 0.0, 1.4, -0.3,
206 3, 0.05, 0.6, 1.0, 0.6,
211 double const lrharpoons[] = {
213 0.0, 0.6, 0.6, 0.35, 1.1, 0.0, 1.4, -0.3,
214 3, 0.05, 0.6, 1.0, 0.6,
215 3, 0.05, 1.2, 1.0, 1.2,
217 1.1, 1.3, 0.4, 1.55, -0.1, 1.9, -0.4, 2.2,
222 double const rlharpoons[] = {
224 -0.4, -0.4, -0.1, -0.1, 0.4, 0.25, 1.0, 0.5,
225 3, 0.05, 0.6, 1.0, 0.6,
226 3, 0.05, 1.2, 1.0, 1.2,
228 0.0, 1.2, 0.6, 1.45, 1.1, 1.8, 1.4, 2.1,
233 double const vec[] = {
235 0.2000, 0.5000, 0.3000, 0.4000, 0.4000, 0.2500,
236 0.5000, 0.0000, 0.6000, 0.2500, 0.7000, 0.4000,
238 3, 0.5000, 0.1000, 0.5000, 0.9500,
243 double const arrow[] = {
245 0.0500, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
246 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
248 3, 0.5000, 0.1500, 0.5000, 1.0000,
253 double const Arrow[] = {
255 0.0000, 0.7500, 0.1500, 0.6000, 0.3500, 0.3500,
256 0.5000, 0.0500, 0.6500, 0.3500, 0.8500, 0.6000,
258 3, 0.3000, 0.4500, 0.3000, 1.0000,
259 3, 0.7000, 0.4500, 0.7000, 1.0000,
264 double const udarrow[] = {
266 0.0500, 0.6500, 0.2000, 0.5000, 0.3500, 0.2500,
267 0.5000, -0.0500, 0.6500, 0.2500, 0.8000, 0.5000,
270 0.0500, 0.2500, 0.2000, 0.4000, 0.3500, 0.6500,
271 0.5000, 0.9500, 0.6500, 0.6500, 0.8000, 0.4000,
273 3, 0.5, 0.0, 0.5, 1.0,
278 double const Udarrow[] = {
280 0.0000, 0.7500, 0.1500, 0.6000, 0.3500, 0.3500,
281 0.5000, 0.0500, 0.6500, 0.3500, 0.8500, 0.6000,
284 0.0000, 0.2500, 0.1500, 0.4000, 0.3500, 0.6500,
285 0.5000, 0.9500, 0.6500, 0.6500, 0.8500, 0.4000,
287 3, 0.3000, 0.4500, 0.3000, 0.9500,
288 3, 0.7000, 0.4500, 0.7000, 0.9500,
293 double const brack[] = {
295 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
300 double const dbrack[] = {
302 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
304 0.50, 0.05, 0.50, 0.95,
309 double const corner[] = {
311 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
316 double const angle[] = {
318 0.9, 0.05, 0.05, 0.5, 0.9, 0.95,
323 double const slash[] = {
324 1, 0.95, 0.05, 0.05, 0.95,
329 double const hline[] = {
330 1, 0.00, 0.5, 1.0, 0.5,
335 double const dot[] = {
336 // 1, 0.5, 0.2, 0.5, 0.2,
337 // 1, 0.4, 0.4, 0.6, 0.4,
338 // 1, 0.5, 0.5, 0.5, 0.5,
339 5, 0.4, 0.5, 0.6, 0.5,
344 double const ddot[] = {
345 5, 0.1, 0.5, 0.3, 0.5,
346 5, 0.6, 0.5, 0.8, 0.5,
351 double const dddot[] = {
352 5, 0.0, 0.5, 0.2, 0.5,
353 5, 0.4, 0.5, 0.6, 0.5,
354 5, 0.8, 0.5, 1.0, 0.5,
359 double const ddddot[] = {
360 5, -0.2, 0.5, 0.0, 0.5,
361 5, 0.2, 0.5, 0.4, 0.5,
362 5, 0.6, 0.5, 0.8, 0.5,
363 5, 1.0, 0.5, 1.2, 0.5,
368 double const hline3[] = {
370 1, 0.475, 0, 0.525, 0,
376 double const dline3[] = {
377 1, 0.1, 0.1, 0.15, 0.15,
378 1, 0.475, 0.475, 0.525, 0.525,
379 1, 0.85, 0.85, 0.9, 0.9,
384 double const ring[] = {
386 0.5000, 0.7750, 0.6375, 0.7375, 0.7375, 0.6375, 0.7750, 0.5000,
387 0.7375, 0.3625, 0.6375, 0.2625, 0.5000, 0.2250, 0.3625, 0.2625,
388 0.2625, 0.3625, 0.2250, 0.5000, 0.2625, 0.6375, 0.3625, 0.7375,
394 double const vert[] = {
395 1, 0.5, 0.05, 0.5, 0.95,
400 double const Vert[] = {
401 1, 0.3, 0.05, 0.3, 0.95,
402 1, 0.7, 0.05, 0.7, 0.95,
407 double const tilde[] = {
409 0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
410 0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
420 struct named_deco_struct {
426 named_deco_struct deco_table[] = {
428 {"widehat", angle, 3 },
429 {"widetilde", tilde, 0 },
430 {"underbar", hline, 0 },
431 {"underline", hline, 0 },
432 {"overline", hline, 0 },
433 {"underbrace", brace, 1 },
434 {"overbrace", brace, 3 },
435 {"overleftarrow", arrow, 1 },
436 {"overrightarrow", arrow, 3 },
437 {"overleftrightarrow", udarrow, 1 },
438 {"xhookleftarrow", lhook, 0 },
439 {"xhookrightarrow", rhook, 0 },
440 {"xleftarrow", arrow, 1 },
441 {"xLeftarrow", LArrow, 0 },
442 {"xleftharpoondown", lharpoondown, 0 },
443 {"xleftharpoonup", lharpoonup, 0 },
444 {"xleftrightharpoons", lrharpoons, 0 },
445 {"xleftrightarrow", udarrow, 1 },
446 {"xLeftrightarrow", LRArrow, 0 },
447 {"xmapsto", mapsto, 0 },
448 {"xrightarrow", arrow, 3 },
449 {"xRightarrow", LArrow, 2 },
450 {"xrightharpoondown", lharpoonup, 2 },
451 {"xrightharpoonup", lharpoondown, 2 },
452 {"xrightleftharpoons", rlharpoons, 0 },
453 {"underleftarrow", arrow, 1 },
454 {"underrightarrow", arrow, 3 },
455 {"underleftrightarrow", udarrow, 1 },
456 {"undertilde", tilde, 0 },
457 {"utilde", tilde, 0 },
464 {"lbrace", brace, 0 },
465 {"rbrace", brace, 2 },
468 {"llbracket", dbrack, 0 },
469 {"rrbracket", dbrack, 2 },
472 {"slash", slash, 0 },
483 {"backslash", slash, 1 },
484 {"langle", angle, 0 },
485 {"lceil", corner, 0 },
486 {"lfloor", corner, 1 },
487 {"rangle", angle, 2 },
488 {"rceil", corner, 3 },
489 {"rfloor", corner, 2 },
490 {"downarrow", arrow, 2 },
491 {"Downarrow", Arrow, 2 },
492 {"uparrow", arrow, 0 },
493 {"Uparrow", Arrow, 0 },
494 {"updownarrow", udarrow, 0 },
495 {"Updownarrow", Udarrow, 0 },
499 {"dddot", dddot, 0 },
500 {"ddddot", ddddot, 0 },
502 {"grave", slash, 1 },
503 {"acute", slash, 0 },
504 {"tilde", tilde, 0 },
507 {"check", angle, 1 },
508 {"breve", breve, 0 },
510 {"mathring", ring, 0 },
513 {"dots", hline3, 0 },
514 {"ldots", hline3, 0 },
515 {"cdots", hline3, 0 },
516 {"vdots", hline3, 1 },
517 {"ddots", dline3, 0 },
518 {"adots", dline3, 1 },
519 {"iddots", dline3, 1 },
520 {"dotsb", hline3, 0 },
521 {"dotsc", hline3, 0 },
522 {"dotsi", hline3, 0 },
523 {"dotsm", hline3, 0 },
524 {"dotso", hline3, 0 }
528 map<docstring, deco_struct> deco_list;
530 // sort the table on startup
531 class init_deco_table {
534 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
535 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
539 deco_list[from_ascii(p->name)] = d;
544 static init_deco_table dummy_deco_table;
547 deco_struct const * search_deco(docstring const & name)
549 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
550 return p == deco_list.end() ? 0 : &(p->second);
557 int mathed_font_em(FontInfo const & font)
559 return theFontMetrics(font).em();
563 int mathed_font_x_height(FontInfo const & font)
565 return theFontMetrics(font).xHeight();
568 /* The math units. Quoting TeX by Topic, p.205:
570 * Spacing around mathematical objects is measured in mu units. A mu
571 * is 1/18th part of \fontdimen6 of the font in family 2 in the
572 * current style, the ‘quad’ value of the symbol font.
574 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
575 * inserted around (binary) relations, except where these are preceded
576 * or followed by other relations or punctuation, and except if they
577 * follow an open, or precede a close symbol.
579 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
580 * is put around binary operators.
582 * A \thinmuskip (default value in plain TeX: 3mu) follows after
583 * punctuation, and is put around inner objects, except where these
584 * are followed by a close or preceded by an open symbol, and except
585 * if the other object is a large operator or a binary relation.
587 * See the file MathClass.cpp for a formal implementation of the rules
591 int mathed_mu(FontInfo const & font, double mu)
593 MetricsBase mb(nullptr, font);
594 return mb.inPixels(Length(mu, Length::MU));
597 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
598 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
599 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
602 int mathed_char_width(FontInfo const & font, char_type c)
604 return theFontMetrics(font).width(c);
608 int mathed_char_kerning(FontInfo const & font, char_type c)
610 frontend::FontMetrics const & fm = theFontMetrics(font);
611 return max(0, fm.rbearing(c) - fm.width(c));
615 double mathed_char_slope(MetricsBase const & mb, char_type c)
617 bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
618 if (slanted && mb.fontname == "mathnormal")
619 return theFontMetrics(mb.font).italicSlope();
624 void mathed_string_dim(FontInfo const & font,
628 frontend::FontMetrics const & fm = theFontMetrics(font);
631 for (char_type const c : s) {
632 dim.asc = max(dim.asc, fm.ascent(c));
633 dim.des = max(dim.des, fm.descent(c));
635 dim.wid = fm.width(s);
639 int mathed_string_width(FontInfo const & font, docstring const & s)
641 return theFontMetrics(font).width(s);
645 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
646 docstring const & name)
648 int const lw = pi.base.solidLineThickness();
651 pi.pain.line(x + w/2, y, x + w/2, y + h,
652 Color_cursor, Painter::line_onoffdash, lw);
656 deco_struct const * mds = search_deco(name);
658 lyxerr << "Deco was not found. Programming error?" << endl;
659 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
663 int const n = (w < h) ? w : h;
664 int const r = mds->angle;
665 double const * d = mds->data;
667 if (h > 70 && (name == "(" || name == ")"))
671 Matrix sqmt(r, n, n);
679 for (int i = 0; d[i]; ) {
680 int code = int(d[i++]);
681 if (code & 1) { // code == 1 || code == 3 || code == 5
687 sqmt.transform(xx, yy);
689 mt.transform(xx, yy);
690 mt.transform(x2, y2);
692 int(x + xx + 0.5), int(y + yy + 0.5),
693 int(x + x2 + 0.5), int(y + y2 + 0.5),
694 pi.base.font.color(), Painter::line_solid, lw);
695 if (code == 5) { // thicker, but rounded
696 double const xa = x + xx + 0.5;
697 double const xb = x + x2 + 0.5;
698 double const ya = y + yy + 0.5;
699 double const yb = y + y2 + 0.5;
700 pi.pain.line(int(xa + 1), int(ya - 1),
701 int(xb - 1), int(yb - 1),
702 pi.base.font.color(),
703 Painter::line_solid, lw);
704 pi.pain.line(int(xa + 1), int(ya + 1),
705 int(xb - 1), int(yb + 1),
706 pi.base.font.color(),
707 Painter::line_solid, lw);
708 for (int k = 2; xa + k <= xb - k; k++) {
709 pi.pain.line(int(xa + k), int(ya - k),
710 int(xb - k), int(yb - k),
711 pi.base.font.color(),
712 Painter::line_solid, lw);
713 pi.pain.line(int(xa + k), int(ya + k),
714 int(xb - k), int(yb + k),
715 pi.base.font.color(),
716 Painter::line_solid, lw);
722 double xshift = (code == 6 ? d[i++] : 0.0);
723 double yshift = (code == 6 ? d[i++] : 0.0);
724 int const n2 = int(d[i++]);
725 for (int j = 0; j < n2; ++j) {
726 double xx = d[i++] + xshift;
727 double yy = d[i++] + yshift;
728 // lyxerr << ' ' << xx << ' ' << yy << ' ';
729 if (code == 4 || code == 6) {
730 sqmt.transform(xx, yy);
732 if (r == 0 && xshift == 0.0)
738 mt.transform(xx, yy);
739 xp[j] = int(x + xx + 0.5);
740 yp[j] = int(y + yy + 0.5);
741 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
743 pi.pain.lines(xp, yp, n2, pi.base.font.color(),
744 Painter::fill_none, Painter::line_solid, lw);
750 docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
752 return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
753 sym->dsp_draw : sym->draw;
757 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
759 LASSERT((bool)sym, return 0);
760 //lyxerr << "metrics: symbol: '" << sym->name
761 // << "' in font: '" << sym->inset
762 // << "' drawn as: '" << sym->draw
765 bool const italic_upcase_greek = sym->inset == "cmr" &&
766 sym->extra == "mathalpha" &&
767 mb.fontname == "mathit";
768 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
769 bool const change_font = font != "cmr" ||
770 (mb.fontname != "mathbb" &&
771 mb.fontname != "mathds" &&
772 mb.fontname != "mathfrak" &&
773 mb.fontname != "mathcal" &&
774 mb.fontname != "mathscr");
775 Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
776 mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
777 return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
781 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
783 LASSERT((bool)sym, return);
784 //lyxerr << "drawing: symbol: '" << sym->name
785 // << "' in font: '" << sym->inset
786 // << "' drawn as: '" << sym->draw
789 bool const italic_upcase_greek = sym->inset == "cmr" &&
790 sym->extra == "mathalpha" &&
791 pi.base.fontname == "mathit";
792 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
793 bool const change_font = font != "cmr" ||
794 (pi.base.fontname != "mathbb" &&
795 pi.base.fontname != "mathds" &&
796 pi.base.fontname != "mathfrak" &&
797 pi.base.fontname != "mathcal" &&
798 pi.base.fontname != "mathscr");
799 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
800 pi.draw(x, y, mathedSymbol(pi.base, sym));
804 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
806 FontInfo font = mi.base.font;
807 augmentFont(font, "mathnormal");
808 mathed_string_dim(font, str, dim);
812 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
814 FontInfo f = pi.base.font;
815 augmentFont(f, "mathnormal");
816 f.setColor(Color_latex);
817 pi.pain.text(x, y, str, f);
821 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
823 FontInfo f = pi.base.font;
824 augmentFont(f, "mathnormal");
825 f.setColor(Color_foreground);
826 pi.pain.text(x, y, str, f);
830 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
832 frontend::FontMetrics const & fm = theFontMetrics(font);
833 asc = fm.maxAscent();
834 des = fm.maxDescent();
847 FontFamily const inh_family = INHERIT_FAMILY;
848 FontSeries const inh_series = INHERIT_SERIES;
849 FontShape const inh_shape = INHERIT_SHAPE;
852 // mathnormal should be the first, otherwise the fallback further down
854 fontinfo fontinfos[] = {
856 // Color_math determines which fonts are math (see isMathFont)
857 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
858 ITALIC_SHAPE, Color_math},
859 {"mathbf", inh_family, BOLD_SERIES,
860 inh_shape, Color_math},
861 {"mathcal", CMSY_FAMILY, inh_series,
862 inh_shape, Color_math},
863 {"mathfrak", EUFRAK_FAMILY, inh_series,
864 inh_shape, Color_math},
865 {"mathrm", ROMAN_FAMILY, inh_series,
866 UP_SHAPE, Color_math},
867 {"mathsf", SANS_FAMILY, inh_series,
868 inh_shape, Color_math},
869 {"mathbb", MSB_FAMILY, inh_series,
870 inh_shape, Color_math},
871 {"mathds", DS_FAMILY, inh_series,
872 inh_shape, Color_math},
873 {"mathtt", TYPEWRITER_FAMILY, inh_series,
874 inh_shape, Color_math},
875 {"mathit", inh_family, inh_series,
876 ITALIC_SHAPE, Color_math},
877 {"mathscr", RSFS_FAMILY, inh_series,
878 inh_shape, Color_math},
879 {"cmex", CMEX_FAMILY, inh_series,
880 inh_shape, Color_math},
881 {"cmm", CMM_FAMILY, inh_series,
882 inh_shape, Color_math},
883 {"cmr", CMR_FAMILY, inh_series,
884 inh_shape, Color_math},
885 {"cmsy", CMSY_FAMILY, inh_series,
886 inh_shape, Color_math},
887 {"eufrak", EUFRAK_FAMILY, inh_series,
888 inh_shape, Color_math},
889 {"msa", MSA_FAMILY, inh_series,
890 inh_shape, Color_math},
891 {"msb", MSB_FAMILY, inh_series,
892 inh_shape, Color_math},
893 {"stmry", STMARY_FAMILY, inh_series,
894 inh_shape, Color_math},
895 {"wasy", WASY_FAMILY, inh_series,
896 inh_shape, Color_math},
897 {"esint", ESINT_FAMILY, inh_series,
898 inh_shape, Color_math},
901 {"text", inh_family, inh_series,
902 inh_shape, Color_foreground},
903 {"textbf", inh_family, BOLD_SERIES,
904 inh_shape, Color_foreground},
905 {"textit", inh_family, inh_series,
906 ITALIC_SHAPE, Color_foreground},
907 {"textmd", inh_family, MEDIUM_SERIES,
908 inh_shape, Color_foreground},
909 {"textnormal", inh_family, inh_series,
910 UP_SHAPE, Color_foreground},
911 {"textrm", ROMAN_FAMILY,
912 inh_series, UP_SHAPE,Color_foreground},
913 {"textsc", inh_family, inh_series,
914 SMALLCAPS_SHAPE, Color_foreground},
915 {"textsf", SANS_FAMILY, inh_series,
916 inh_shape, Color_foreground},
917 {"textsl", inh_family, inh_series,
918 SLANTED_SHAPE, Color_foreground},
919 {"texttt", TYPEWRITER_FAMILY, inh_series,
920 inh_shape, Color_foreground},
921 {"textup", inh_family, inh_series,
922 UP_SHAPE, Color_foreground},
925 {"textipa", inh_family, inh_series,
926 inh_shape, Color_foreground},
929 {"ce", inh_family, inh_series,
930 inh_shape, Color_foreground},
931 {"cf", inh_family, inh_series,
932 inh_shape, Color_foreground},
934 // LyX internal usage
935 {"lyxtex", inh_family, inh_series,
936 UP_SHAPE, Color_latex},
937 // FIXME: The following two don't work on OS X, since the Symbol font
938 // uses a different encoding, and is therefore disabled in
939 // FontLoader::available().
940 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
941 inh_shape, Color_math},
942 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
943 inh_shape, Color_math},
944 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
945 UP_SHAPE, Color_foreground},
946 {"lyxnochange", inh_family, inh_series,
947 inh_shape, Color_foreground},
948 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
949 UP_SHAPE, Color_math},
950 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
951 ITALIC_SHAPE, Color_math},
952 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
953 ITALIC_SHAPE, Color_math}
957 fontinfo * lookupFont(string const & name)
959 //lyxerr << "searching font '" << name << "'" << endl;
960 int const n = sizeof(fontinfos) / sizeof(fontinfo);
961 for (int i = 0; i < n; ++i)
962 if (fontinfos[i].cmd_ == name) {
963 //lyxerr << "found '" << i << "'" << endl;
964 return fontinfos + i;
970 fontinfo * searchFont(string const & name)
972 fontinfo * f = lookupFont(name);
973 return f ? f : fontinfos;
974 // this should be mathnormal
975 //return searchFont("mathnormal");
979 bool isFontName(string const & name)
981 return lookupFont(name);
985 bool isMathFont(string const & name)
987 fontinfo * f = lookupFont(name);
988 return f && f->color_ == Color_math;
992 bool isTextFont(string const & name)
994 fontinfo * f = lookupFont(name);
995 return f && f->color_ == Color_foreground;
999 FontInfo getFont(string const & name)
1002 augmentFont(font, name);
1007 void fakeFont(string const & orig, string const & fake)
1009 fontinfo * forig = searchFont(orig);
1010 fontinfo * ffake = searchFont(fake);
1011 if (forig && ffake) {
1012 forig->family_ = ffake->family_;
1013 forig->series_ = ffake->series_;
1014 forig->shape_ = ffake->shape_;
1015 forig->color_ = ffake->color_;
1017 lyxerr << "Can't fake font '" << orig << "' with '"
1018 << fake << "'" << endl;
1023 void augmentFont(FontInfo & font, string const & name)
1025 static bool initialized = false;
1028 // fake fonts if necessary
1029 if (!theFontLoader().available(getFont("mathfrak")))
1030 fakeFont("mathfrak", "lyxfakefrak");
1031 if (!theFontLoader().available(getFont("mathcal")))
1032 fakeFont("mathcal", "lyxfakecal");
1034 fontinfo * info = searchFont(name);
1035 if (info->family_ != inh_family)
1036 font.setFamily(info->family_);
1037 if (info->series_ != inh_series)
1038 font.setSeries(info->series_);
1039 if (info->shape_ != inh_shape)
1040 font.setShape(info->shape_);
1041 if (info->color_ != Color_none)
1042 font.setColor(info->color_);
1046 bool isAlphaSymbol(MathAtom const & at)
1048 if (at->asCharInset() ||
1049 (at->asSymbolInset() &&
1050 at->asSymbolInset()->isOrdAlpha()))
1053 if (at->asFontInset()) {
1054 MathData const & ar = at->asFontInset()->cell(0);
1055 for (size_t i = 0; i < ar.size(); ++i) {
1056 if (!(ar[i]->asCharInset() ||
1057 (ar[i]->asSymbolInset() &&
1058 ar[i]->asSymbolInset()->isOrdAlpha())))
1067 docstring asString(MathData const & ar)
1069 odocstringstream os;
1070 otexrowstream ots(os);
1071 TeXMathStream ws(ots);
1077 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1079 // If the QUIET flag is set, we are going to parse for either
1080 // a paste operation or a macro definition. We try to do the
1081 // right thing in all cases.
1083 bool quiet = pf & Parse::QUIET;
1084 bool macro = pf & Parse::MACRODEF;
1085 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1086 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1090 docstring asString(InsetMath const & inset)
1092 odocstringstream os;
1093 otexrowstream ots(os);
1094 TeXMathStream ws(ots);
1100 docstring asString(MathAtom const & at)
1102 odocstringstream os;
1103 otexrowstream ots(os);
1104 TeXMathStream ws(ots);
1110 int axis_height(MetricsBase & mb)
1112 Changer dummy = mb.changeFontSet("mathnormal");
1113 return theFontMetrics(mb.font).ascent('-') - 1;
1117 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1119 MathWordList const & words = mathedWordList();
1120 MathWordList::const_iterator it = words.find(word);
1121 if (it != words.end()) {
1122 string const req = it->second.required;
1124 features.require(req);