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
648 int(x + xx + 0.5+1), int(y + yy + 0.5-1),
649 int(x + x2 + 0.5-1), int(y + y2 + 0.5-1),
650 pi.base.font.color(), Painter::line_solid, lw);
652 int(x + xx + 0.5+1), int(y + yy + 0.5+1),
653 int(x + x2 + 0.5-1), int(y + y2 + 0.5+1),
654 pi.base.font.color(), Painter::line_solid, lw);
659 int const n2 = int(d[i++]);
660 for (int j = 0; j < n2; ++j) {
663 // lyxerr << ' ' << xx << ' ' << yy << ' ';
665 sqmt.transform(xx, yy);
667 mt.transform(xx, yy);
668 xp[j] = int(x + xx + 0.5);
669 yp[j] = int(y + yy + 0.5);
670 // lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
672 pi.pain.lines(xp, yp, n2, pi.base.font.color(),
673 Painter::fill_none, Painter::line_solid, lw);
679 docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
681 return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
682 sym->dsp_draw : sym->draw;
686 int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
688 LASSERT((bool)sym, return 0);
689 //lyxerr << "metrics: symbol: '" << sym->name
690 // << "' in font: '" << sym->inset
691 // << "' drawn as: '" << sym->draw
694 bool const italic_upcase_greek = sym->inset == "cmr" &&
695 sym->extra == "mathalpha" &&
696 mb.fontname == "mathit";
697 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
698 bool const change_font = font != "cmr" ||
699 (mb.fontname != "mathbb" &&
700 mb.fontname != "mathds" &&
701 mb.fontname != "mathfrak" &&
702 mb.fontname != "mathcal" &&
703 mb.fontname != "mathscr");
704 Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
705 mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
706 return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
710 void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
712 LASSERT((bool)sym, return);
713 //lyxerr << "drawing: symbol: '" << sym->name
714 // << "' in font: '" << sym->inset
715 // << "' drawn as: '" << sym->draw
718 bool const italic_upcase_greek = sym->inset == "cmr" &&
719 sym->extra == "mathalpha" &&
720 pi.base.fontname == "mathit";
721 std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
722 bool const change_font = font != "cmr" ||
723 (pi.base.fontname != "mathbb" &&
724 pi.base.fontname != "mathds" &&
725 pi.base.fontname != "mathfrak" &&
726 pi.base.fontname != "mathcal" &&
727 pi.base.fontname != "mathscr");
728 Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
729 pi.draw(x, y, mathedSymbol(pi.base, sym));
733 void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
735 FontInfo font = mi.base.font;
736 augmentFont(font, "mathnormal");
737 mathed_string_dim(font, str, dim);
741 void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
743 FontInfo f = pi.base.font;
744 augmentFont(f, "mathnormal");
745 f.setColor(Color_latex);
746 pi.pain.text(x, y, str, f);
750 void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
752 FontInfo f = pi.base.font;
753 augmentFont(f, "mathnormal");
754 f.setColor(Color_foreground);
755 pi.pain.text(x, y, str, f);
759 void math_font_max_dim(FontInfo const & font, int & asc, int & des)
761 frontend::FontMetrics const & fm = theFontMetrics(font);
762 asc = fm.maxAscent();
763 des = fm.maxDescent();
776 FontFamily const inh_family = INHERIT_FAMILY;
777 FontSeries const inh_series = INHERIT_SERIES;
778 FontShape const inh_shape = INHERIT_SHAPE;
781 // mathnormal should be the first, otherwise the fallback further down
783 fontinfo fontinfos[] = {
785 // Color_math determines which fonts are math (see isMathFont)
786 {"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
787 ITALIC_SHAPE, Color_math},
788 {"mathbf", inh_family, BOLD_SERIES,
789 inh_shape, Color_math},
790 {"mathcal", CMSY_FAMILY, inh_series,
791 inh_shape, Color_math},
792 {"mathfrak", EUFRAK_FAMILY, inh_series,
793 inh_shape, Color_math},
794 {"mathrm", ROMAN_FAMILY, inh_series,
795 UP_SHAPE, Color_math},
796 {"mathsf", SANS_FAMILY, inh_series,
797 inh_shape, Color_math},
798 {"mathbb", MSB_FAMILY, inh_series,
799 inh_shape, Color_math},
800 {"mathds", DS_FAMILY, inh_series,
801 inh_shape, Color_math},
802 {"mathtt", TYPEWRITER_FAMILY, inh_series,
803 inh_shape, Color_math},
804 {"mathit", inh_family, inh_series,
805 ITALIC_SHAPE, Color_math},
806 {"mathscr", RSFS_FAMILY, inh_series,
807 inh_shape, Color_math},
808 {"cmex", CMEX_FAMILY, inh_series,
809 inh_shape, Color_math},
810 {"cmm", CMM_FAMILY, inh_series,
811 inh_shape, Color_math},
812 {"cmr", CMR_FAMILY, inh_series,
813 inh_shape, Color_math},
814 {"cmsy", CMSY_FAMILY, inh_series,
815 inh_shape, Color_math},
816 {"eufrak", EUFRAK_FAMILY, inh_series,
817 inh_shape, Color_math},
818 {"msa", MSA_FAMILY, inh_series,
819 inh_shape, Color_math},
820 {"msb", MSB_FAMILY, inh_series,
821 inh_shape, Color_math},
822 {"stmry", STMARY_FAMILY, inh_series,
823 inh_shape, Color_math},
824 {"wasy", WASY_FAMILY, inh_series,
825 inh_shape, Color_math},
826 {"esint", ESINT_FAMILY, inh_series,
827 inh_shape, Color_math},
830 {"text", inh_family, inh_series,
831 inh_shape, Color_foreground},
832 {"textbf", inh_family, BOLD_SERIES,
833 inh_shape, Color_foreground},
834 {"textit", inh_family, inh_series,
835 ITALIC_SHAPE, Color_foreground},
836 {"textmd", inh_family, MEDIUM_SERIES,
837 inh_shape, Color_foreground},
838 {"textnormal", inh_family, inh_series,
839 UP_SHAPE, Color_foreground},
840 {"textrm", ROMAN_FAMILY,
841 inh_series, UP_SHAPE,Color_foreground},
842 {"textsc", inh_family, inh_series,
843 SMALLCAPS_SHAPE, Color_foreground},
844 {"textsf", SANS_FAMILY, inh_series,
845 inh_shape, Color_foreground},
846 {"textsl", inh_family, inh_series,
847 SLANTED_SHAPE, Color_foreground},
848 {"texttt", TYPEWRITER_FAMILY, inh_series,
849 inh_shape, Color_foreground},
850 {"textup", inh_family, inh_series,
851 UP_SHAPE, Color_foreground},
854 {"textipa", inh_family, inh_series,
855 inh_shape, Color_foreground},
858 {"ce", inh_family, inh_series,
859 inh_shape, Color_foreground},
860 {"cf", inh_family, inh_series,
861 inh_shape, Color_foreground},
863 // LyX internal usage
864 {"lyxtex", inh_family, inh_series,
865 UP_SHAPE, Color_latex},
866 // FIXME: The following two don't work on OS X, since the Symbol font
867 // uses a different encoding, and is therefore disabled in
868 // FontLoader::available().
869 {"lyxsymbol", SYMBOL_FAMILY, inh_series,
870 inh_shape, Color_math},
871 {"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
872 inh_shape, Color_math},
873 {"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
874 UP_SHAPE, Color_foreground},
875 {"lyxnochange", inh_family, inh_series,
876 inh_shape, Color_foreground},
877 {"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
878 UP_SHAPE, Color_math},
879 {"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
880 ITALIC_SHAPE, Color_math},
881 {"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
882 ITALIC_SHAPE, Color_math}
886 fontinfo * lookupFont(string const & name)
888 //lyxerr << "searching font '" << name << "'" << endl;
889 int const n = sizeof(fontinfos) / sizeof(fontinfo);
890 for (int i = 0; i < n; ++i)
891 if (fontinfos[i].cmd_ == name) {
892 //lyxerr << "found '" << i << "'" << endl;
893 return fontinfos + i;
899 fontinfo * searchFont(string const & name)
901 fontinfo * f = lookupFont(name);
902 return f ? f : fontinfos;
903 // this should be mathnormal
904 //return searchFont("mathnormal");
908 bool isFontName(string const & name)
910 return lookupFont(name);
914 bool isMathFont(string const & name)
916 fontinfo * f = lookupFont(name);
917 return f && f->color_ == Color_math;
921 bool isTextFont(string const & name)
923 fontinfo * f = lookupFont(name);
924 return f && f->color_ == Color_foreground;
928 FontInfo getFont(string const & name)
931 augmentFont(font, name);
936 void fakeFont(string const & orig, string const & fake)
938 fontinfo * forig = searchFont(orig);
939 fontinfo * ffake = searchFont(fake);
940 if (forig && ffake) {
941 forig->family_ = ffake->family_;
942 forig->series_ = ffake->series_;
943 forig->shape_ = ffake->shape_;
944 forig->color_ = ffake->color_;
946 lyxerr << "Can't fake font '" << orig << "' with '"
947 << fake << "'" << endl;
952 void augmentFont(FontInfo & font, string const & name)
954 static bool initialized = false;
957 // fake fonts if necessary
958 if (!theFontLoader().available(getFont("mathfrak")))
959 fakeFont("mathfrak", "lyxfakefrak");
960 if (!theFontLoader().available(getFont("mathcal")))
961 fakeFont("mathcal", "lyxfakecal");
963 fontinfo * info = searchFont(name);
964 if (info->family_ != inh_family)
965 font.setFamily(info->family_);
966 if (info->series_ != inh_series)
967 font.setSeries(info->series_);
968 if (info->shape_ != inh_shape)
969 font.setShape(info->shape_);
970 if (info->color_ != Color_none)
971 font.setColor(info->color_);
975 bool isAlphaSymbol(MathAtom const & at)
977 if (at->asCharInset() ||
978 (at->asSymbolInset() &&
979 at->asSymbolInset()->isOrdAlpha()))
982 if (at->asFontInset()) {
983 MathData const & ar = at->asFontInset()->cell(0);
984 for (size_t i = 0; i < ar.size(); ++i) {
985 if (!(ar[i]->asCharInset() ||
986 (ar[i]->asSymbolInset() &&
987 ar[i]->asSymbolInset()->isOrdAlpha())))
996 docstring asString(MathData const & ar)
999 otexrowstream ots(os);
1000 TeXMathStream ws(ots);
1006 void asArray(docstring const & str, MathData & ar, Parse::flags pf)
1008 // If the QUIET flag is set, we are going to parse for either
1009 // a paste operation or a macro definition. We try to do the
1010 // right thing in all cases.
1012 bool quiet = pf & Parse::QUIET;
1013 bool macro = pf & Parse::MACRODEF;
1014 if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
1015 mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
1019 docstring asString(InsetMath const & inset)
1021 odocstringstream os;
1022 otexrowstream ots(os);
1023 TeXMathStream ws(ots);
1029 docstring asString(MathAtom const & at)
1031 odocstringstream os;
1032 otexrowstream ots(os);
1033 TeXMathStream ws(ots);
1039 int axis_height(MetricsBase & mb)
1041 Changer dummy = mb.changeFontSet("mathnormal");
1042 return theFontMetrics(mb.font).ascent('-') - 1;
1046 void validate_math_word(LaTeXFeatures & features, docstring const & word)
1048 MathWordList const & words = mathedWordList();
1049 MathWordList::const_iterator it = words.find(word);
1050 if (it != words.end()) {
1051 string const req = it->second.required;
1053 features.require(req);