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.0, 0.0625, 0.0625,
367 5, 0.50, 0.0, 0.0625, 0.0625,
368 5, 0.85, 0.0, 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 upcase_greek =
776 sym->inset == "cmr" && sym->extra == "mathalpha";
777 bool const bold_upcase_greek =
778 upcase_greek && pi.base.fontname == "mathbf";
779 bool const italic_upcase_greek =
780 upcase_greek && pi.base.fontname == "mathit";
781 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
782 bool const change_font = font != "cmr" ||
783 (pi.base.fontname != "mathbb" &&
784 pi.base.fontname != "mathds" &&
785 pi.base.fontname != "mathfrak" &&
786 pi.base.fontname != "mathcal" &&
787 pi.base.fontname != "mathscr");
788 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
789 pi.draw(x, y, mathedSymbol(pi.base, sym));
790 if (bold_upcase_greek)
791 pi.draw(x + 1, y, mathedSymbol(pi.base, sym));
795 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
797 FontInfo font = mi.base.font;
798 augmentFont(font, "mathnormal");
799 mathed_string_dim(font, str, dim);
803 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
805 FontInfo f = pi.base.font;
806 augmentFont(f, "mathnormal");
807 f.setColor(Color_latex);
808 pi.pain.text(x, y, str, f);
812 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
814 FontInfo f = pi.base.font;
815 augmentFont(f, "mathnormal");
816 f.setColor(Color_foreground);
817 pi.pain.text(x, y, str, f);
821 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
823 frontend::FontMetrics const & fm = theFontMetrics(font);
824 asc = fm.maxAscent();
825 des = fm.maxDescent();
838 FontFamily const inh_family = INHERIT_FAMILY;
839 FontSeries const inh_series = INHERIT_SERIES;
840 FontShape const inh_shape = INHERIT_SHAPE;
843 // mathnormal should be the first, otherwise the fallback further down
845 fontinfo fontinfos[] = {
847 // Color_math determines which fonts are math (see isMathFont)
848 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
849 ITALIC_SHAPE, Color_math},
850 {"mathbf", inh_family, BOLD_SERIES,
851 inh_shape, Color_math},
852 {"mathcal", CMSY_FAMILY, inh_series,
853 inh_shape, Color_math},
854 {"mathfrak", EUFRAK_FAMILY, inh_series,
855 inh_shape, Color_math},
856 {"mathrm", ROMAN_FAMILY, inh_series,
857 UP_SHAPE, Color_math},
858 {"mathsf", SANS_FAMILY, inh_series,
859 inh_shape, Color_math},
860 {"mathbb", MSB_FAMILY, inh_series,
861 inh_shape, Color_math},
862 {"mathds", DS_FAMILY, inh_series,
863 inh_shape, Color_math},
864 {"mathtt", TYPEWRITER_FAMILY, inh_series,
865 inh_shape, Color_math},
866 {"mathit", inh_family, inh_series,
867 ITALIC_SHAPE, Color_math},
868 {"mathscr", RSFS_FAMILY, inh_series,
869 inh_shape, Color_math},
870 {"cmex", CMEX_FAMILY, inh_series,
871 inh_shape, Color_math},
872 {"cmm", CMM_FAMILY, inh_series,
873 inh_shape, Color_math},
874 {"cmr", CMR_FAMILY, inh_series,
875 inh_shape, Color_math},
876 {"cmsy", CMSY_FAMILY, inh_series,
877 inh_shape, Color_math},
878 {"eufrak", EUFRAK_FAMILY, inh_series,
879 inh_shape, Color_math},
880 {"msa", MSA_FAMILY, inh_series,
881 inh_shape, Color_math},
882 {"msb", MSB_FAMILY, inh_series,
883 inh_shape, Color_math},
884 {"stmry", STMARY_FAMILY, inh_series,
885 inh_shape, Color_math},
886 {"wasy", WASY_FAMILY, inh_series,
887 inh_shape, Color_math},
888 {"esint", ESINT_FAMILY, inh_series,
889 inh_shape, Color_math},
892 {"text", inh_family, inh_series,
893 inh_shape, Color_foreground},
894 {"textbf", inh_family, BOLD_SERIES,
895 inh_shape, Color_foreground},
896 {"textit", inh_family, inh_series,
897 ITALIC_SHAPE, Color_foreground},
898 {"textmd", inh_family, MEDIUM_SERIES,
899 inh_shape, Color_foreground},
900 {"textnormal", inh_family, inh_series,
901 UP_SHAPE, Color_foreground},
902 {"textrm", ROMAN_FAMILY,
903 inh_series, UP_SHAPE,Color_foreground},
904 {"textsc", inh_family, inh_series,
905 SMALLCAPS_SHAPE, Color_foreground},
906 {"textsf", SANS_FAMILY, inh_series,
907 inh_shape, Color_foreground},
908 {"textsl", inh_family, inh_series,
909 SLANTED_SHAPE, Color_foreground},
910 {"texttt", TYPEWRITER_FAMILY, inh_series,
911 inh_shape, Color_foreground},
912 {"textup", inh_family, inh_series,
913 UP_SHAPE, Color_foreground},
916 {"textipa", inh_family, inh_series,
917 inh_shape, Color_foreground},
920 {"ce", inh_family, inh_series,
921 inh_shape, Color_foreground},
922 {"cf", inh_family, inh_series,
923 inh_shape, Color_foreground},
925 // LyX internal usage
926 {"lyxtex", inh_family, inh_series,
927 UP_SHAPE, Color_latex},
928 // FIXME: The following two don't work on OS X, since the Symbol font
929 // uses a different encoding, and is therefore disabled in
930 // FontLoader::available().
931 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
932 inh_shape, Color_math},
933 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
934 inh_shape, Color_math},
935 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
936 UP_SHAPE, Color_foreground},
937 {"lyxnochange", inh_family, inh_series,
938 inh_shape, Color_foreground},
939 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
940 UP_SHAPE, Color_math},
941 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
942 ITALIC_SHAPE, Color_math},
943 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
944 ITALIC_SHAPE, Color_math}
948 fontinfo * lookupFont(string const & name)
950 //lyxerr << "searching font '" << name << "'" << endl;
951 int const n = sizeof(fontinfos) / sizeof(fontinfo);
952 for (int i = 0; i < n; ++i)
953 if (fontinfos[i].cmd_ == name) {
954 //lyxerr << "found '" << i << "'" << endl;
955 return fontinfos + i;
961 fontinfo * searchFont(string const & name)
963 fontinfo * f = lookupFont(name);
964 return f ? f : fontinfos;
965 // this should be mathnormal
966 //return searchFont("mathnormal");
970 bool isFontName(string const & name)
972 return lookupFont(name);
976 bool isMathFont(string const & name)
978 fontinfo * f = lookupFont(name);
979 return f && f->color_ == Color_math;
983 bool isTextFont(string const & name)
985 fontinfo * f = lookupFont(name);
986 return f && f->color_ == Color_foreground;
990 FontInfo getFont(string const & name)
993 augmentFont(font, name);
998 void fakeFont(string const & orig, string const & fake)
1000 fontinfo * forig = searchFont(orig);
1001 fontinfo * ffake = searchFont(fake);
1002 if (forig && ffake) {
1003 forig->family_ = ffake->family_;
1004 forig->series_ = ffake->series_;
1005 forig->shape_ = ffake->shape_;
1006 forig->color_ = ffake->color_;
1008 lyxerr << "Can't fake font '" << orig << "' with '"
1009 << fake << "'" << endl;
1014 void augmentFont(FontInfo & font, string const & name)
1016 static bool initialized = false;
1019 // fake fonts if necessary
1020 if (!theFontLoader().available(getFont("mathfrak")))
1021 fakeFont("mathfrak", "lyxfakefrak");
1022 if (!theFontLoader().available(getFont("mathcal")))
1023 fakeFont("mathcal", "lyxfakecal");
1025 fontinfo * info = searchFont(name);
1026 if (info->family_ != inh_family)
1027 font.setFamily(info->family_);
1028 if (info->series_ != inh_series)
1029 font.setSeries(info->series_);
1030 if (info->shape_ != inh_shape)
1031 font.setShape(info->shape_);
1032 if (info->color_ != Color_none)
1033 font.setColor(info->color_);
1037 bool isAlphaSymbol(MathAtom const & at)
1039 if (at->asCharInset() ||
1040 (at->asSymbolInset() &&
1041 at->asSymbolInset()->isOrdAlpha()))
1044 if (at->asFontInset()) {
1045 MathData const & ar = at->asFontInset()->cell(0);
1046 for (size_t i = 0; i < ar.size(); ++i) {
1047 if (!(ar[i]->asCharInset() ||
1048 (ar[i]->asSymbolInset() &&
1049 ar[i]->asSymbolInset()->isOrdAlpha())))
1058 docstring asString(MathData const & ar)
1060 odocstringstream os;
1061 otexrowstream ots(os);
1062 TeXMathStream ws(ots);
1068 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1070 // If the QUIET flag is set, we are going to parse for either
1071 // a paste operation or a macro definition. We try to do the
1072 // right thing in all cases.
1074 bool quiet = pf & Parse::QUIET;
1075 bool macro = pf & Parse::MACRODEF;
1076 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1077 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1081 docstring asString(InsetMath const & inset)
1083 odocstringstream os;
1084 otexrowstream ots(os);
1085 TeXMathStream ws(ots);
1091 docstring asString(MathAtom const & at)
1093 odocstringstream os;
1094 otexrowstream ots(os);
1095 TeXMathStream ws(ots);
1101 int axis_height(MetricsBase & mb)
1103 Changer dummy = mb.changeFontSet("mathnormal");
1104 return theFontMetrics(mb.font).ascent('-') - 1;
1108 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1110 MathWordList const & words = mathedWordList();
1111 MathWordList::const_iterator it = words.find(word);
1112 if (it != words.end()) {
1113 string const req = it->second.required;
1115 features.require(req);