]> git.lyx.org Git - lyx.git/commitdiff
Display properly math characters that behave like symbols
authorGuillaume Munch <gm@lyx.org>
Wed, 25 May 2016 12:16:51 +0000 (13:16 +0100)
committerGuillaume Munch <gm@lyx.org>
Sun, 13 Nov 2016 19:06:35 +0000 (20:06 +0100)
* 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
src/mathed/InsetMathChar.cpp
src/mathed/InsetMathChar.h
src/mathed/InsetMathSymbol.cpp
src/mathed/MathSupport.cpp
src/mathed/MathSupport.h

index 1905888887be3e2c848d4619a6a1f55f712bdbdd..481aa8186c77a3d956ee15c806c48674af4e37d9 100644 (file)
@@ -298,7 +298,7 @@ diamondsuit        cmsy        125 168 mathord  &#x2662;
 heartsuit          cmsy        126 169 mathord  &#x2661;
 spadesuit          cmsy        127 170 mathord  &spades;
 # 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  &plankv;
 hbar               msb         126   0 mathord  &planck;
 backepsilon        msb         127   0 mathrel  &bepsi;
 
-lyxbar             cmsy        161   0 mathord  &mdash;
-lyxeq              cmr          61   0 mathord  =
-lyxdabar           msa          57   0 mathord  &ndash;
-lyxright           msa          75   0 mathord  &rarr;
-lyxleft            msa          76   0 mathord  &larr;
+lyxbar             cmsy        161   0 mathord   &mdash;  hiddensymbol
+lyxminus           cmsy        161   0 mathbin   &mdash;  hiddensymbol
+lyxplus            cmr          43  43 mathbin   +        hiddensymbol
+lyxeq              cmr          61  61 mathord   =        hiddensymbol
+lyxeqrel           cmr          61  61 mathrel   =        hiddensymbol
+lyxlt              cmm          60  60 mathrel   &lt;     hiddensymbol
+lyxgt              cmm          62  62 mathrel   &gt;     hiddensymbol
+lyxdabar           msa          57   0 mathord   &ndash;  hiddensymbol
+lyxright           msa          75   0 mathord   &rarr;   hiddensymbol
+lyxleft            msa          76   0 mathord   &larr;   hiddensymbol
 
 male               wasy          26  0 x        &male;
 female             wasy          25  0 x        &female;
index 813067e08a55bff863821a60885ed335032bd291..ae843bf00dd6c9e5f66215b44e0d67a2096b533c 100644 (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_);
-       } 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 = "&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");
 }
 
 
index 67bbc64e8c866fc345bd9042bc12fa1ebf897971..ea190211b777f7efd7feceba0e36538f7cc2c934 100644 (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
index 68c824742919f1c866368894bb8f0ee423344740..620ca226a2881b6c182c4885cb86a39c49716c59 100644 (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_);
 }
 
 
index 5c3e84f249f816d7d0bcb876aa9fbf7cb5272d23..0c610b1e69412c202c66505d576d4401870452fc 100644 (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,
index 74b7465f10d5934da5a56b807a40a1853d872d41..003631b8ae3bf0f2385b64c1ad5e11e05f7f059b 100644 (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);