heartsuit cmsy 126 169 mathord ♡
spadesuit cmsy 127 170 mathord ♠
# We define lyxnot as mathrel in order to have proper alignment
-lyxnot cmsy 54 47 mathrel /
+lyxnot cmsy 54 47 mathrel / hiddensymbol
iffont cmsy
# 10mu is the extra space added to relation operators
\def\not{\lyxnot\kern-20mu}
hbar msb 126 0 mathord ℏ
backepsilon msb 127 0 mathrel ϶
-lyxbar cmsy 161 0 mathord —
-lyxeq cmr 61 0 mathord =
-lyxdabar msa 57 0 mathord –
-lyxright msa 75 0 mathord →
-lyxleft msa 76 0 mathord ←
+lyxbar cmsy 161 0 mathord — hiddensymbol
+lyxminus cmsy 161 0 mathbin — hiddensymbol
+lyxplus cmr 43 43 mathbin + hiddensymbol
+lyxeq cmr 61 61 mathord = hiddensymbol
+lyxeqrel cmr 61 61 mathrel = hiddensymbol
+lyxlt cmm 60 60 mathrel < hiddensymbol
+lyxgt cmm 62 62 mathrel > hiddensymbol
+lyxdabar msa 57 0 mathord – hiddensymbol
+lyxright msa 75 0 mathord → hiddensymbol
+lyxleft msa 76 0 mathord ← hiddensymbol
male wasy 26 0 x ♂
female wasy 25 0 x ♀
#include "InsetMathChar.h"
+#include "MathParser.h"
#include "MathSupport.h"
#include "MathStream.h"
#include "MetricsInfo.h"
extern bool has_math_fonts;
+namespace {
+
+latexkeys const * makeSubstitute(char_type c)
+{
+ std::string name;
+ switch (c) {
+ // Latex replaces ', *, -, and : with specific symbols. With unicode-math,
+ // these symbols are replaced respectively by ^U+2032, U+2217, U+2212 and
+ // U+2236 (the latter substitution can be turned off with a package
+ // option). Unicode-math also replaces ` with \backprime.
+ // prime needs to be placed in superscript unless an opentype font is used.
+ //case '\'':
+ //name = "prime";
+ //break;
+ case '*':
+ name = "ast";
+ break;
+ case '-':
+ name = "lyxminus";// unicode-math: "minus"
+ break;
+ case ':':
+ name = "ordinarycolon";// unicode-math: "mathratio"
+ break;
+ // The remaining replacements are not real character substitutions (from a
+ // unicode point of view) but are done here: 1. for cosmetic reasons, in the
+ // context of being stuck with CM fonts at the moment, to ensure consistency
+ // with related symbols: -, \leq, \geq, etc. 2. to get the proper spacing
+ // as defined in lib/symbols.
+ case '+':
+ name = "lyxplus";//unicode-math: "mathplus"
+ break;
+ case '>':
+ name = "lyxgt";//unicode-math: "greater"
+ break;
+ case '<':
+ name = "lyxlt";//unicode-math: "less"
+ break;
+ case '=':
+ name = "lyxeqrel";//unicode-math: "equal"
+ break;
+ //case ','://unicode-math: "mathcomma"
+ //case ';'://unicode-math: "mathsemicolon"
+ default:
+ return nullptr;
+ }
+ return in_word_set(from_ascii(name));
+}
+
+} //anonymous namespace
+
+
static bool slanted(char_type c)
{
return isAlphaASCII(c) || Encodings::isMathAlpha(c);
InsetMathChar::InsetMathChar(char_type c)
- : char_(c), kerning_(0)
+ : char_(c), kerning_(0), subst_(makeSubstitute(c))
{}
void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
{
-#if 1
- if (char_ == '=' && has_math_fonts) {
- Changer dummy = mi.base.changeFontSet("cmr");
- dim = theFontMetrics(mi.base.font).dimension(char_);
- } else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
- Changer dummy = mi.base.changeFontSet("cmm");
- dim = theFontMetrics(mi.base.font).dimension(char_);
+ bool const mathfont = isMathFont(mi.base.fontname);
+ if (mathfont && subst_) {
+ // If the char has a substitute, draw the replacement symbol
+ // instead, but only in math mode.
+ mathedSymbolDim(mi, dim, subst_);
+ kerning_ = mathed_char_kerning(mi.base.font, *subst_->draw.rbegin());
+ return;
} else if (!slanted(char_) && mi.base.fontname == "mathnormal") {
Changer dummy = mi.base.font.changeShape(UP_SHAPE);
dim = theFontMetrics(mi.base.font).dimension(char_);
dim = fm.dimension(char_);
kerning_ = fm.rbearing(char_) - dim.wid;
}
- if (isMathBin())
- dim.wid += 2 * mathed_medmuskip(mi.base.font);
- else if (isMathRel())
- dim.wid += 2 * mathed_thickmuskip(mi.base.font);
- else if (isMathPunct())
+ if (mathfont && isMathPunct())
dim.wid += mathed_thinmuskip(mi.base.font);
- else if (char_ == '\'')
- // FIXME: don't know where this is coming from
- dim.wid += mathed_thinmuskip(mi.base.font);
-#else
- whichFont(font_, code_, mi);
- dim = theFontMetrics(font_).dimension(char_);
- if (isBinaryOp(char_, code_))
- dim.wid += 2 * theFontMetrics(font_).width(' ');
- lyxerr << "InsetMathChar::metrics: " << dim << endl;
-#endif
}
void InsetMathChar::draw(PainterInfo & pi, int x, int y) const
{
//lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << std::endl;
- if (isMathBin())
- x += mathed_medmuskip(pi.base.font);
- else if (isMathRel())
- x += mathed_thickmuskip(pi.base.font);
- else if (char_ == '\'')
- x += mathed_thinmuskip(pi.base.font) / 2;
-#if 1
- if (char_ == '=' && has_math_fonts) {
- Changer dummy = pi.base.changeFontSet("cmr");
- pi.draw(x, y, char_);
- } else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
- Changer dummy = pi.base.changeFontSet("cmm");
- pi.draw(x, y, char_);
- } else if (!slanted(char_) && pi.base.fontname == "mathnormal") {
- Changer dummy = pi.base.font.changeShape(UP_SHAPE);
- pi.draw(x, y, char_);
- } else {
- pi.draw(x, y, char_);
+ if (isMathFont(pi.base.fontname)) {
+ if (subst_) {
+ // If the char has a substitute, draw the replacement symbol
+ // instead, but only in math mode.
+ mathedSymbolDraw(pi, x, y, subst_);
+ return;
+ } else if (!slanted(char_) && pi.base.fontname == "mathnormal") {
+ Changer dummy = pi.base.font.changeShape(UP_SHAPE);
+ pi.draw(x, y, char_);
+ return;
+ }
}
-#else
- drawChar(pain, font_, x, y, char_);
-#endif
+ pi.draw(x, y, char_);
}
void InsetMathChar::htmlize(HtmlStream & ms) const
{
std::string entity;
+ // Not taking subst_ into account here because the MathML output of
+ // <>=+-* looks correct as it is. FIXME: ' is not output as ^\prime
switch (char_) {
case '<': entity = "<"; break;
case '>': entity = ">"; break;
bool InsetMathChar::isMathBin() const
{
- return support::contains("+-*", static_cast<char>(char_));
+ return subst_ && subst_->extra == "mathbin";
}
bool InsetMathChar::isMathRel() const
{
- return support::contains("<>=:", static_cast<char>(char_));
+ return subst_ && subst_->extra == "mathrel";
}
bool InsetMathChar::isMathPunct() const
{
- return support::contains(",;", static_cast<char>(char_));
+ return support::contains(",;", static_cast<char>(char_))
+ || (subst_ && subst_->extra == "mathpunct");
}
namespace lyx {
+class latexkeys;
+
/// The base character inset.
class InsetMathChar : public InsetMath {
public:
private:
virtual Inset * clone() const;
/// the character
- char_type char_;
+ char_type const char_;
/// cached kerning for superscript
mutable int kerning_;
+ /// Inset to substitute char for, for on-screen display in math mode, as
+ /// performed by LaTeX (#9893):
+ /// * -> \ast (U+2217)
+ /// - -> \lyxminus (U+2212)
+ /// : -> \ordinarycolon (U+2236)
+ ///
+ /// For cosmetic reasons, +, >, <, and = are also substituted to force the
+ /// use of CM fonts for uniformity. If CM fonts are replaced with unicode
+ /// math fonts, this should be removed, and substitutions of "'", ",", and
+ /// ";" added.
+ ///
+ /// Null if there is no substitute.
+ latexkeys const * const subst_;
};
} // namespace lyx
void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
{
- //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" &&
- mi.base.fontname == "mathit";
- std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
- Changer dummy = mi.base.changeFontSet(font);
- mathed_string_dim(mi.base.font, sym_->draw, dim);
- docstring::const_reverse_iterator rit = sym_->draw.rbegin();
- kerning_ = mathed_char_kerning(mi.base.font, *rit);
+ // set dim
+ mathedSymbolDim(mi, dim, sym_);
+ // set kerning_
+ kerning_ = mathed_char_kerning(mi.base.font, *sym_->draw.rbegin());
// correct height for broken cmex and wasy font
if (sym_->inset == "cmex" || sym_->inset == "wasy") {
h_ = 4 * dim.des / 5;
dim.asc += h_;
dim.des -= h_;
}
- // seperate things a bit
- if (isMathBin())
- dim.wid += 2 * mathed_medmuskip(mi.base.font);
- else if (isMathRel())
- dim.wid += 2 * mathed_thickmuskip(mi.base.font);
- else if (isMathPunct())
- dim.wid += mathed_thinmuskip(mi.base.font);
- // FIXME: I see no reason for this
- //else
- // dim.wid += support::iround(0.1667 * em);
-
+ // set striptable_
scriptable_ = false;
if (mi.base.style == LM_ST_DISPLAY)
if (sym_->inset == "cmex" || sym_->inset == "esint" ||
void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const
{
- //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" &&
- pi.base.fontname == "mathit";
- std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
- if (isMathBin())
- x += mathed_medmuskip(pi.base.font);
- else if (isMathRel())
- x += mathed_thickmuskip(pi.base.font);
- // FIXME: I see no reason for this
- //else
- // x += support::iround(0.0833 * em);
-
- Changer dummy = pi.base.changeFontSet(font);
- pi.draw(x, y - h_, sym_->draw);
+ mathedSymbolDraw(pi, x, y - h_, sym_);
}
#include "support/debug.h"
#include "support/docstream.h"
+#include "support/lassert.h"
#include "support/lyxlib.h"
#include <map>
}
+void mathedSymbolDim(MetricsInfo & mi, Dimension & dim, latexkeys const * sym)
+{
+ LASSERT((bool)sym, return);
+ //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" &&
+ mi.base.fontname == "mathit";
+ std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
+ Changer dummy = mi.base.changeFontSet(font);
+ mathed_string_dim(mi.base.font, sym->draw, dim);
+ // seperate things a bit
+ if (sym->extra == "mathbin")
+ dim.wid += 2 * mathed_medmuskip(mi.base.font);
+ else if (sym->extra == "mathrel")
+ dim.wid += 2 * mathed_thickmuskip(mi.base.font);
+ else if (sym->extra == "mathpunct")
+ dim.wid += mathed_thinmuskip(mi.base.font);
+}
+
+
+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 italic_upcase_greek = sym->inset == "cmr" &&
+ sym->extra == "mathalpha" &&
+ pi.base.fontname == "mathit";
+ std::string const font = italic_upcase_greek ? "cmm" : sym->inset;
+ if (sym->extra == "mathbin")
+ x += mathed_medmuskip(pi.base.font);
+ else if (sym->extra == "mathrel")
+ x += mathed_thickmuskip(pi.base.font);
+
+ Changer dummy = pi.base.changeFontSet(font);
+ pi.draw(x, y, sym->draw);
+}
+
+
void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & str)
{
FontInfo font = mi.base.font;
// 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,
class MathData;
class MathAtom;
class InsetMath;
+class latexkeys;
int mathed_font_em(FontInfo const &);
int mathed_string_width(FontInfo const &, docstring const & s);
+void mathedSymbolDim(MetricsInfo & mi, Dimension & dim, latexkeys const * sym);
+
+void mathedSymbolDraw(PainterInfo & pi, int x, int y, latexkeys const * sym);
+
void metricsStrRedBlack(MetricsInfo & mi, Dimension & dim, docstring const & s);
void drawStrRed(PainterInfo & pi, int x, int y, docstring const & s);