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.
This commit is contained in:
Guillaume Munch 2016-05-25 13:16:51 +01:00
parent ad7e2435cf
commit be836909c5
6 changed files with 165 additions and 97 deletions

View File

@ -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 ♀

View File

@ -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_);
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_);
} else {
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 = "&lt;"; break;
case '>': entity = "&gt;"; 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");
}

View File

@ -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

View File

@ -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_);
}

View File

@ -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,

View File

@ -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);