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 hline2[] = {
336 1, 0.00, 0.2, 1.0, 0.2,
337 1, 0.00, 0.5, 1.0, 0.5,
342 double const dot[] = {
343 5, 0.5, 0.5, 0.1, 0.1,
348 double const ddot[] = {
349 5, 0.2, 0.5, 0.1, 0.1,
350 5, 0.7, 0.5, 0.1, 0.1,
355 double const dddot[] = {
356 5, 0.1, 0.5, 0.1, 0.1,
357 5, 0.5, 0.5, 0.1, 0.1,
358 5, 0.9, 0.5, 0.1, 0.1,
363 double const ddddot[] = {
364 5, -0.1, 0.5, 0.1, 0.1,
365 5, 0.3, 0.5, 0.1, 0.1,
366 5, 0.7, 0.5, 0.1, 0.1,
367 5, 1.1, 0.5, 0.1, 0.1,
372 double const hline3[] = {
373 5, 0.15, 0.0, 0.0625, 0.0625,
374 5, 0.50, 0.0, 0.0625, 0.0625,
375 5, 0.85, 0.0, 0.0625, 0.0625,
380 double const dline3[] = {
381 5, 0.25, 0.225, 0.0625, 0.0625,
382 5, 0.50, 0.475, 0.0625, 0.0625,
383 5, 0.75, 0.725, 0.0625, 0.0625,
388 double const ring[] = {
390 0.5000, 0.7750, 0.6375, 0.7375, 0.7375, 0.6375, 0.7750, 0.5000,
391 0.7375, 0.3625, 0.6375, 0.2625, 0.5000, 0.2250, 0.3625, 0.2625,
392 0.2625, 0.3625, 0.2250, 0.5000, 0.2625, 0.6375, 0.3625, 0.7375,
398 double const vert[] = {
399 1, 0.5, 0.05, 0.5, 0.95,
404 double const Vert[] = {
405 1, 0.3, 0.05, 0.3, 0.95,
406 1, 0.7, 0.05, 0.7, 0.95,
411 double const tilde[] = {
413 0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
414 0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
419 double const wave[] = {
422 0.01, 0.39, 0.04, 0.21, 0.05, 0.20, 0.06, 0.21, 0.09, 0.39, 0.10, 0.40,
423 0.11, 0.39, 0.14, 0.21, 0.15, 0.20, 0.16, 0.21, 0.19, 0.39, 0.20, 0.40,
424 0.21, 0.39, 0.24, 0.21, 0.25, 0.20, 0.26, 0.21, 0.29, 0.39, 0.30, 0.40,
425 0.31, 0.39, 0.34, 0.21, 0.35, 0.20, 0.36, 0.21, 0.39, 0.39, 0.40, 0.40,
426 0.41, 0.39, 0.44, 0.21, 0.45, 0.20, 0.46, 0.21, 0.49, 0.39, 0.50, 0.40,
427 0.51, 0.39, 0.54, 0.21, 0.55, 0.20, 0.56, 0.21, 0.59, 0.39, 0.60, 0.40,
428 0.61, 0.39, 0.64, 0.21, 0.65, 0.20, 0.66, 0.21, 0.69, 0.39, 0.70, 0.40,
429 0.71, 0.39, 0.74, 0.21, 0.75, 0.20, 0.76, 0.21, 0.79, 0.39, 0.80, 0.40,
430 0.81, 0.39, 0.84, 0.21, 0.85, 0.20, 0.86, 0.21, 0.89, 0.39, 0.90, 0.40,
431 0.91, 0.39, 0.94, 0.21, 0.95, 0.20, 0.96, 0.21, 0.99, 0.39, 1.00, 0.40,
441 struct named_deco_struct {
447 named_deco_struct deco_table[] = {
449 {"widehat", angle, 3 },
450 {"widetilde", tilde, 0 },
451 {"underbar", hline, 0 },
452 {"underline", hline, 0 },
453 {"uline", hline, 0 },
454 {"uuline", hline2, 0 },
456 {"overline", hline, 0 },
457 {"underbrace", brace, 1 },
458 {"overbrace", brace, 3 },
459 {"overleftarrow", arrow, 1 },
460 {"overrightarrow", arrow, 3 },
461 {"overleftrightarrow", udarrow, 1 },
462 {"xhookleftarrow", lhook, 0 },
463 {"xhookrightarrow", rhook, 0 },
464 {"xleftarrow", arrow, 1 },
465 {"xLeftarrow", LArrow, 0 },
466 {"xleftharpoondown", lharpoondown, 0 },
467 {"xleftharpoonup", lharpoonup, 0 },
468 {"xleftrightharpoons", lrharpoons, 0 },
469 {"xleftrightarrow", udarrow, 1 },
470 {"xLeftrightarrow", LRArrow, 0 },
471 {"xmapsto", mapsto, 0 },
472 {"xrightarrow", arrow, 3 },
473 {"xRightarrow", LArrow, 2 },
474 {"xrightharpoondown", lharpoonup, 2 },
475 {"xrightharpoonup", lharpoondown, 2 },
476 {"xrightleftharpoons", rlharpoons, 0 },
477 {"underleftarrow", arrow, 1 },
478 {"underrightarrow", arrow, 3 },
479 {"underleftrightarrow", udarrow, 1 },
480 {"undertilde", tilde, 0 },
481 {"utilde", tilde, 0 },
488 {"lbrace", brace, 0 },
489 {"rbrace", brace, 2 },
492 {"llbracket", dbrack, 0 },
493 {"rrbracket", dbrack, 2 },
496 {"slash", slash, 0 },
507 {"backslash", slash, 1 },
508 {"langle", angle, 0 },
509 {"lceil", corner, 0 },
510 {"lfloor", corner, 1 },
511 {"rangle", angle, 2 },
512 {"rceil", corner, 3 },
513 {"rfloor", corner, 2 },
514 {"downarrow", arrow, 2 },
515 {"Downarrow", Arrow, 2 },
516 {"uparrow", arrow, 0 },
517 {"Uparrow", Arrow, 0 },
518 {"updownarrow", udarrow, 0 },
519 {"Updownarrow", Udarrow, 0 },
523 {"dddot", dddot, 0 },
524 {"ddddot", ddddot, 0 },
526 {"grave", slash, 1 },
527 {"acute", slash, 0 },
528 {"tilde", tilde, 0 },
531 {"check", angle, 1 },
532 {"breve", breve, 0 },
534 {"mathring", ring, 0 },
537 {"dots", hline3, 0 },
538 {"ldots", hline3, 0 },
539 {"cdots", hline3, 0 },
540 {"vdots", hline3, 1 },
541 {"ddots", dline3, 0 },
542 {"adots", dline3, 1 },
543 {"iddots", dline3, 1 },
544 {"dotsb", hline3, 0 },
545 {"dotsc", hline3, 0 },
546 {"dotsi", hline3, 0 },
547 {"dotsm", hline3, 0 },
548 {"dotso", hline3, 0 }
552 map<docstring, deco_struct> deco_list;
554 // sort the table on startup
555 class init_deco_table {
558 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
559 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
563 deco_list[from_ascii(p->name)] = d;
568 static init_deco_table dummy_deco_table;
571 deco_struct const * search_deco(docstring const & name)
573 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
574 return p == deco_list.end() ? 0 : &(p->second);
581 int mathed_font_em(FontInfo const & font)
583 return theFontMetrics(font).em();
587 int mathed_font_x_height(FontInfo const & font)
589 return theFontMetrics(font).xHeight();
592 /* The math units. Quoting TeX by Topic, p.205:
594 * Spacing around mathematical objects is measured in mu units. A mu
595 * is 1/18th part of \fontdimen6 of the font in family 2 in the
596 * current style, the ‘quad’ value of the symbol font.
598 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
599 * inserted around (binary) relations, except where these are preceded
600 * or followed by other relations or punctuation, and except if they
601 * follow an open, or precede a close symbol.
603 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
604 * is put around binary operators.
606 * A \thinmuskip (default value in plain TeX: 3mu) follows after
607 * punctuation, and is put around inner objects, except where these
608 * are followed by a close or preceded by an open symbol, and except
609 * if the other object is a large operator or a binary relation.
611 * See the file MathClass.cpp for a formal implementation of the rules
615 int mathed_mu(FontInfo const & font, double mu)
617 MetricsBase mb(nullptr, font);
618 return mb.inPixels(Length(mu, Length::MU));
621 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
622 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
623 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
626 int mathed_char_width(FontInfo const & font, char_type c)
628 return theFontMetrics(font).width(c);
632 int mathed_char_kerning(FontInfo const & font, char_type c)
634 frontend::FontMetrics const & fm = theFontMetrics(font);
635 return max(0, fm.rbearing(c) - fm.width(c));
639 double mathed_char_slope(MetricsBase const & mb, char_type c)
641 bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
642 if (slanted && mb.fontname == "mathnormal")
643 return theFontMetrics(mb.font).italicSlope();
648 void mathed_string_dim(FontInfo const & font,
652 frontend::FontMetrics const & fm = theFontMetrics(font);
655 for (char_type const c : s) {
656 dim.asc = max(dim.asc, fm.ascent(c));
657 dim.des = max(dim.des, fm.descent(c));
659 dim.wid = fm.width(s);
663 int mathed_string_width(FontInfo const & font, docstring const & s)
665 return theFontMetrics(font).width(s);
669 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
670 docstring const & name)
672 int const lw = pi.base.solidLineThickness();
675 pi.pain.line(x + w/2, y, x + w/2, y + h,
676 Color_cursor, Painter::line_onoffdash, lw);
680 deco_struct const * mds = search_deco(name);
682 lyxerr << "Deco was not found. Programming error?" << endl;
683 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
687 int const n = (w < h) ? w : h;
688 int const r = mds->angle;
689 double const * d = mds->data;
691 if (h > 70 && (name == "(" || name == ")"))
695 Matrix sqmt(r, n, n);
703 for (int i = 0; d[i]; ) {
704 int code = int(d[i++]);
705 if (code == 1 || code == 3) {
711 sqmt.transform(xx, yy);
713 mt.transform(xx, yy);
714 mt.transform(x2, y2);
716 int(x + xx + 0.5), int(y + yy + 0.5),
717 int(x + x2 + 0.5), int(y + y2 + 0.5),
718 pi.base.font.color(), Painter::line_solid, lw);
719 } else if (code == 5) {
722 double x2 = xx + d[i++];
723 double y2 = yy + d[i++];
724 mt.transform(xx, yy);
725 mt.transform(x2, y2);
726 double const xc = x + xx;
727 double const yc = y + yy;
728 double const rx = x2 - xx;
729 double const ry = y2 - yy;
730 pi.pain.ellipse(xc, yc, rx, ry,
731 pi.base.font.color(), Painter::fill_winding);
735 double xshift = (code == 6 ? d[i++] : 0.0);
736 double yshift = (code == 6 ? d[i++] : 0.0);
737 int const n2 = int(d[i++]);
738 for (int j = 0; j < n2; ++j) {
739 double xx = d[i++] + xshift;
740 double yy = d[i++] + yshift;
741 // lyxerr << ' ' << xx << ' ' << yy << ' ';
742 if (code == 4 || code == 6) {
743 sqmt.transform(xx, yy);
745 if (r == 0 && xshift == 0.0)
751 mt.transform(xx, yy);
752 xp[j] = int(x + xx + 0.5);
753 yp[j] = int(y + yy + 0.5);
754 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
756 pi.pain.lines(xp, yp, n2, pi.base.font.color(),
757 Painter::fill_none, Painter::line_solid, lw);
763 docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
765 return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
766 sym->dsp_draw : sym->draw;
770 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
772 LASSERT((bool)sym, return 0);
773 //lyxerr << "metrics: symbol: '" << sym->name
774 // << "' in font: '" << sym->inset
775 // << "' drawn as: '" << sym->draw
778 bool const italic_upcase_greek = sym->inset == "cmr" &&
779 sym->extra == "mathalpha" &&
780 mb.fontname == "mathit";
781 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
782 bool const change_font = font != "cmr" ||
783 (mb.fontname != "mathbb" &&
784 mb.fontname != "mathds" &&
785 mb.fontname != "mathfrak" &&
786 mb.fontname != "mathcal" &&
787 mb.fontname != "mathscr");
788 Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
789 mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
790 return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
794 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
796 LASSERT((bool)sym, return);
797 //lyxerr << "drawing: symbol: '" << sym->name
798 // << "' in font: '" << sym->inset
799 // << "' drawn as: '" << sym->draw
802 bool const upcase_greek =
803 sym->inset == "cmr" && sym->extra == "mathalpha";
804 bool const bold_upcase_greek =
805 upcase_greek && pi.base.fontname == "mathbf";
806 bool const italic_upcase_greek =
807 upcase_greek && pi.base.fontname == "mathit";
808 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
809 bool const change_font = font != "cmr" ||
810 (pi.base.fontname != "mathbb" &&
811 pi.base.fontname != "mathds" &&
812 pi.base.fontname != "mathfrak" &&
813 pi.base.fontname != "mathcal" &&
814 pi.base.fontname != "mathscr");
815 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
816 pi.draw(x, y, mathedSymbol(pi.base, sym));
817 if (bold_upcase_greek)
818 pi.draw(x + 1, y, mathedSymbol(pi.base, sym));
822 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
824 FontInfo font = mi.base.font;
825 augmentFont(font, "mathnormal");
826 mathed_string_dim(font, str, dim);
830 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
832 FontInfo f = pi.base.font;
833 augmentFont(f, "mathnormal");
834 f.setColor(Color_latex);
835 pi.pain.text(x, y, str, f, Painter::LtR);
839 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
841 FontInfo f = pi.base.font;
842 augmentFont(f, "mathnormal");
843 f.setColor(Color_foreground);
844 pi.pain.text(x, y, str, f, Painter::LtR);
848 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
850 frontend::FontMetrics const & fm = theFontMetrics(font);
851 asc = fm.maxAscent();
852 des = fm.maxDescent();
865 FontFamily const inh_family = INHERIT_FAMILY;
866 FontSeries const inh_series = INHERIT_SERIES;
867 FontShape const inh_shape = INHERIT_SHAPE;
870 // mathnormal should be the first, otherwise the fallback further down
872 fontinfo fontinfos[] = {
874 // Color_math determines which fonts are math (see isMathFont)
875 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
876 ITALIC_SHAPE, Color_math},
877 {"mathbf", inh_family, BOLD_SERIES,
878 inh_shape, Color_math},
879 {"mathcal", CMSY_FAMILY, inh_series,
880 inh_shape, Color_math},
881 {"mathfrak", EUFRAK_FAMILY, inh_series,
882 inh_shape, Color_math},
883 {"mathrm", ROMAN_FAMILY, inh_series,
884 UP_SHAPE, Color_math},
885 {"mathsf", SANS_FAMILY, inh_series,
886 inh_shape, Color_math},
887 {"mathbb", MSB_FAMILY, inh_series,
888 inh_shape, Color_math},
889 {"mathds", DS_FAMILY, inh_series,
890 inh_shape, Color_math},
891 {"mathtt", TYPEWRITER_FAMILY, inh_series,
892 inh_shape, Color_math},
893 {"mathit", inh_family, inh_series,
894 ITALIC_SHAPE, Color_math},
895 {"mathscr", RSFS_FAMILY, inh_series,
896 inh_shape, Color_math},
897 {"cmex", CMEX_FAMILY, inh_series,
898 inh_shape, Color_math},
899 {"cmm", CMM_FAMILY, inh_series,
900 inh_shape, Color_math},
901 {"cmr", CMR_FAMILY, inh_series,
902 inh_shape, Color_math},
903 {"cmsy", CMSY_FAMILY, inh_series,
904 inh_shape, Color_math},
905 {"eufrak", EUFRAK_FAMILY, inh_series,
906 inh_shape, Color_math},
907 {"msa", MSA_FAMILY, inh_series,
908 inh_shape, Color_math},
909 {"msb", MSB_FAMILY, inh_series,
910 inh_shape, Color_math},
911 {"stmry", STMARY_FAMILY, inh_series,
912 inh_shape, Color_math},
913 {"wasy", WASY_FAMILY, inh_series,
914 inh_shape, Color_math},
915 {"esint", ESINT_FAMILY, inh_series,
916 inh_shape, Color_math},
919 {"text", inh_family, inh_series,
920 inh_shape, Color_foreground},
921 {"textbf", inh_family, BOLD_SERIES,
922 inh_shape, Color_foreground},
923 {"textit", inh_family, inh_series,
924 ITALIC_SHAPE, Color_foreground},
925 {"textmd", inh_family, MEDIUM_SERIES,
926 inh_shape, Color_foreground},
927 {"textnormal", inh_family, inh_series,
928 UP_SHAPE, Color_foreground},
929 {"textrm", ROMAN_FAMILY,
930 inh_series, UP_SHAPE,Color_foreground},
931 {"textsc", inh_family, inh_series,
932 SMALLCAPS_SHAPE, Color_foreground},
933 {"textsf", SANS_FAMILY, inh_series,
934 inh_shape, Color_foreground},
935 {"textsl", inh_family, inh_series,
936 SLANTED_SHAPE, Color_foreground},
937 {"texttt", TYPEWRITER_FAMILY, inh_series,
938 inh_shape, Color_foreground},
939 {"textup", inh_family, inh_series,
940 UP_SHAPE, Color_foreground},
943 {"textipa", inh_family, inh_series,
944 inh_shape, Color_foreground},
947 {"ce", inh_family, inh_series,
948 inh_shape, Color_foreground},
949 {"cf", inh_family, inh_series,
950 inh_shape, Color_foreground},
952 // LyX internal usage
953 {"lyxtex", inh_family, inh_series,
954 UP_SHAPE, Color_latex},
955 // FIXME: The following two don't work on OS X, since the Symbol font
956 // uses a different encoding, and is therefore disabled in
957 // FontLoader::available().
958 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
959 inh_shape, Color_math},
960 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
961 inh_shape, Color_math},
962 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
963 UP_SHAPE, Color_foreground},
964 {"lyxnochange", inh_family, inh_series,
965 inh_shape, Color_foreground},
966 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
967 UP_SHAPE, Color_math},
968 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
969 ITALIC_SHAPE, Color_math},
970 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
971 ITALIC_SHAPE, Color_math}
975 fontinfo * lookupFont(string const & name)
977 //lyxerr << "searching font '" << name << "'" << endl;
978 int const n = sizeof(fontinfos) / sizeof(fontinfo);
979 for (int i = 0; i < n; ++i)
980 if (fontinfos[i].cmd_ == name) {
981 //lyxerr << "found '" << i << "'" << endl;
982 return fontinfos + i;
988 fontinfo * searchFont(string const & name)
990 fontinfo * f = lookupFont(name);
991 return f ? f : fontinfos;
992 // this should be mathnormal
993 //return searchFont("mathnormal");
997 bool isFontName(string const & name)
999 return lookupFont(name);
1003 bool isMathFont(string const & name)
1005 fontinfo * f = lookupFont(name);
1006 return f && f->color_ == Color_math;
1010 bool isTextFont(string const & name)
1012 fontinfo * f = lookupFont(name);
1013 return f && f->color_ == Color_foreground;
1017 FontInfo getFont(string const & name)
1020 augmentFont(font, name);
1025 void fakeFont(string const & orig, string const & fake)
1027 fontinfo * forig = searchFont(orig);
1028 fontinfo * ffake = searchFont(fake);
1029 if (forig && ffake) {
1030 forig->family_ = ffake->family_;
1031 forig->series_ = ffake->series_;
1032 forig->shape_ = ffake->shape_;
1033 forig->color_ = ffake->color_;
1035 lyxerr << "Can't fake font '" << orig << "' with '"
1036 << fake << "'" << endl;
1041 void augmentFont(FontInfo & font, string const & name)
1043 static bool initialized = false;
1046 // fake fonts if necessary
1047 if (!theFontLoader().available(getFont("mathfrak")))
1048 fakeFont("mathfrak", "lyxfakefrak");
1049 if (!theFontLoader().available(getFont("mathcal")))
1050 fakeFont("mathcal", "lyxfakecal");
1052 fontinfo * info = searchFont(name);
1053 if (info->family_ != inh_family)
1054 font.setFamily(info->family_);
1055 if (info->series_ != inh_series)
1056 font.setSeries(info->series_);
1057 if (info->shape_ != inh_shape)
1058 font.setShape(info->shape_);
1059 if (info->color_ != Color_none)
1060 font.setColor(info->color_);
1064 bool isAlphaSymbol(MathAtom const & at)
1066 if (at->asCharInset() ||
1067 (at->asSymbolInset() &&
1068 at->asSymbolInset()->isOrdAlpha()))
1071 if (at->asFontInset()) {
1072 MathData const & ar = at->asFontInset()->cell(0);
1073 for (const auto & i : ar) {
1074 if (!(i->asCharInset() ||
1075 (i->asSymbolInset() &&
1076 i->asSymbolInset()->isOrdAlpha())))
1085 docstring asString(MathData const & ar)
1087 odocstringstream os;
1088 otexrowstream ots(os);
1089 TeXMathStream ws(ots);
1095 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1097 // If the QUIET flag is set, we are going to parse for either
1098 // a paste operation or a macro definition. We try to do the
1099 // right thing in all cases.
1101 bool quiet = pf & Parse::QUIET;
1102 bool macro = pf & Parse::MACRODEF;
1103 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1104 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1106 // set the buffer of the MathData contents
1107 ar.setContentsBuffer();
1111 docstring asString(InsetMath const & inset)
1113 odocstringstream os;
1114 otexrowstream ots(os);
1115 TeXMathStream ws(ots);
1121 docstring asString(MathAtom const & at)
1123 odocstringstream os;
1124 otexrowstream ots(os);
1125 TeXMathStream ws(ots);
1131 int axis_height(MetricsBase & mb)
1133 Changer dummy = mb.changeFontSet("mathnormal");
1134 return theFontMetrics(mb.font).ascent('-') - 1;
1138 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1140 MathWordList const & words = mathedWordList();
1141 MathWordList::const_iterator it = words.find(word);
1142 if (it != words.end()) {
1143 string const req = it->second.required;
1145 features.require(req);