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 = ellipse with given center and horizontal and vertical radii,
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 5, 0.5, 0.5, 0.1, 0.1,
341 double const ddot[] = {
342 5, 0.2, 0.5, 0.1, 0.1,
343 5, 0.7, 0.5, 0.1, 0.1,
348 double const dddot[] = {
349 5, 0.1, 0.5, 0.1, 0.1,
350 5, 0.5, 0.5, 0.1, 0.1,
351 5, 0.9, 0.5, 0.1, 0.1,
356 double const ddddot[] = {
357 5, -0.1, 0.5, 0.1, 0.1,
358 5, 0.3, 0.5, 0.1, 0.1,
359 5, 0.7, 0.5, 0.1, 0.1,
360 5, 1.1, 0.5, 0.1, 0.1,
365 double const hline3[] = {
366 5, 0.15, 0.05, 0.0625, 0.0625,
367 5, 0.50, 0.05, 0.0625, 0.0625,
368 5, 0.85, 0.05, 0.0625, 0.0625,
373 double const dline3[] = {
374 5, 0.25, 0.225, 0.0625, 0.0625,
375 5, 0.50, 0.475, 0.0625, 0.0625,
376 5, 0.75, 0.725, 0.0625, 0.0625,
381 double const ring[] = {
383 0.5000, 0.7750, 0.6375, 0.7375, 0.7375, 0.6375, 0.7750, 0.5000,
384 0.7375, 0.3625, 0.6375, 0.2625, 0.5000, 0.2250, 0.3625, 0.2625,
385 0.2625, 0.3625, 0.2250, 0.5000, 0.2625, 0.6375, 0.3625, 0.7375,
391 double const vert[] = {
392 1, 0.5, 0.05, 0.5, 0.95,
397 double const Vert[] = {
398 1, 0.3, 0.05, 0.3, 0.95,
399 1, 0.7, 0.05, 0.7, 0.95,
404 double const tilde[] = {
406 0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
407 0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
417 struct named_deco_struct {
423 named_deco_struct deco_table[] = {
425 {"widehat", angle, 3 },
426 {"widetilde", tilde, 0 },
427 {"underbar", hline, 0 },
428 {"underline", hline, 0 },
429 {"overline", hline, 0 },
430 {"underbrace", brace, 1 },
431 {"overbrace", brace, 3 },
432 {"overleftarrow", arrow, 1 },
433 {"overrightarrow", arrow, 3 },
434 {"overleftrightarrow", udarrow, 1 },
435 {"xhookleftarrow", lhook, 0 },
436 {"xhookrightarrow", rhook, 0 },
437 {"xleftarrow", arrow, 1 },
438 {"xLeftarrow", LArrow, 0 },
439 {"xleftharpoondown", lharpoondown, 0 },
440 {"xleftharpoonup", lharpoonup, 0 },
441 {"xleftrightharpoons", lrharpoons, 0 },
442 {"xleftrightarrow", udarrow, 1 },
443 {"xLeftrightarrow", LRArrow, 0 },
444 {"xmapsto", mapsto, 0 },
445 {"xrightarrow", arrow, 3 },
446 {"xRightarrow", LArrow, 2 },
447 {"xrightharpoondown", lharpoonup, 2 },
448 {"xrightharpoonup", lharpoondown, 2 },
449 {"xrightleftharpoons", rlharpoons, 0 },
450 {"underleftarrow", arrow, 1 },
451 {"underrightarrow", arrow, 3 },
452 {"underleftrightarrow", udarrow, 1 },
453 {"undertilde", tilde, 0 },
454 {"utilde", tilde, 0 },
461 {"lbrace", brace, 0 },
462 {"rbrace", brace, 2 },
465 {"llbracket", dbrack, 0 },
466 {"rrbracket", dbrack, 2 },
469 {"slash", slash, 0 },
480 {"backslash", slash, 1 },
481 {"langle", angle, 0 },
482 {"lceil", corner, 0 },
483 {"lfloor", corner, 1 },
484 {"rangle", angle, 2 },
485 {"rceil", corner, 3 },
486 {"rfloor", corner, 2 },
487 {"downarrow", arrow, 2 },
488 {"Downarrow", Arrow, 2 },
489 {"uparrow", arrow, 0 },
490 {"Uparrow", Arrow, 0 },
491 {"updownarrow", udarrow, 0 },
492 {"Updownarrow", Udarrow, 0 },
496 {"dddot", dddot, 0 },
497 {"ddddot", ddddot, 0 },
499 {"grave", slash, 1 },
500 {"acute", slash, 0 },
501 {"tilde", tilde, 0 },
504 {"check", angle, 1 },
505 {"breve", breve, 0 },
507 {"mathring", ring, 0 },
510 {"dots", hline3, 0 },
511 {"ldots", hline3, 0 },
512 {"cdots", hline3, 0 },
513 {"vdots", hline3, 1 },
514 {"ddots", dline3, 0 },
515 {"adots", dline3, 1 },
516 {"iddots", dline3, 1 },
517 {"dotsb", hline3, 0 },
518 {"dotsc", hline3, 0 },
519 {"dotsi", hline3, 0 },
520 {"dotsm", hline3, 0 },
521 {"dotso", hline3, 0 }
525 map<docstring, deco_struct> deco_list;
527 // sort the table on startup
528 class init_deco_table {
531 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
532 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
536 deco_list[from_ascii(p->name)] = d;
541 static init_deco_table dummy_deco_table;
544 deco_struct const * search_deco(docstring const & name)
546 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
547 return p == deco_list.end() ? 0 : &(p->second);
554 int mathed_font_em(FontInfo const & font)
556 return theFontMetrics(font).em();
560 int mathed_font_x_height(FontInfo const & font)
562 return theFontMetrics(font).xHeight();
565 /* The math units. Quoting TeX by Topic, p.205:
567 * Spacing around mathematical objects is measured in mu units. A mu
568 * is 1/18th part of \fontdimen6 of the font in family 2 in the
569 * current style, the ‘quad’ value of the symbol font.
571 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
572 * inserted around (binary) relations, except where these are preceded
573 * or followed by other relations or punctuation, and except if they
574 * follow an open, or precede a close symbol.
576 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
577 * is put around binary operators.
579 * A \thinmuskip (default value in plain TeX: 3mu) follows after
580 * punctuation, and is put around inner objects, except where these
581 * are followed by a close or preceded by an open symbol, and except
582 * if the other object is a large operator or a binary relation.
584 * See the file MathClass.cpp for a formal implementation of the rules
588 int mathed_mu(FontInfo const & font, double mu)
590 MetricsBase mb(nullptr, font);
591 return mb.inPixels(Length(mu, Length::MU));
594 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
595 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
596 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
599 int mathed_char_width(FontInfo const & font, char_type c)
601 return theFontMetrics(font).width(c);
605 int mathed_char_kerning(FontInfo const & font, char_type c)
607 frontend::FontMetrics const & fm = theFontMetrics(font);
608 return max(0, fm.rbearing(c) - fm.width(c));
612 double mathed_char_slope(MetricsBase const & mb, char_type c)
614 bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
615 if (slanted && mb.fontname == "mathnormal")
616 return theFontMetrics(mb.font).italicSlope();
621 void mathed_string_dim(FontInfo const & font,
625 frontend::FontMetrics const & fm = theFontMetrics(font);
628 for (char_type const c : s) {
629 dim.asc = max(dim.asc, fm.ascent(c));
630 dim.des = max(dim.des, fm.descent(c));
632 dim.wid = fm.width(s);
636 int mathed_string_width(FontInfo const & font, docstring const & s)
638 return theFontMetrics(font).width(s);
642 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
643 docstring const & name)
645 int const lw = pi.base.solidLineThickness();
648 pi.pain.line(x + w/2, y, x + w/2, y + h,
649 Color_cursor, Painter::line_onoffdash, lw);
653 deco_struct const * mds = search_deco(name);
655 lyxerr << "Deco was not found. Programming error?" << endl;
656 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
660 int const n = (w < h) ? w : h;
661 int const r = mds->angle;
662 double const * d = mds->data;
664 if (h > 70 && (name == "(" || name == ")"))
668 Matrix sqmt(r, n, n);
676 for (int i = 0; d[i]; ) {
677 int code = int(d[i++]);
678 if (code == 1 || code == 3) {
684 sqmt.transform(xx, yy);
686 mt.transform(xx, yy);
687 mt.transform(x2, y2);
689 int(x + xx + 0.5), int(y + yy + 0.5),
690 int(x + x2 + 0.5), int(y + y2 + 0.5),
691 pi.base.font.color(), Painter::line_solid, lw);
692 } else if (code == 5) {
695 double x2 = xx + d[i++];
696 double y2 = yy + d[i++];
697 mt.transform(xx, yy);
698 mt.transform(x2, y2);
699 double const xc = x + xx;
700 double const yc = y + yy;
701 double const rx = x2 - xx;
702 double const ry = y2 - yy;
703 pi.pain.ellipse(xc, yc, rx, ry,
704 pi.base.font.color(), Painter::fill_winding);
708 double xshift = (code == 6 ? d[i++] : 0.0);
709 double yshift = (code == 6 ? d[i++] : 0.0);
710 int const n2 = int(d[i++]);
711 for (int j = 0; j < n2; ++j) {
712 double xx = d[i++] + xshift;
713 double yy = d[i++] + yshift;
714 // lyxerr << ' ' << xx << ' ' << yy << ' ';
715 if (code == 4 || code == 6) {
716 sqmt.transform(xx, yy);
718 if (r == 0 && xshift == 0.0)
724 mt.transform(xx, yy);
725 xp[j] = int(x + xx + 0.5);
726 yp[j] = int(y + yy + 0.5);
727 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
729 pi.pain.lines(xp, yp, n2, pi.base.font.color(),
730 Painter::fill_none, Painter::line_solid, lw);
736 docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
738 return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
739 sym->dsp_draw : sym->draw;
743 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
745 LASSERT((bool)sym, return 0);
746 //lyxerr << "metrics: symbol: '" << sym->name
747 // << "' in font: '" << sym->inset
748 // << "' drawn as: '" << sym->draw
751 bool const italic_upcase_greek = sym->inset == "cmr" &&
752 sym->extra == "mathalpha" &&
753 mb.fontname == "mathit";
754 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
755 bool const change_font = font != "cmr" ||
756 (mb.fontname != "mathbb" &&
757 mb.fontname != "mathds" &&
758 mb.fontname != "mathfrak" &&
759 mb.fontname != "mathcal" &&
760 mb.fontname != "mathscr");
761 Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
762 mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
763 return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
767 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
769 LASSERT((bool)sym, return);
770 //lyxerr << "drawing: symbol: '" << sym->name
771 // << "' in font: '" << sym->inset
772 // << "' drawn as: '" << sym->draw
775 bool const italic_upcase_greek = sym->inset == "cmr" &&
776 sym->extra == "mathalpha" &&
777 pi.base.fontname == "mathit";
778 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
779 bool const change_font = font != "cmr" ||
780 (pi.base.fontname != "mathbb" &&
781 pi.base.fontname != "mathds" &&
782 pi.base.fontname != "mathfrak" &&
783 pi.base.fontname != "mathcal" &&
784 pi.base.fontname != "mathscr");
785 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
786 pi.draw(x, y, mathedSymbol(pi.base, sym));
790 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
792 FontInfo font = mi.base.font;
793 augmentFont(font, "mathnormal");
794 mathed_string_dim(font, str, dim);
798 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
800 FontInfo f = pi.base.font;
801 augmentFont(f, "mathnormal");
802 f.setColor(Color_latex);
803 pi.pain.text(x, y, str, f);
807 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
809 FontInfo f = pi.base.font;
810 augmentFont(f, "mathnormal");
811 f.setColor(Color_foreground);
812 pi.pain.text(x, y, str, f);
816 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
818 frontend::FontMetrics const & fm = theFontMetrics(font);
819 asc = fm.maxAscent();
820 des = fm.maxDescent();
833 FontFamily const inh_family = INHERIT_FAMILY;
834 FontSeries const inh_series = INHERIT_SERIES;
835 FontShape const inh_shape = INHERIT_SHAPE;
838 // mathnormal should be the first, otherwise the fallback further down
840 fontinfo fontinfos[] = {
842 // Color_math determines which fonts are math (see isMathFont)
843 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
844 ITALIC_SHAPE, Color_math},
845 {"mathbf", inh_family, BOLD_SERIES,
846 inh_shape, Color_math},
847 {"mathcal", CMSY_FAMILY, inh_series,
848 inh_shape, Color_math},
849 {"mathfrak", EUFRAK_FAMILY, inh_series,
850 inh_shape, Color_math},
851 {"mathrm", ROMAN_FAMILY, inh_series,
852 UP_SHAPE, Color_math},
853 {"mathsf", SANS_FAMILY, inh_series,
854 inh_shape, Color_math},
855 {"mathbb", MSB_FAMILY, inh_series,
856 inh_shape, Color_math},
857 {"mathds", DS_FAMILY, inh_series,
858 inh_shape, Color_math},
859 {"mathtt", TYPEWRITER_FAMILY, inh_series,
860 inh_shape, Color_math},
861 {"mathit", inh_family, inh_series,
862 ITALIC_SHAPE, Color_math},
863 {"mathscr", RSFS_FAMILY, inh_series,
864 inh_shape, Color_math},
865 {"cmex", CMEX_FAMILY, inh_series,
866 inh_shape, Color_math},
867 {"cmm", CMM_FAMILY, inh_series,
868 inh_shape, Color_math},
869 {"cmr", CMR_FAMILY, inh_series,
870 inh_shape, Color_math},
871 {"cmsy", CMSY_FAMILY, inh_series,
872 inh_shape, Color_math},
873 {"eufrak", EUFRAK_FAMILY, inh_series,
874 inh_shape, Color_math},
875 {"msa", MSA_FAMILY, inh_series,
876 inh_shape, Color_math},
877 {"msb", MSB_FAMILY, inh_series,
878 inh_shape, Color_math},
879 {"stmry", STMARY_FAMILY, inh_series,
880 inh_shape, Color_math},
881 {"wasy", WASY_FAMILY, inh_series,
882 inh_shape, Color_math},
883 {"esint", ESINT_FAMILY, inh_series,
884 inh_shape, Color_math},
887 {"text", inh_family, inh_series,
888 inh_shape, Color_foreground},
889 {"textbf", inh_family, BOLD_SERIES,
890 inh_shape, Color_foreground},
891 {"textit", inh_family, inh_series,
892 ITALIC_SHAPE, Color_foreground},
893 {"textmd", inh_family, MEDIUM_SERIES,
894 inh_shape, Color_foreground},
895 {"textnormal", inh_family, inh_series,
896 UP_SHAPE, Color_foreground},
897 {"textrm", ROMAN_FAMILY,
898 inh_series, UP_SHAPE,Color_foreground},
899 {"textsc", inh_family, inh_series,
900 SMALLCAPS_SHAPE, Color_foreground},
901 {"textsf", SANS_FAMILY, inh_series,
902 inh_shape, Color_foreground},
903 {"textsl", inh_family, inh_series,
904 SLANTED_SHAPE, Color_foreground},
905 {"texttt", TYPEWRITER_FAMILY, inh_series,
906 inh_shape, Color_foreground},
907 {"textup", inh_family, inh_series,
908 UP_SHAPE, Color_foreground},
911 {"textipa", inh_family, inh_series,
912 inh_shape, Color_foreground},
915 {"ce", inh_family, inh_series,
916 inh_shape, Color_foreground},
917 {"cf", inh_family, inh_series,
918 inh_shape, Color_foreground},
920 // LyX internal usage
921 {"lyxtex", inh_family, inh_series,
922 UP_SHAPE, Color_latex},
923 // FIXME: The following two don't work on OS X, since the Symbol font
924 // uses a different encoding, and is therefore disabled in
925 // FontLoader::available().
926 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
927 inh_shape, Color_math},
928 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
929 inh_shape, Color_math},
930 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
931 UP_SHAPE, Color_foreground},
932 {"lyxnochange", inh_family, inh_series,
933 inh_shape, Color_foreground},
934 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
935 UP_SHAPE, Color_math},
936 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
937 ITALIC_SHAPE, Color_math},
938 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
939 ITALIC_SHAPE, Color_math}
943 fontinfo * lookupFont(string const & name)
945 //lyxerr << "searching font '" << name << "'" << endl;
946 int const n = sizeof(fontinfos) / sizeof(fontinfo);
947 for (int i = 0; i < n; ++i)
948 if (fontinfos[i].cmd_ == name) {
949 //lyxerr << "found '" << i << "'" << endl;
950 return fontinfos + i;
956 fontinfo * searchFont(string const & name)
958 fontinfo * f = lookupFont(name);
959 return f ? f : fontinfos;
960 // this should be mathnormal
961 //return searchFont("mathnormal");
965 bool isFontName(string const & name)
967 return lookupFont(name);
971 bool isMathFont(string const & name)
973 fontinfo * f = lookupFont(name);
974 return f && f->color_ == Color_math;
978 bool isTextFont(string const & name)
980 fontinfo * f = lookupFont(name);
981 return f && f->color_ == Color_foreground;
985 FontInfo getFont(string const & name)
988 augmentFont(font, name);
993 void fakeFont(string const & orig, string const & fake)
995 fontinfo * forig = searchFont(orig);
996 fontinfo * ffake = searchFont(fake);
997 if (forig && ffake) {
998 forig->family_ = ffake->family_;
999 forig->series_ = ffake->series_;
1000 forig->shape_ = ffake->shape_;
1001 forig->color_ = ffake->color_;
1003 lyxerr << "Can't fake font '" << orig << "' with '"
1004 << fake << "'" << endl;
1009 void augmentFont(FontInfo & font, string const & name)
1011 static bool initialized = false;
1014 // fake fonts if necessary
1015 if (!theFontLoader().available(getFont("mathfrak")))
1016 fakeFont("mathfrak", "lyxfakefrak");
1017 if (!theFontLoader().available(getFont("mathcal")))
1018 fakeFont("mathcal", "lyxfakecal");
1020 fontinfo * info = searchFont(name);
1021 if (info->family_ != inh_family)
1022 font.setFamily(info->family_);
1023 if (info->series_ != inh_series)
1024 font.setSeries(info->series_);
1025 if (info->shape_ != inh_shape)
1026 font.setShape(info->shape_);
1027 if (info->color_ != Color_none)
1028 font.setColor(info->color_);
1032 bool isAlphaSymbol(MathAtom const & at)
1034 if (at->asCharInset() ||
1035 (at->asSymbolInset() &&
1036 at->asSymbolInset()->isOrdAlpha()))
1039 if (at->asFontInset()) {
1040 MathData const & ar = at->asFontInset()->cell(0);
1041 for (size_t i = 0; i < ar.size(); ++i) {
1042 if (!(ar[i]->asCharInset() ||
1043 (ar[i]->asSymbolInset() &&
1044 ar[i]->asSymbolInset()->isOrdAlpha())))
1053 docstring asString(MathData const & ar)
1055 odocstringstream os;
1056 otexrowstream ots(os);
1057 TeXMathStream ws(ots);
1063 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1065 // If the QUIET flag is set, we are going to parse for either
1066 // a paste operation or a macro definition. We try to do the
1067 // right thing in all cases.
1069 bool quiet = pf & Parse::QUIET;
1070 bool macro = pf & Parse::MACRODEF;
1071 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1072 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1076 docstring asString(InsetMath const & inset)
1078 odocstringstream os;
1079 otexrowstream ots(os);
1080 TeXMathStream ws(ots);
1086 docstring asString(MathAtom const & at)
1088 odocstringstream os;
1089 otexrowstream ots(os);
1090 TeXMathStream ws(ots);
1096 int axis_height(MetricsBase & mb)
1098 Changer dummy = mb.changeFontSet("mathnormal");
1099 return theFontMetrics(mb.font).ascent('-') - 1;
1103 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1105 MathWordList const & words = mathedWordList();
1106 MathWordList::const_iterator it = words.find(word);
1107 if (it != words.end()) {
1108 string const req = it->second.required;
1110 features.require(req);