commit be836909c52f8586646fa6360df649288b5e2875
Author: Guillaume Munch <[email protected]>
Date: Wed May 25 13:16:51 2016 +0100
Display properly math characters that behave like symbols
* set up a replacement of *, -, and : by the adequate symbols (#9893)
* fix the wrong character selection and operator spacing in \text mode
* hide some internal symbols from the auto-completion.
---
lib/symbols | 17 ++++--
src/mathed/InsetMathChar.cpp | 126 +++++++++++++++++++++++++---------------
src/mathed/InsetMathChar.h | 17 +++++-
src/mathed/InsetMathSymbol.cpp | 49 ++--------------
src/mathed/MathSupport.cpp | 48 +++++++++++++++
src/mathed/MathSupport.h | 5 ++
6 files changed, 165 insertions(+), 97 deletions(-)
diff --git a/lib/symbols b/lib/symbols
index 1905888..481aa81 100644
--- a/lib/symbols
+++ b/lib/symbols
@@ -298,7 +298,7 @@ diamondsuit cmsy 125 168 mathord ♢
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}
@@ -669,11 +669,16 @@ hslash msb 125 0 mathord ℏ
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 ♀
diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp
index 813067e..ae843bf 100644
--- a/src/mathed/InsetMathChar.cpp
+++ b/src/mathed/InsetMathChar.cpp
@@ -13,6 +13,7 @@
#include "InsetMathChar.h"
+#include "MathParser.h"
#include "MathSupport.h"
#include "MathStream.h"
#include "MetricsInfo.h"
@@ -34,6 +35,57 @@ namespace lyx {
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);
@@ -41,7 +93,7 @@ static bool slanted(char_type c)
InsetMathChar::InsetMathChar(char_type c)
- : char_(c), kerning_(0)
+ : char_(c), kerning_(0), subst_(makeSubstitute(c))
{}
@@ -54,13 +106,13 @@ Inset * InsetMathChar::clone() const
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_);
@@ -69,50 +121,27 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension &
dim) const
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_);
}
@@ -202,6 +231,8 @@ void InsetMathChar::mathmlize(MathStream & ms) const
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;
@@ -237,19 +268,20 @@ void InsetMathChar::htmlize(HtmlStream & ms) const
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");
}
diff --git a/src/mathed/InsetMathChar.h b/src/mathed/InsetMathChar.h
index 67bbc64..ea19021 100644
--- a/src/mathed/InsetMathChar.h
+++ b/src/mathed/InsetMathChar.h
@@ -16,6 +16,8 @@
namespace lyx {
+class latexkeys;
+
/// The base character inset.
class InsetMathChar : public InsetMath {
public:
@@ -60,9 +62,22 @@ 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
diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp
index 68c8247..620ca22 100644
--- a/src/mathed/InsetMathSymbol.cpp
+++ b/src/mathed/InsetMathSymbol.cpp
@@ -60,36 +60,17 @@ docstring InsetMathSymbol::name() const
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" ||
@@ -101,25 +82,7 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension &
dim) const
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_);
}
diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp
index 5c3e84f..0c610b1 100644
--- a/src/mathed/MathSupport.cpp
+++ b/src/mathed/MathSupport.cpp
@@ -27,6 +27,7 @@
#include "support/debug.h"
#include "support/docstream.h"
+#include "support/lassert.h"
#include "support/lyxlib.h"
#include <map>
@@ -656,6 +657,52 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int
w, int h,
}
+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;
@@ -708,6 +755,7 @@ FontShape const inh_shape = INHERIT_SHAPE;
// 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,
diff --git a/src/mathed/MathSupport.h b/src/mathed/MathSupport.h
index 74b7465..003631b 100644
--- a/src/mathed/MathSupport.h
+++ b/src/mathed/MathSupport.h
@@ -25,6 +25,7 @@ class Dimension;
class MathData;
class MathAtom;
class InsetMath;
+class latexkeys;
int mathed_font_em(FontInfo const &);
@@ -48,6 +49,10 @@ void mathed_string_dim(FontInfo const & font,
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);