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"
23 #include "LaTeXFeatures.h"
24 #include "MetricsInfo.h"
26 #include "frontends/FontLoader.h"
27 #include "frontends/FontMetrics.h"
28 #include "frontends/Painter.h"
30 #include "support/Changer.h"
31 #include "support/debug.h"
32 #include "support/docstream.h"
33 #include "support/lassert.h"
34 #include "support/Length.h"
43 using frontend::Painter;
50 Matrix(int, double, double);
52 void transform(double &, double &);
59 Matrix::Matrix(int code, double x, double y)
61 double const cs = (code & 1) ? 0 : (1 - code);
62 double const sn = (code & 1) ? (2 - code) : 0;
70 void Matrix::transform(double & x, double & y)
72 double xx = m_[0][0] * x + m_[0][1] * y;
73 double yy = m_[1][0] * x + m_[1][1] * y;
83 * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
84 * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline
85 * 5 = rounded thick line (i.e. dot for short line)
89 double const parenthHigh[] = {
91 0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
92 0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
93 0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
94 0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
100 double const parenth[] = {
102 0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
103 0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
104 0.0141, 0.5000, 0.0563, 0.6369, 0.2113, 0.7647,
105 0.3310, 0.8276, 0.5070, 0.8864, 0.7254, 0.9412,
111 double const brace[] = {
113 0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
114 0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
115 0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
116 0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
117 0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
118 0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
119 0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
124 double const mapsto[] = {
126 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
127 1, 0.015, 0.475, 0.945, 0.475,
128 1, 0.015, 0.015, 0.015, 0.985,
133 double const lhook[] = {
135 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
136 1, 0.015, 0.475, 0.7, 0.475,
138 0.7, 0.015, 0.825, 0.15, 0.985, 0.25,
139 0.825, 0.35, 0.7, 0.475,
144 double const rhook[] = {
146 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
147 1, 0.3, 0.475, 0.985, 0.475,
149 0.3, 0.015, 0.175, 0.15, 0.05, 0.25,
150 0.175, 0.35, 0.3, 0.475,
155 double const LRArrow[] = {
157 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
159 0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
160 1, 0.2, 0.8, 0.8, 0.8,
161 1, 0.2, 0.2, 0.8, 0.2,
166 double const LArrow[] = {
168 0.25, 0.015, 0.05, 0.5, 0.25, 0.985,
169 1, 0.2, 0.8, 0.985, 0.8,
170 1, 0.2, 0.2, 0.985, 0.2,
175 double const lharpoondown[] = {
177 0.015, 0.5, 0.25, 0.985,
178 1, 0.02, 0.475, 0.985, 0.475,
183 double const lharpoonup[] = {
185 0.25, 0.015, 0.015, 0.5,
186 1, 0.02, 0.525, 0.985, 0.525,
191 double const lrharpoons[] = {
193 0.25, 0.015, 0.015, 0.225,
194 1, 0.02, 0.23, 0.985, 0.23,
196 0.75, 0.985, 0.985, 0.775,
197 1, 0.02, 0.7, 0.980, 0.7,
202 double const rlharpoons[] = {
204 0.75, 0.015, 0.985, 0.225,
205 1, 0.02, 0.23, 0.985, 0.23,
207 0.25, 0.985, 0.015, 0.775,
208 1, 0.02, 0.7, 0.980, 0.7,
213 double const arrow[] = {
215 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
216 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
218 3, 0.5000, 0.1500, 0.5000, 0.9500,
223 double const Arrow[] = {
225 0.0150, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
226 0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
228 3, 0.3500, 0.5000, 0.3500, 0.9500,
229 3, 0.6500, 0.5000, 0.6500, 0.9500,
234 double const udarrow[] = {
236 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
238 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
239 1, 0.5, 0.1, 0.5, 0.9,
244 double const Udarrow[] = {
246 0.015, 0.25, 0.5, 0.05, 0.95, 0.25,
248 0.015, 0.75, 0.5, 0.95, 0.95, 0.75,
249 1, 0.35, 0.2, 0.35, 0.8,
250 1, 0.65, 0.2, 0.65, 0.8,
255 double const brack[] = {
257 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
262 double const dbrack[] = {
264 0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
266 0.50, 0.05, 0.50, 0.95,
271 double const corner[] = {
273 0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
278 double const angle[] = {
280 1, 0, 0.05, 0.5, 1, 1,
285 double const slash[] = {
286 1, 0.95, 0.05, 0.05, 0.95,
291 double const hline[] = {
292 1, 0.00, 0.5, 1.0, 0.5,
297 double const dot[] = {
298 // 1, 0.5, 0.2, 0.5, 0.2,
299 // 1, 0.4, 0.4, 0.6, 0.4,
300 // 1, 0.5, 0.5, 0.5, 0.5,
301 5, 0.4, 0.6, 0.6, 0.6,
306 double const ddot[] = {
307 5, 0.1, 0.6, 0.3, 0.6,
308 5, 0.6, 0.6, 0.8, 0.6,
313 double const dddot[] = {
314 5, -0.2, 0.6, 0.0, 0.6,
315 5, 0.3, 0.6, 0.5, 0.6,
316 5, 0.8, 0.6, 1.0, 0.6,
321 double const ddddot[] = {
322 5, -0.4, 0.6, -0.2, 0.6,
323 5, 0.1, 0.6, 0.3, 0.6,
324 5, 0.6, 0.6, 0.8, 0.6,
325 5, 1.1, 0.6, 1.3, 0.6,
330 double const hline3[] = {
332 1, 0.475, 0, 0.525, 0,
338 double const dline3[] = {
339 1, 0.1, 0.1, 0.15, 0.15,
340 1, 0.475, 0.475, 0.525, 0.525,
341 1, 0.85, 0.85, 0.9, 0.9,
346 double const ring[] = {
348 0.5, 0.8, 0.7, 0.7, 0.8, 0.4,
349 0.7, 0.1, 0.5, 0.0, 0.3, 0.1,
350 0.2, 0.4, 0.3, 0.7, 0.5, 0.8,
355 double const vert[] = {
356 1, 0.5, 0.05, 0.5, 0.95,
361 double const Vert[] = {
362 1, 0.3, 0.05, 0.3, 0.95,
363 1, 0.7, 0.05, 0.7, 0.95,
368 double const tilde[] = {
370 0.0, 0.8, 0.15, 0.2, 0.35, 0.2, 0.65, 0.8, 0.85, 0.8, 1.0, 0.2,
380 struct named_deco_struct {
386 named_deco_struct deco_table[] = {
388 {"widehat", angle, 3 },
389 {"widetilde", tilde, 0 },
390 {"underbar", hline, 0 },
391 {"underline", hline, 0 },
392 {"overline", hline, 0 },
393 {"underbrace", brace, 1 },
394 {"overbrace", brace, 3 },
395 {"overleftarrow", arrow, 1 },
396 {"overrightarrow", arrow, 3 },
397 {"overleftrightarrow", udarrow, 1 },
398 {"xhookleftarrow", lhook, 0 },
399 {"xhookrightarrow", rhook, 0 },
400 {"xleftarrow", arrow, 1 },
401 {"xLeftarrow", LArrow, 0 },
402 {"xleftharpoondown", lharpoondown, 0 },
403 {"xleftharpoonup", lharpoonup, 0 },
404 {"xleftrightharpoons", lrharpoons, 0 },
405 {"xleftrightarrow", udarrow, 1 },
406 {"xLeftrightarrow", LRArrow, 0 },
407 {"xmapsto", mapsto, 0 },
408 {"xrightarrow", arrow, 3 },
409 {"xRightarrow", LArrow, 2 },
410 {"xrightharpoondown", lharpoonup, 2 },
411 {"xrightharpoonup", lharpoondown, 2 },
412 {"xrightleftharpoons", rlharpoons, 0 },
413 {"underleftarrow", arrow, 1 },
414 {"underrightarrow", arrow, 3 },
415 {"underleftrightarrow", udarrow, 1 },
416 {"undertilde", tilde, 0 },
417 {"utilde", tilde, 0 },
424 {"lbrace", brace, 0 },
425 {"rbrace", brace, 2 },
428 {"llbracket", dbrack, 0 },
429 {"rrbracket", dbrack, 2 },
432 {"slash", slash, 0 },
443 {"backslash", slash, 1 },
444 {"langle", angle, 0 },
445 {"lceil", corner, 0 },
446 {"lfloor", corner, 1 },
447 {"rangle", angle, 2 },
448 {"rceil", corner, 3 },
449 {"rfloor", corner, 2 },
450 {"downarrow", arrow, 2 },
451 {"Downarrow", Arrow, 2 },
452 {"uparrow", arrow, 0 },
453 {"Uparrow", Arrow, 0 },
454 {"updownarrow", udarrow, 0 },
455 {"Updownarrow", Udarrow, 0 },
459 {"dddot", dddot, 0 },
460 {"ddddot", ddddot, 0 },
462 {"grave", slash, 1 },
463 {"acute", slash, 0 },
464 {"tilde", tilde, 0 },
467 {"check", angle, 1 },
468 {"breve", parenth, 1 },
470 {"mathring", ring, 0 },
473 {"dots", hline3, 0 },
474 {"ldots", hline3, 0 },
475 {"cdots", hline3, 0 },
476 {"vdots", hline3, 1 },
477 {"ddots", dline3, 0 },
478 {"adots", dline3, 1 },
479 {"iddots", dline3, 1 },
480 {"dotsb", hline3, 0 },
481 {"dotsc", hline3, 0 },
482 {"dotsi", hline3, 0 },
483 {"dotsm", hline3, 0 },
484 {"dotso", hline3, 0 }
488 map<docstring, deco_struct> deco_list;
490 // sort the table on startup
491 class init_deco_table {
494 unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
495 for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
499 deco_list[from_ascii(p->name)] = d;
504 static init_deco_table dummy_deco_table;
507 deco_struct const * search_deco(docstring const & name)
509 map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
510 return p == deco_list.end() ? 0 : &(p->second);
517 int mathed_font_em(FontInfo const & font)
519 return theFontMetrics(font).em();
523 int mathed_font_x_height(FontInfo const & font)
525 return theFontMetrics(font).xHeight();
528 /* The math units. Quoting TeX by Topic, p.205:
530 * Spacing around mathematical objects is measured in mu units. A mu
531 * is 1/18th part of \fontdimen6 of the font in family 2 in the
532 * current style, the ‘quad’ value of the symbol font.
534 * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
535 * inserted around (binary) relations, except where these are preceded
536 * or followed by other relations or punctuation, and except if they
537 * follow an open, or precede a close symbol.
539 * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
540 * is put around binary operators.
542 * A \thinmuskip (default value in plain TeX: 3mu) follows after
543 * punctuation, and is put around inner objects, except where these
544 * are followed by a close or preceded by an open symbol, and except
545 * if the other object is a large operator or a binary relation.
547 * See the file MathClass.cpp for a formal implementation of the rules
551 int mathed_mu(FontInfo const & font, double mu)
553 MetricsBase mb(nullptr, font);
554 return mb.inPixels(Length(mu, Length::MU));
557 int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
558 int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
559 int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
562 int mathed_char_width(FontInfo const & font, char_type c)
564 return theFontMetrics(font).width(c);
568 int mathed_char_kerning(FontInfo const & font, char_type c)
570 frontend::FontMetrics const & fm = theFontMetrics(font);
571 return max(0, fm.rbearing(c) - fm.width(c));
575 void mathed_string_dim(FontInfo const & font,
579 frontend::FontMetrics const & fm = theFontMetrics(font);
582 for (char_type const c : s) {
583 dim.asc = max(dim.asc, fm.ascent(c));
584 dim.des = max(dim.des, fm.descent(c));
586 dim.wid = fm.width(s);
590 int mathed_string_width(FontInfo const & font, docstring const & s)
592 return theFontMetrics(font).width(s);
596 void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
597 docstring const & name)
599 int const lw = pi.base.solidLineThickness();
602 pi.pain.line(x + w/2, y, x + w/2, y + h,
603 Color_cursor, Painter::line_onoffdash, lw);
607 deco_struct const * mds = search_deco(name);
609 lyxerr << "Deco was not found. Programming error?" << endl;
610 lyxerr << "name: '" << to_utf8(name) << "'" << endl;
614 int const n = (w < h) ? w : h;
615 int const r = mds->angle;
616 double const * d = mds->data;
618 if (h > 70 && (name == "(" || name == ")"))
622 Matrix sqmt(r, n, n);
630 for (int i = 0; d[i]; ) {
631 int code = int(d[i++]);
632 if (code & 1) { // code == 1 || code == 3 || code == 5
638 sqmt.transform(xx, yy);
640 mt.transform(xx, yy);
641 mt.transform(x2, y2);
643 int(x + xx + 0.5), int(y + yy + 0.5),
644 int(x + x2 + 0.5), int(y + y2 + 0.5),
645 pi.base.font.color(), Painter::line_solid, lw);
646 if (code == 5) { // thicker, but rounded
647 double const xa = x + xx + 0.5;
648 double const xb = x + x2 + 0.5;
649 double const ya = y + yy + 0.5;
650 double const yb = y + y2 + 0.5;
651 pi.pain.line(int(xa + 1), int(ya - 1),
652 int(xb - 1), int(yb - 1),
653 pi.base.font.color(),
654 Painter::line_solid, lw);
655 pi.pain.line(int(xa + 1), int(ya + 1),
656 int(xb - 1), int(yb + 1),
657 pi.base.font.color(),
658 Painter::line_solid, lw);
659 if (xa + 2 <= xb - 2) {
660 pi.pain.line(int(xa + 2), int(ya - 2),
661 int(xb - 2), int(yb - 2),
662 pi.base.font.color(),
663 Painter::line_solid, lw);
664 pi.pain.line(int(xa + 2), int(ya + 2),
665 int(xb - 2), int(yb + 2),
666 pi.base.font.color(),
667 Painter::line_solid, lw);
669 if (xa + 3 <= xb - 3) {
670 pi.pain.line(int(xa + 3), int(ya - 3),
671 int(xb - 3), int(yb - 3),
672 pi.base.font.color(),
673 Painter::line_solid, lw);
674 pi.pain.line(int(xa + 3), int(ya + 3),
675 int(xb - 3), int(yb + 3),
676 pi.base.font.color(),
677 Painter::line_solid, lw);
679 if (xa + 4 <= xb - 4) {
680 pi.pain.line(int(xa + 4), int(ya - 4),
681 int(xb - 4), int(yb - 4),
682 pi.base.font.color(),
683 Painter::line_solid, lw);
684 pi.pain.line(int(xa + 4), int(ya + 4),
685 int(xb - 4), int(yb + 4),
686 pi.base.font.color(),
687 Painter::line_solid, lw);
693 int const n2 = int(d[i++]);
694 for (int j = 0; j < n2; ++j) {
697 // lyxerr << ' ' << xx << ' ' << yy << ' ';
699 sqmt.transform(xx, yy);
701 mt.transform(xx, yy);
702 xp[j] = int(x + xx + 0.5);
703 yp[j] = int(y + yy + 0.5);
704 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
706 pi.pain.lines(xp, yp, n2, pi.base.font.color(),
707 Painter::fill_none, Painter::line_solid, lw);
713 docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
715 return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
716 sym->dsp_draw : sym->draw;
720 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
722 LASSERT((bool)sym, return 0);
723 //lyxerr << "metrics: symbol: '" << sym->name
724 // << "' in font: '" << sym->inset
725 // << "' drawn as: '" << sym->draw
728 bool const italic_upcase_greek = sym->inset == "cmr" &&
729 sym->extra == "mathalpha" &&
730 mb.fontname == "mathit";
731 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
732 bool const change_font = font != "cmr" ||
733 (mb.fontname != "mathbb" &&
734 mb.fontname != "mathds" &&
735 mb.fontname != "mathfrak" &&
736 mb.fontname != "mathcal" &&
737 mb.fontname != "mathscr");
738 Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
739 mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
740 return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
744 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
746 LASSERT((bool)sym, return);
747 //lyxerr << "drawing: symbol: '" << sym->name
748 // << "' in font: '" << sym->inset
749 // << "' drawn as: '" << sym->draw
752 bool const italic_upcase_greek = sym->inset == "cmr" &&
753 sym->extra == "mathalpha" &&
754 pi.base.fontname == "mathit";
755 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
756 bool const change_font = font != "cmr" ||
757 (pi.base.fontname != "mathbb" &&
758 pi.base.fontname != "mathds" &&
759 pi.base.fontname != "mathfrak" &&
760 pi.base.fontname != "mathcal" &&
761 pi.base.fontname != "mathscr");
762 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
763 pi.draw(x, y, mathedSymbol(pi.base, sym));
767 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
769 FontInfo font = mi.base.font;
770 augmentFont(font, "mathnormal");
771 mathed_string_dim(font, str, dim);
775 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
777 FontInfo f = pi.base.font;
778 augmentFont(f, "mathnormal");
779 f.setColor(Color_latex);
780 pi.pain.text(x, y, str, f);
784 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
786 FontInfo f = pi.base.font;
787 augmentFont(f, "mathnormal");
788 f.setColor(Color_foreground);
789 pi.pain.text(x, y, str, f);
793 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
795 frontend::FontMetrics const & fm = theFontMetrics(font);
796 asc = fm.maxAscent();
797 des = fm.maxDescent();
810 FontFamily const inh_family = INHERIT_FAMILY;
811 FontSeries const inh_series = INHERIT_SERIES;
812 FontShape const inh_shape = INHERIT_SHAPE;
815 // mathnormal should be the first, otherwise the fallback further down
817 fontinfo fontinfos[] = {
819 // Color_math determines which fonts are math (see isMathFont)
820 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
821 ITALIC_SHAPE, Color_math},
822 {"mathbf", inh_family, BOLD_SERIES,
823 inh_shape, Color_math},
824 {"mathcal", CMSY_FAMILY, inh_series,
825 inh_shape, Color_math},
826 {"mathfrak", EUFRAK_FAMILY, inh_series,
827 inh_shape, Color_math},
828 {"mathrm", ROMAN_FAMILY, inh_series,
829 UP_SHAPE, Color_math},
830 {"mathsf", SANS_FAMILY, inh_series,
831 inh_shape, Color_math},
832 {"mathbb", MSB_FAMILY, inh_series,
833 inh_shape, Color_math},
834 {"mathds", DS_FAMILY, inh_series,
835 inh_shape, Color_math},
836 {"mathtt", TYPEWRITER_FAMILY, inh_series,
837 inh_shape, Color_math},
838 {"mathit", inh_family, inh_series,
839 ITALIC_SHAPE, Color_math},
840 {"mathscr", RSFS_FAMILY, inh_series,
841 inh_shape, Color_math},
842 {"cmex", CMEX_FAMILY, inh_series,
843 inh_shape, Color_math},
844 {"cmm", CMM_FAMILY, inh_series,
845 inh_shape, Color_math},
846 {"cmr", CMR_FAMILY, inh_series,
847 inh_shape, Color_math},
848 {"cmsy", CMSY_FAMILY, inh_series,
849 inh_shape, Color_math},
850 {"eufrak", EUFRAK_FAMILY, inh_series,
851 inh_shape, Color_math},
852 {"msa", MSA_FAMILY, inh_series,
853 inh_shape, Color_math},
854 {"msb", MSB_FAMILY, inh_series,
855 inh_shape, Color_math},
856 {"stmry", STMARY_FAMILY, inh_series,
857 inh_shape, Color_math},
858 {"wasy", WASY_FAMILY, inh_series,
859 inh_shape, Color_math},
860 {"esint", ESINT_FAMILY, inh_series,
861 inh_shape, Color_math},
864 {"text", inh_family, inh_series,
865 inh_shape, Color_foreground},
866 {"textbf", inh_family, BOLD_SERIES,
867 inh_shape, Color_foreground},
868 {"textit", inh_family, inh_series,
869 ITALIC_SHAPE, Color_foreground},
870 {"textmd", inh_family, MEDIUM_SERIES,
871 inh_shape, Color_foreground},
872 {"textnormal", inh_family, inh_series,
873 UP_SHAPE, Color_foreground},
874 {"textrm", ROMAN_FAMILY,
875 inh_series, UP_SHAPE,Color_foreground},
876 {"textsc", inh_family, inh_series,
877 SMALLCAPS_SHAPE, Color_foreground},
878 {"textsf", SANS_FAMILY, inh_series,
879 inh_shape, Color_foreground},
880 {"textsl", inh_family, inh_series,
881 SLANTED_SHAPE, Color_foreground},
882 {"texttt", TYPEWRITER_FAMILY, inh_series,
883 inh_shape, Color_foreground},
884 {"textup", inh_family, inh_series,
885 UP_SHAPE, Color_foreground},
888 {"textipa", inh_family, inh_series,
889 inh_shape, Color_foreground},
892 {"ce", inh_family, inh_series,
893 inh_shape, Color_foreground},
894 {"cf", inh_family, inh_series,
895 inh_shape, Color_foreground},
897 // LyX internal usage
898 {"lyxtex", inh_family, inh_series,
899 UP_SHAPE, Color_latex},
900 // FIXME: The following two don't work on OS X, since the Symbol font
901 // uses a different encoding, and is therefore disabled in
902 // FontLoader::available().
903 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
904 inh_shape, Color_math},
905 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
906 inh_shape, Color_math},
907 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
908 UP_SHAPE, Color_foreground},
909 {"lyxnochange", inh_family, inh_series,
910 inh_shape, Color_foreground},
911 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
912 UP_SHAPE, Color_math},
913 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
914 ITALIC_SHAPE, Color_math},
915 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
916 ITALIC_SHAPE, Color_math}
920 fontinfo * lookupFont(string const & name)
922 //lyxerr << "searching font '" << name << "'" << endl;
923 int const n = sizeof(fontinfos) / sizeof(fontinfo);
924 for (int i = 0; i < n; ++i)
925 if (fontinfos[i].cmd_ == name) {
926 //lyxerr << "found '" << i << "'" << endl;
927 return fontinfos + i;
933 fontinfo * searchFont(string const & name)
935 fontinfo * f = lookupFont(name);
936 return f ? f : fontinfos;
937 // this should be mathnormal
938 //return searchFont("mathnormal");
942 bool isFontName(string const & name)
944 return lookupFont(name);
948 bool isMathFont(string const & name)
950 fontinfo * f = lookupFont(name);
951 return f && f->color_ == Color_math;
955 bool isTextFont(string const & name)
957 fontinfo * f = lookupFont(name);
958 return f && f->color_ == Color_foreground;
962 FontInfo getFont(string const & name)
965 augmentFont(font, name);
970 void fakeFont(string const & orig, string const & fake)
972 fontinfo * forig = searchFont(orig);
973 fontinfo * ffake = searchFont(fake);
974 if (forig && ffake) {
975 forig->family_ = ffake->family_;
976 forig->series_ = ffake->series_;
977 forig->shape_ = ffake->shape_;
978 forig->color_ = ffake->color_;
980 lyxerr << "Can't fake font '" << orig << "' with '"
981 << fake << "'" << endl;
986 void augmentFont(FontInfo & font, string const & name)
988 static bool initialized = false;
991 // fake fonts if necessary
992 if (!theFontLoader().available(getFont("mathfrak")))
993 fakeFont("mathfrak", "lyxfakefrak");
994 if (!theFontLoader().available(getFont("mathcal")))
995 fakeFont("mathcal", "lyxfakecal");
997 fontinfo * info = searchFont(name);
998 if (info->family_ != inh_family)
999 font.setFamily(info->family_);
1000 if (info->series_ != inh_series)
1001 font.setSeries(info->series_);
1002 if (info->shape_ != inh_shape)
1003 font.setShape(info->shape_);
1004 if (info->color_ != Color_none)
1005 font.setColor(info->color_);
1009 bool isAlphaSymbol(MathAtom const & at)
1011 if (at->asCharInset() ||
1012 (at->asSymbolInset() &&
1013 at->asSymbolInset()->isOrdAlpha()))
1016 if (at->asFontInset()) {
1017 MathData const & ar = at->asFontInset()->cell(0);
1018 for (size_t i = 0; i < ar.size(); ++i) {
1019 if (!(ar[i]->asCharInset() ||
1020 (ar[i]->asSymbolInset() &&
1021 ar[i]->asSymbolInset()->isOrdAlpha())))
1030 docstring asString(MathData const & ar)
1032 odocstringstream os;
1033 otexrowstream ots(os);
1034 TeXMathStream ws(ots);
1040 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1042 // If the QUIET flag is set, we are going to parse for either
1043 // a paste operation or a macro definition. We try to do the
1044 // right thing in all cases.
1046 bool quiet = pf & Parse::QUIET;
1047 bool macro = pf & Parse::MACRODEF;
1048 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1049 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1053 docstring asString(InsetMath const & inset)
1055 odocstringstream os;
1056 otexrowstream ots(os);
1057 TeXMathStream ws(ots);
1063 docstring asString(MathAtom const & at)
1065 odocstringstream os;
1066 otexrowstream ots(os);
1067 TeXMathStream ws(ots);
1073 int axis_height(MetricsBase & mb)
1075 Changer dummy = mb.changeFontSet("mathnormal");
1076 return theFontMetrics(mb.font).ascent('-') - 1;
1080 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1082 MathWordList const & words = mathedWordList();
1083 MathWordList::const_iterator it = words.find(word);
1084 if (it != words.end()) {
1085 string const req = it->second.required;
1087 features.require(req);