lyx_mirror/src/mathed/MathSupport.cpp
Enrico Forestieri 7b526d6461 Fix bug #3751
We lack the necessary font (cmb10) for drawing bold uppercase greek
letters. It would be overkill adding it for this sole purpose, so
adopt the same poor man's bold strategy used with \boldsymbol.
2021-02-27 21:40:28 +01:00

1121 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* \file MathSupport.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Alejandro Aguilar Sierra
* \author André Pönitz
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "MathSupport.h"
#include "InsetMathFont.h"
#include "InsetMathSymbol.h"
#include "MathData.h"
#include "MathFactory.h"
#include "MathParser.h"
#include "MathStream.h"
#include "Encoding.h"
#include "LaTeXFeatures.h"
#include "MetricsInfo.h"
#include "frontends/FontLoader.h"
#include "frontends/FontMetrics.h"
#include "frontends/Painter.h"
#include "support/Changer.h"
#include "support/debug.h"
#include "support/docstream.h"
#include "support/lassert.h"
#include "support/Length.h"
#include "support/textutils.h"
#include <map>
#include <algorithm>
using namespace std;
namespace lyx {
using frontend::Painter;
///
class Matrix {
public:
///
Matrix(int, double, double);
///
void transform(double &, double &);
private:
///
double m_[2][2];
};
Matrix::Matrix(int code, double x, double y)
{
double const cs = (code & 1) ? 0 : (1 - code);
double const sn = (code & 1) ? (2 - code) : 0;
m_[0][0] = cs * x;
m_[0][1] = sn * x;
m_[1][0] = -sn * y;
m_[1][1] = cs * y;
}
void Matrix::transform(double & x, double & y)
{
double xx = m_[0][0] * x + m_[0][1] * y;
double yy = m_[1][0] * x + m_[1][1] * y;
x = xx;
y = yy;
}
namespace {
/*
* Internal struct of a drawing: code n x1 y1 ... xn yn, where code is:
* 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline,
* 5 = ellipse with given center and horizontal and vertical radii,
* 6 = shifted square polyline drawn at the other end
*/
double const parenthHigh[] = {
2, 13,
0.9840, 0.0014, 0.7143, 0.0323, 0.4603, 0.0772,
0.2540, 0.1278, 0.1746, 0.1966, 0.0952, 0.3300,
0.0950, 0.5000, 0.0952, 0.6700, 0.1746, 0.8034,
0.2540, 0.8722, 0.4603, 0.9228, 0.7143, 0.9677,
0.9840, 0.9986,
0
};
double const parenth[] = {
2, 13,
0.9930, 0.0071, 0.7324, 0.0578, 0.5141, 0.1126,
0.3380, 0.1714, 0.2183, 0.2333, 0.0634, 0.3621,
0.0141, 0.5000, 0.0634, 0.6379, 0.2183, 0.7667,
0.3380, 0.8286, 0.5141, 0.8874, 0.7324, 0.9422,
0.9930, 0.9929,
0
};
double const breve[] = {
2, 8,
0.100, 0.400, 0.125, 0.550, 0.200, 0.700, 0.400, 0.800,
0.600, 0.800, 0.800, 0.700, 0.875, 0.550, 0.900, 0.400,
0
};
double const brace[] = {
2, 21,
0.9492, 0.0020, 0.9379, 0.0020, 0.7458, 0.0243,
0.5819, 0.0527, 0.4859, 0.0892, 0.4463, 0.1278,
0.4463, 0.3732, 0.4011, 0.4199, 0.2712, 0.4615,
0.0734, 0.4919, 0.0113, 0.5000, 0.0734, 0.5081,
0.2712, 0.5385, 0.4011, 0.5801, 0.4463, 0.6268,
0.4463, 0.8722, 0.4859, 0.9108, 0.5819, 0.9473,
0.7458, 0.9757, 0.9379, 0.9980, 0.9492, 0.9980,
0
};
double const mapsto[] = {
2, 3,
0.75, 0.015, 0.95, 0.5, 0.75, 0.985,
1, 0.015, 0.475, 0.945, 0.475,
1, 0.015, 0.015, 0.015, 0.985,
0
};
double const lhook[] = {
4, 7,
1.40, -0.30, 1.10, 0.00, 0.60, 0.35,
0.00, 0.60, 0.60, 0.85, 1.10, 1.20,
1.40, 1.50,
3, 0.05, 0.6, 1.0, 0.6,
6, -0.5, 0.0, 6,
0.65, -0.40, 0.95, -0.35, 1.15, -0.10,
1.15, 0.25, 0.95, 0.50, 0.65, 0.60,
0
};
double const rhook[] = {
4, 6,
0.50, -0.40, 0.20, -0.35, 0.00, -0.10,
0.00, 0.25, 0.20, 0.50, 0.50, 0.60,
3, 0.55, 0.60, 1.00, 0.60,
6, -0.8, 0.0, 7,
0.00, -0.30, 0.30, 0.00, 0.80, 0.35, 1.40, 0.60,
0.80, 0.85, 0.30, 1.20, 0.00, 1.50,
0
};
double const LRArrow[] = {
4, 7,
1.300, -0.300, 1.100, 0.000, 0.600, 0.350,
0.000, 0.600, 0.600, 0.850, 1.100, 1.200,
1.300, 1.500,
6, -0.1, 0.0, 7,
-0.300, -0.300, -0.100, 0.000, 0.400, 0.350,
1.000, 0.600, 0.400, 0.850, -0.100, 1.200,
-0.300, 1.500,
3, 0.85, 1.0, 1.0, 1.0,
3, 0.85, 0.2, 1.0, 0.2,
0
};
double const LArrow[] = {
4, 7,
1.300, -0.300, 1.100, 0.000, 0.600, 0.350,
0.000, 0.600, 0.600, 0.850, 1.100, 1.200,
1.300, 1.500,
3, 0.85, 1.0, 1.0, 1.0,
3, 0.85, 0.2, 1.0, 0.2,
0
};
double const lharpoondown[] = {
4, 4,
0.0, 0.6, 0.6, 0.85, 1.1, 1.2, 1.4, 1.5,
3, 0.05, 0.6, 1.0, 0.6,
0
};
double const lharpoonup[] = {
4, 4,
0.0, 0.6, 0.6, 0.35, 1.1, 0.0, 1.4, -0.3,
3, 0.05, 0.6, 1.0, 0.6,
0
};
double const lrharpoons[] = {
4, 4,
0.0, 0.6, 0.6, 0.35, 1.1, 0.0, 1.4, -0.3,
3, 0.05, 0.6, 1.0, 0.6,
3, 0.05, 1.2, 1.0, 1.2,
6, -1.0, 0.0, 4,
1.1, 1.3, 0.4, 1.55, -0.1, 1.9, -0.4, 2.2,
0
};
double const rlharpoons[] = {
6, -1.0, 0.0, 4,
-0.4, -0.4, -0.1, -0.1, 0.4, 0.25, 1.0, 0.5,
3, 0.05, 0.6, 1.0, 0.6,
3, 0.05, 1.2, 1.0, 1.2,
4, 4,
0.0, 1.2, 0.6, 1.45, 1.1, 1.8, 1.4, 2.1,
0
};
double const vec[] = {
4, 7,
0.2000, 0.5000, 0.3000, 0.4000, 0.4000, 0.2500,
0.5000, 0.0000, 0.6000, 0.2500, 0.7000, 0.4000,
0.8000, 0.5000,
3, 0.5000, 0.1000, 0.5000, 0.9500,
0
};
double const arrow[] = {
4, 7,
0.0500, 0.7500, 0.2000, 0.6000, 0.3500, 0.3500,
0.5000, 0.0500, 0.6500, 0.3500, 0.8000, 0.6000,
0.9500, 0.7500,
3, 0.5000, 0.1500, 0.5000, 1.0000,
0
};
double const Arrow[] = {
4, 7,
0.0000, 0.7500, 0.1500, 0.6000, 0.3500, 0.3500,
0.5000, 0.0500, 0.6500, 0.3500, 0.8500, 0.6000,
1.0000, 0.7500,
3, 0.3000, 0.4500, 0.3000, 1.0000,
3, 0.7000, 0.4500, 0.7000, 1.0000,
0
};
double const udarrow[] = {
4, 7,
0.0500, 0.6500, 0.2000, 0.5000, 0.3500, 0.2500,
0.5000, -0.0500, 0.6500, 0.2500, 0.8000, 0.5000,
0.9500, 0.6500,
6, 0.0, -1.0, 7,
0.0500, 0.2500, 0.2000, 0.4000, 0.3500, 0.6500,
0.5000, 0.9500, 0.6500, 0.6500, 0.8000, 0.4000,
0.9500, 0.2500,
3, 0.5, 0.0, 0.5, 1.0,
0
};
double const Udarrow[] = {
4, 7,
0.0000, 0.7500, 0.1500, 0.6000, 0.3500, 0.3500,
0.5000, 0.0500, 0.6500, 0.3500, 0.8500, 0.6000,
1.0000, 0.7500,
6, 0.0, -1.0, 7,
0.0000, 0.2500, 0.1500, 0.4000, 0.3500, 0.6500,
0.5000, 0.9500, 0.6500, 0.6500, 0.8500, 0.4000,
1.0000, 0.2500,
3, 0.3000, 0.4500, 0.3000, 0.9500,
3, 0.7000, 0.4500, 0.7000, 0.9500,
0
};
double const brack[] = {
2, 4,
0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
0
};
double const dbrack[] = {
2, 4,
0.95, 0.05, 0.05, 0.05, 0.05, 0.95, 0.95, 0.95,
2, 2,
0.50, 0.05, 0.50, 0.95,
0
};
double const corner[] = {
2, 3,
0.95, 0.05, 0.05, 0.05, 0.05, 0.95,
0
};
double const angle[] = {
2, 3,
0.9, 0.05, 0.05, 0.5, 0.9, 0.95,
0
};
double const slash[] = {
1, 0.95, 0.05, 0.05, 0.95,
0
};
double const hline[] = {
1, 0.00, 0.5, 1.0, 0.5,
0
};
double const dot[] = {
5, 0.5, 0.5, 0.1, 0.1,
0
};
double const ddot[] = {
5, 0.2, 0.5, 0.1, 0.1,
5, 0.7, 0.5, 0.1, 0.1,
0
};
double const dddot[] = {
5, 0.1, 0.5, 0.1, 0.1,
5, 0.5, 0.5, 0.1, 0.1,
5, 0.9, 0.5, 0.1, 0.1,
0
};
double const ddddot[] = {
5, -0.1, 0.5, 0.1, 0.1,
5, 0.3, 0.5, 0.1, 0.1,
5, 0.7, 0.5, 0.1, 0.1,
5, 1.1, 0.5, 0.1, 0.1,
0
};
double const hline3[] = {
5, 0.15, 0.0, 0.0625, 0.0625,
5, 0.50, 0.0, 0.0625, 0.0625,
5, 0.85, 0.0, 0.0625, 0.0625,
0
};
double const dline3[] = {
5, 0.25, 0.225, 0.0625, 0.0625,
5, 0.50, 0.475, 0.0625, 0.0625,
5, 0.75, 0.725, 0.0625, 0.0625,
0
};
double const ring[] = {
2, 13,
0.5000, 0.7750, 0.6375, 0.7375, 0.7375, 0.6375, 0.7750, 0.5000,
0.7375, 0.3625, 0.6375, 0.2625, 0.5000, 0.2250, 0.3625, 0.2625,
0.2625, 0.3625, 0.2250, 0.5000, 0.2625, 0.6375, 0.3625, 0.7375,
0.5000, 0.7750,
0
};
double const vert[] = {
1, 0.5, 0.05, 0.5, 0.95,
0
};
double const Vert[] = {
1, 0.3, 0.05, 0.3, 0.95,
1, 0.7, 0.05, 0.7, 0.95,
0
};
double const tilde[] = {
2, 10,
0.000, 0.625, 0.050, 0.500, 0.150, 0.350, 0.275, 0.275, 0.400, 0.350,
0.575, 0.650, 0.700, 0.725, 0.825, 0.650, 0.925, 0.500, 0.975, 0.375,
0
};
struct deco_struct {
double const * data;
int angle;
};
struct named_deco_struct {
char const * name;
double const * data;
int angle;
};
named_deco_struct deco_table[] = {
// Decorations
{"widehat", angle, 3 },
{"widetilde", tilde, 0 },
{"underbar", hline, 0 },
{"underline", hline, 0 },
{"overline", hline, 0 },
{"underbrace", brace, 1 },
{"overbrace", brace, 3 },
{"overleftarrow", arrow, 1 },
{"overrightarrow", arrow, 3 },
{"overleftrightarrow", udarrow, 1 },
{"xhookleftarrow", lhook, 0 },
{"xhookrightarrow", rhook, 0 },
{"xleftarrow", arrow, 1 },
{"xLeftarrow", LArrow, 0 },
{"xleftharpoondown", lharpoondown, 0 },
{"xleftharpoonup", lharpoonup, 0 },
{"xleftrightharpoons", lrharpoons, 0 },
{"xleftrightarrow", udarrow, 1 },
{"xLeftrightarrow", LRArrow, 0 },
{"xmapsto", mapsto, 0 },
{"xrightarrow", arrow, 3 },
{"xRightarrow", LArrow, 2 },
{"xrightharpoondown", lharpoonup, 2 },
{"xrightharpoonup", lharpoondown, 2 },
{"xrightleftharpoons", rlharpoons, 0 },
{"underleftarrow", arrow, 1 },
{"underrightarrow", arrow, 3 },
{"underleftrightarrow", udarrow, 1 },
{"undertilde", tilde, 0 },
{"utilde", tilde, 0 },
// Delimiters
{"(", parenth, 0 },
{")", parenth, 2 },
{"{", brace, 0 },
{"}", brace, 2 },
{"lbrace", brace, 0 },
{"rbrace", brace, 2 },
{"[", brack, 0 },
{"]", brack, 2 },
{"llbracket", dbrack, 0 },
{"rrbracket", dbrack, 2 },
{"|", vert, 0 },
{"/", slash, 0 },
{"slash", slash, 0 },
{"vert", vert, 0 },
{"lvert", vert, 0 },
{"rvert", vert, 0 },
{"Vert", Vert, 0 },
{"lVert", Vert, 0 },
{"rVert", Vert, 0 },
{"'", slash, 1 },
{"<", angle, 0 },
{">", angle, 2 },
{"\\", slash, 1 },
{"backslash", slash, 1 },
{"langle", angle, 0 },
{"lceil", corner, 0 },
{"lfloor", corner, 1 },
{"rangle", angle, 2 },
{"rceil", corner, 3 },
{"rfloor", corner, 2 },
{"downarrow", arrow, 2 },
{"Downarrow", Arrow, 2 },
{"uparrow", arrow, 0 },
{"Uparrow", Arrow, 0 },
{"updownarrow", udarrow, 0 },
{"Updownarrow", Udarrow, 0 },
// Accents
{"ddot", ddot, 0 },
{"dddot", dddot, 0 },
{"ddddot", ddddot, 0 },
{"hat", angle, 3 },
{"grave", slash, 1 },
{"acute", slash, 0 },
{"tilde", tilde, 0 },
{"bar", hline, 0 },
{"dot", dot, 0 },
{"check", angle, 1 },
{"breve", breve, 0 },
{"vec", vec, 3 },
{"mathring", ring, 0 },
// Dots
{"dots", hline3, 0 },
{"ldots", hline3, 0 },
{"cdots", hline3, 0 },
{"vdots", hline3, 1 },
{"ddots", dline3, 0 },
{"adots", dline3, 1 },
{"iddots", dline3, 1 },
{"dotsb", hline3, 0 },
{"dotsc", hline3, 0 },
{"dotsi", hline3, 0 },
{"dotsm", hline3, 0 },
{"dotso", hline3, 0 }
};
map<docstring, deco_struct> deco_list;
// sort the table on startup
class init_deco_table {
public:
init_deco_table() {
unsigned const n = sizeof(deco_table) / sizeof(deco_table[0]);
for (named_deco_struct * p = deco_table; p != deco_table + n; ++p) {
deco_struct d;
d.data = p->data;
d.angle = p->angle;
deco_list[from_ascii(p->name)] = d;
}
}
};
static init_deco_table dummy_deco_table;
deco_struct const * search_deco(docstring const & name)
{
map<docstring, deco_struct>::const_iterator p = deco_list.find(name);
return p == deco_list.end() ? 0 : &(p->second);
}
} // namespace
int mathed_font_em(FontInfo const & font)
{
return theFontMetrics(font).em();
}
int mathed_font_x_height(FontInfo const & font)
{
return theFontMetrics(font).xHeight();
}
/* The math units. Quoting TeX by Topic, p.205:
*
* Spacing around mathematical objects is measured in mu units. A mu
* is 1/18th part of \fontdimen6 of the font in family 2 in the
* current style, the quad value of the symbol font.
*
* A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is
* inserted around (binary) relations, except where these are preceded
* or followed by other relations or punctuation, and except if they
* follow an open, or precede a close symbol.
*
* A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu)
* is put around binary operators.
*
* A \thinmuskip (default value in plain TeX: 3mu) follows after
* punctuation, and is put around inner objects, except where these
* are followed by a close or preceded by an open symbol, and except
* if the other object is a large operator or a binary relation.
*
* See the file MathClass.cpp for a formal implementation of the rules
* above.
*/
int mathed_mu(FontInfo const & font, double mu)
{
MetricsBase mb(nullptr, font);
return mb.inPixels(Length(mu, Length::MU));
}
int mathed_thinmuskip(FontInfo const & font) { return mathed_mu(font, 3.0); }
int mathed_medmuskip(FontInfo const & font) { return mathed_mu(font, 4.0); }
int mathed_thickmuskip(FontInfo const & font) { return mathed_mu(font, 5.0); }
int mathed_char_width(FontInfo const & font, char_type c)
{
return theFontMetrics(font).width(c);
}
int mathed_char_kerning(FontInfo const & font, char_type c)
{
frontend::FontMetrics const & fm = theFontMetrics(font);
return max(0, fm.rbearing(c) - fm.width(c));
}
double mathed_char_slope(MetricsBase const & mb, char_type c)
{
bool slanted = isAlphaASCII(c) || Encodings::isMathAlpha(c);
if (slanted && mb.fontname == "mathnormal")
return theFontMetrics(mb.font).italicSlope();
return 0.0;
}
void mathed_string_dim(FontInfo const & font,
docstring const & s,
Dimension & dim)
{
frontend::FontMetrics const & fm = theFontMetrics(font);
dim.asc = 0;
dim.des = 0;
for (char_type const c : s) {
dim.asc = max(dim.asc, fm.ascent(c));
dim.des = max(dim.des, fm.descent(c));
}
dim.wid = fm.width(s);
}
int mathed_string_width(FontInfo const & font, docstring const & s)
{
return theFontMetrics(font).width(s);
}
void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
docstring const & name)
{
int const lw = pi.base.solidLineThickness();
if (name == ".") {
pi.pain.line(x + w/2, y, x + w/2, y + h,
Color_cursor, Painter::line_onoffdash, lw);
return;
}
deco_struct const * mds = search_deco(name);
if (!mds) {
lyxerr << "Deco was not found. Programming error?" << endl;
lyxerr << "name: '" << to_utf8(name) << "'" << endl;
return;
}
int const n = (w < h) ? w : h;
int const r = mds->angle;
double const * d = mds->data;
if (h > 70 && (name == "(" || name == ")"))
d = parenthHigh;
Matrix mt(r, w, h);
Matrix sqmt(r, n, n);
if (r > 0 && r < 3)
y += h;
if (r >= 2)
x += w;
for (int i = 0; d[i]; ) {
int code = int(d[i++]);
if (code == 1 || code == 3) {
double xx = d[i++];
double yy = d[i++];
double x2 = d[i++];
double y2 = d[i++];
if (code == 3)
sqmt.transform(xx, yy);
else
mt.transform(xx, yy);
mt.transform(x2, y2);
pi.pain.line(
int(x + xx + 0.5), int(y + yy + 0.5),
int(x + x2 + 0.5), int(y + y2 + 0.5),
pi.base.font.color(), Painter::line_solid, lw);
} else if (code == 5) {
double xx = d[i++];
double yy = d[i++];
double x2 = xx + d[i++];
double y2 = yy + d[i++];
mt.transform(xx, yy);
mt.transform(x2, y2);
double const xc = x + xx;
double const yc = y + yy;
double const rx = x2 - xx;
double const ry = y2 - yy;
pi.pain.ellipse(xc, yc, rx, ry,
pi.base.font.color(), Painter::fill_winding);
} else {
int xp[32];
int yp[32];
double xshift = (code == 6 ? d[i++] : 0.0);
double yshift = (code == 6 ? d[i++] : 0.0);
int const n2 = int(d[i++]);
for (int j = 0; j < n2; ++j) {
double xx = d[i++] + xshift;
double yy = d[i++] + yshift;
// lyxerr << ' ' << xx << ' ' << yy << ' ';
if (code == 4 || code == 6) {
sqmt.transform(xx, yy);
if (code == 6) {
if (r == 0 && xshift == 0.0)
yy += h;
else
xx += w;
}
} else
mt.transform(xx, yy);
xp[j] = int(x + xx + 0.5);
yp[j] = int(y + yy + 0.5);
// lyxerr << "P[" << j ' ' << xx << ' ' << yy << ' ' << x << ' ' << y << ']';
}
pi.pain.lines(xp, yp, n2, pi.base.font.color(),
Painter::fill_none, Painter::line_solid, lw);
}
}
}
docstring const & mathedSymbol(MetricsBase & mb, latexkeys const * sym)
{
return (mb.font.style() == DISPLAY_STYLE && !sym->dsp_draw.empty()) ?
sym->dsp_draw : sym->draw;
}
int mathedSymbolDim(MetricsBase & mb, Dimension & dim, latexkeys const * sym)
{
LASSERT((bool)sym, return 0);
//lyxerr << "metrics: symbol: '" << sym->name
// << "' in font: '" << sym->inset
// << "' drawn as: '" << sym->draw
// << "'" << endl;
bool const italic_upcase_greek = sym->inset == "cmr" &&
sym->extra == "mathalpha" &&
mb.fontname == "mathit";
std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
bool const change_font = font != "cmr" ||
(mb.fontname != "mathbb" &&
mb.fontname != "mathds" &&
mb.fontname != "mathfrak" &&
mb.fontname != "mathcal" &&
mb.fontname != "mathscr");
Changer dummy = change_font ? mb.changeFontSet(font) : noChange();
mathed_string_dim(mb.font, mathedSymbol(mb, sym), dim);
return mathed_char_kerning(mb.font, mathedSymbol(mb, sym).back());
}
void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym)
{
LASSERT((bool)sym, return);
//lyxerr << "drawing: symbol: '" << sym->name
// << "' in font: '" << sym->inset
// << "' drawn as: '" << sym->draw
// << "'" << endl;
bool const upcase_greek =
sym->inset == "cmr" && sym->extra == "mathalpha";
bool const bold_upcase_greek =
upcase_greek && pi.base.fontname == "mathbf";
bool const italic_upcase_greek =
upcase_greek && pi.base.fontname == "mathit";
std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
bool const change_font = font != "cmr" ||
(pi.base.fontname != "mathbb" &&
pi.base.fontname != "mathds" &&
pi.base.fontname != "mathfrak" &&
pi.base.fontname != "mathcal" &&
pi.base.fontname != "mathscr");
Changer dummy = change_font ? pi.base.changeFontSet(font) : noChange();
pi.draw(x, y, mathedSymbol(pi.base, sym));
if (bold_upcase_greek)
pi.draw(x + 1, y, mathedSymbol(pi.base, sym));
}
void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
{
FontInfo font = mi.base.font;
augmentFont(font, "mathnormal");
mathed_string_dim(font, str, dim);
}
void drawStrRed(PainterInfo & pi, int x, int y, docstring const & str)
{
FontInfo f = pi.base.font;
augmentFont(f, "mathnormal");
f.setColor(Color_latex);
pi.pain.text(x, y, str, f);
}
void drawStrBlack(PainterInfo & pi, int x, int y, docstring const & str)
{
FontInfo f = pi.base.font;
augmentFont(f, "mathnormal");
f.setColor(Color_foreground);
pi.pain.text(x, y, str, f);
}
void math_font_max_dim(FontInfo const & font, int & asc, int & des)
{
frontend::FontMetrics const & fm = theFontMetrics(font);
asc = fm.maxAscent();
des = fm.maxDescent();
}
struct fontinfo {
string cmd_;
FontFamily family_;
FontSeries series_;
FontShape shape_;
ColorCode color_;
};
FontFamily const inh_family = INHERIT_FAMILY;
FontSeries const inh_series = INHERIT_SERIES;
FontShape const inh_shape = INHERIT_SHAPE;
// mathnormal should be the first, otherwise the fallback further down
// does not work
fontinfo fontinfos[] = {
// math fonts
// Color_math determines which fonts are math (see isMathFont)
{"mathnormal", ROMAN_FAMILY, MEDIUM_SERIES,
ITALIC_SHAPE, Color_math},
{"mathbf", inh_family, BOLD_SERIES,
inh_shape, Color_math},
{"mathcal", CMSY_FAMILY, inh_series,
inh_shape, Color_math},
{"mathfrak", EUFRAK_FAMILY, inh_series,
inh_shape, Color_math},
{"mathrm", ROMAN_FAMILY, inh_series,
UP_SHAPE, Color_math},
{"mathsf", SANS_FAMILY, inh_series,
inh_shape, Color_math},
{"mathbb", MSB_FAMILY, inh_series,
inh_shape, Color_math},
{"mathds", DS_FAMILY, inh_series,
inh_shape, Color_math},
{"mathtt", TYPEWRITER_FAMILY, inh_series,
inh_shape, Color_math},
{"mathit", inh_family, inh_series,
ITALIC_SHAPE, Color_math},
{"mathscr", RSFS_FAMILY, inh_series,
inh_shape, Color_math},
{"cmex", CMEX_FAMILY, inh_series,
inh_shape, Color_math},
{"cmm", CMM_FAMILY, inh_series,
inh_shape, Color_math},
{"cmr", CMR_FAMILY, inh_series,
inh_shape, Color_math},
{"cmsy", CMSY_FAMILY, inh_series,
inh_shape, Color_math},
{"eufrak", EUFRAK_FAMILY, inh_series,
inh_shape, Color_math},
{"msa", MSA_FAMILY, inh_series,
inh_shape, Color_math},
{"msb", MSB_FAMILY, inh_series,
inh_shape, Color_math},
{"stmry", STMARY_FAMILY, inh_series,
inh_shape, Color_math},
{"wasy", WASY_FAMILY, inh_series,
inh_shape, Color_math},
{"esint", ESINT_FAMILY, inh_series,
inh_shape, Color_math},
// Text fonts
{"text", inh_family, inh_series,
inh_shape, Color_foreground},
{"textbf", inh_family, BOLD_SERIES,
inh_shape, Color_foreground},
{"textit", inh_family, inh_series,
ITALIC_SHAPE, Color_foreground},
{"textmd", inh_family, MEDIUM_SERIES,
inh_shape, Color_foreground},
{"textnormal", inh_family, inh_series,
UP_SHAPE, Color_foreground},
{"textrm", ROMAN_FAMILY,
inh_series, UP_SHAPE,Color_foreground},
{"textsc", inh_family, inh_series,
SMALLCAPS_SHAPE, Color_foreground},
{"textsf", SANS_FAMILY, inh_series,
inh_shape, Color_foreground},
{"textsl", inh_family, inh_series,
SLANTED_SHAPE, Color_foreground},
{"texttt", TYPEWRITER_FAMILY, inh_series,
inh_shape, Color_foreground},
{"textup", inh_family, inh_series,
UP_SHAPE, Color_foreground},
// TIPA support
{"textipa", inh_family, inh_series,
inh_shape, Color_foreground},
// mhchem support
{"ce", inh_family, inh_series,
inh_shape, Color_foreground},
{"cf", inh_family, inh_series,
inh_shape, Color_foreground},
// LyX internal usage
{"lyxtex", inh_family, inh_series,
UP_SHAPE, Color_latex},
// FIXME: The following two don't work on OS X, since the Symbol font
// uses a different encoding, and is therefore disabled in
// FontLoader::available().
{"lyxsymbol", SYMBOL_FAMILY, inh_series,
inh_shape, Color_math},
{"lyxboldsymbol", SYMBOL_FAMILY, BOLD_SERIES,
inh_shape, Color_math},
{"lyxblacktext", ROMAN_FAMILY, MEDIUM_SERIES,
UP_SHAPE, Color_foreground},
{"lyxnochange", inh_family, inh_series,
inh_shape, Color_foreground},
{"lyxfakebb", TYPEWRITER_FAMILY, BOLD_SERIES,
UP_SHAPE, Color_math},
{"lyxfakecal", SANS_FAMILY, MEDIUM_SERIES,
ITALIC_SHAPE, Color_math},
{"lyxfakefrak", ROMAN_FAMILY, BOLD_SERIES,
ITALIC_SHAPE, Color_math}
};
fontinfo * lookupFont(string const & name)
{
//lyxerr << "searching font '" << name << "'" << endl;
int const n = sizeof(fontinfos) / sizeof(fontinfo);
for (int i = 0; i < n; ++i)
if (fontinfos[i].cmd_ == name) {
//lyxerr << "found '" << i << "'" << endl;
return fontinfos + i;
}
return 0;
}
fontinfo * searchFont(string const & name)
{
fontinfo * f = lookupFont(name);
return f ? f : fontinfos;
// this should be mathnormal
//return searchFont("mathnormal");
}
bool isFontName(string const & name)
{
return lookupFont(name);
}
bool isMathFont(string const & name)
{
fontinfo * f = lookupFont(name);
return f && f->color_ == Color_math;
}
bool isTextFont(string const & name)
{
fontinfo * f = lookupFont(name);
return f && f->color_ == Color_foreground;
}
FontInfo getFont(string const & name)
{
FontInfo font;
augmentFont(font, name);
return font;
}
void fakeFont(string const & orig, string const & fake)
{
fontinfo * forig = searchFont(orig);
fontinfo * ffake = searchFont(fake);
if (forig && ffake) {
forig->family_ = ffake->family_;
forig->series_ = ffake->series_;
forig->shape_ = ffake->shape_;
forig->color_ = ffake->color_;
} else {
lyxerr << "Can't fake font '" << orig << "' with '"
<< fake << "'" << endl;
}
}
void augmentFont(FontInfo & font, string const & name)
{
static bool initialized = false;
if (!initialized) {
initialized = true;
// fake fonts if necessary
if (!theFontLoader().available(getFont("mathfrak")))
fakeFont("mathfrak", "lyxfakefrak");
if (!theFontLoader().available(getFont("mathcal")))
fakeFont("mathcal", "lyxfakecal");
}
fontinfo * info = searchFont(name);
if (info->family_ != inh_family)
font.setFamily(info->family_);
if (info->series_ != inh_series)
font.setSeries(info->series_);
if (info->shape_ != inh_shape)
font.setShape(info->shape_);
if (info->color_ != Color_none)
font.setColor(info->color_);
}
bool isAlphaSymbol(MathAtom const & at)
{
if (at->asCharInset() ||
(at->asSymbolInset() &&
at->asSymbolInset()->isOrdAlpha()))
return true;
if (at->asFontInset()) {
MathData const & ar = at->asFontInset()->cell(0);
for (size_t i = 0; i < ar.size(); ++i) {
if (!(ar[i]->asCharInset() ||
(ar[i]->asSymbolInset() &&
ar[i]->asSymbolInset()->isOrdAlpha())))
return false;
}
return true;
}
return false;
}
docstring asString(MathData const & ar)
{
odocstringstream os;
otexrowstream ots(os);
TeXMathStream ws(ots);
ws << ar;
return os.str();
}
void asArray(docstring const & str, MathData & ar, Parse::flags pf)
{
// If the QUIET flag is set, we are going to parse for either
// a paste operation or a macro definition. We try to do the
// right thing in all cases.
bool quiet = pf & Parse::QUIET;
bool macro = pf & Parse::MACRODEF;
if ((str.size() == 1 && quiet) || (!mathed_parse_cell(ar, str, pf) && quiet && !macro))
mathed_parse_cell(ar, str, pf | Parse::VERBATIM);
}
docstring asString(InsetMath const & inset)
{
odocstringstream os;
otexrowstream ots(os);
TeXMathStream ws(ots);
inset.write(ws);
return os.str();
}
docstring asString(MathAtom const & at)
{
odocstringstream os;
otexrowstream ots(os);
TeXMathStream ws(ots);
at->write(ws);
return os.str();
}
int axis_height(MetricsBase & mb)
{
Changer dummy = mb.changeFontSet("mathnormal");
return theFontMetrics(mb.font).ascent('-') - 1;
}
void validate_math_word(LaTeXFeatures & features, docstring const & word)
{
MathWordList const & words = mathedWordList();
MathWordList::const_iterator it = words.find(word);
if (it != words.end()) {
string const req = it->second.required;
if (!req.empty())
features.require(req);
}
}
} // namespace lyx