X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathChar.cpp;h=a1c49d16be530ee1f3277a7bcf6a99431a60da99;hb=1538a8352ca82914bc131f2bf98b0ef4f55c1e2d;hp=03bda07cf60475c4ebaae4584ea401c613fccc12;hpb=8164fea772121e41145fabed8172ea6b8ec0f007;p=lyx.git diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index 03bda07cf6..a1c49d16be 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" @@ -28,17 +29,65 @@ #include "support/lstrings.h" #include "support/textutils.h" +#include + +using namespace std; + namespace lyx { extern bool has_math_fonts; -static bool isBinaryOp(char_type c) +namespace { +latexkeys const * makeSubstitute(char_type c) { - return support::contains("+-<>=/*", static_cast(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) { @@ -47,7 +96,7 @@ static bool slanted(char_type c) InsetMathChar::InsetMathChar(char_type c) - : char_(c), kerning_(0) + : char_(c), kerning_(0), subst_(makeSubstitute(c)) {} @@ -60,60 +109,62 @@ Inset * InsetMathChar::clone() const void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const { -#if 1 - if (char_ == '=' && has_math_fonts) { - FontSetChanger dummy(mi.base, "cmr"); - dim = theFontMetrics(mi.base.font).dimension(char_); - } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { - FontSetChanger dummy(mi.base, "cmm"); - dim = theFontMetrics(mi.base.font).dimension(char_); - } else if (!slanted(char_) && mi.base.fontname == "mathnormal") { - ShapeChanger dummy(mi.base.font, UP_SHAPE); + string const & f = mi.base.fontname; + if (isMathFont(f) && subst_) { + // If the char has a substitute, draw the replacement symbol + // instead, but only in math mode. + mathedSymbolDim(mi.base, dim, subst_); + kerning_ = mathed_char_kerning(mi.base.font, *subst_->draw.rbegin()); + return; + } else if (!slanted(char_) && f == "mathnormal") { + Changer dummy = mi.base.font.changeShape(UP_SHAPE); dim = theFontMetrics(mi.base.font).dimension(char_); + kerning_ = 0; } else { frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); dim = fm.dimension(char_); - kerning_ = fm.rbearing(char_) - dim.wid; + kerning_ = mathed_char_kerning(mi.base.font, char_); + // cmmi has almost no left bearing: simulate this + if (f == "mathnormal") { + dim.wid += max(-fm.lbearing(char_), 0); + } + // Rule 17 from Appendix G + // These are the fonts with fontdimen(2)==0. + // To properly handle the case fontdimen(2)!=0 (that is for all other + // math fonts), where the italic correction must also be converted into + // kerning but only at the end of strings of characters with the same + // font, one would need a more elaborate implementation in MathRow. For + // now the case fontdimen(2)==0 is the most important. + if (f == "mathnormal" || f == "mathscr" || f == "mathcal") { + dim.wid += kerning_; + // We use a negative value to tell InsetMathScript to move the + // subscript leftwards instead of the superscript rightwards + kerning_ = -kerning_; + } } - int const em = mathed_char_width(mi.base.font, 'M'); - if (isBinaryOp(char_)) - dim.wid += static_cast(0.5*em+0.5); - else if (char_ == '\'') - dim.wid += static_cast(0.1667*em+0.5); -#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 << endl; - int const em = mathed_char_width(pi.base.font, 'M'); - if (isBinaryOp(char_)) - x += static_cast(0.25*em+0.5); - else if (char_ == '\'') - x += static_cast(0.0833*em+0.5); -#if 1 - if (char_ == '=' && has_math_fonts) { - FontSetChanger dummy(pi.base, "cmr"); - pi.draw(x, y, char_); - } else if ((char_ == '>' || char_ == '<') && has_math_fonts) { - FontSetChanger dummy(pi.base, "cmm"); - pi.draw(x, y, char_); - } else if (!slanted(char_) && pi.base.fontname == "mathnormal") { - ShapeChanger dummy(pi.base.font, UP_SHAPE); - pi.draw(x, y, char_); - } else { - pi.draw(x, y, char_); + //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << std::endl; + 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; + } + } + // cmmi has almost no left bearing: simulate this + if (pi.base.fontname == "mathnormal") { + x += max(-theFontMetrics(pi.base.font).lbearing(char_), 0); } -#else - drawChar(pain, font_, x, y, char_); -#endif + pi.draw(x, y, char_); } @@ -203,6 +254,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; @@ -236,9 +289,19 @@ void InsetMathChar::htmlize(HtmlStream & ms) const } -bool InsetMathChar::isRelOp() const +MathClass InsetMathChar::mathClass() const { - return char_ == '=' || char_ == '<' || char_ == '>'; + // this information comes from fontmath.ltx in LaTeX source. + char const ch = static_cast(char_); + if (subst_) + return string_to_class(subst_->extra); + else if (support::contains(",;", ch)) + return MC_PUNCT; + else if (support::contains("([", ch)) + return MC_OPEN; + else if (support::contains(")]!?", ch)) + return MC_CLOSE; + else return MC_ORD; }