From 03a4b8c93281f9081dc56673f408d32ecddc2470 Mon Sep 17 00:00:00 2001 From: Guillaume Munch Date: Sun, 27 Nov 2016 22:45:51 +0100 Subject: [PATCH] Implement rule 17 * Convert the kerning into a proper right margin for mathnormal, mathscr and mathcal (fonts with \fontdimen2 == 0 as per rule 17 from TeXBook). * Simulate the fact that characters in mathnormal fonts have a 0-width left bearing. * Implement subscript positioning in the case of rule 17 using negative italic correction (kerning_). --- src/mathed/InsetMath.h | 2 +- src/mathed/InsetMathChar.cpp | 34 +++++++++++++++++++++++++---- src/mathed/InsetMathScript.cpp | 16 +++++++------- src/mathed/InsetMathScript.h | 5 ++++- src/mathed/InsetMathSideset.h | 2 +- src/mathed/InsetMathSpecialChar.cpp | 2 +- src/mathed/MathData.h | 2 +- src/mathed/MathSupport.cpp | 2 +- 8 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index 68cd59793e..9c65fafe4d 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -230,7 +230,7 @@ public: /// math stuff usually isn't allowed in text mode virtual bool allowedIn(mode_type mode) const { return mode == MATH_MODE; } - /// superscript kerning + /// Italic correction as described in InsetMathScript.h virtual int kerning(BufferView const *) const { return 0; } /// bool isInToc() const { return true; } diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index 1fef2209a5..a1c49d16be 100644 --- a/src/mathed/InsetMathChar.cpp +++ b/src/mathed/InsetMathChar.cpp @@ -29,6 +29,10 @@ #include "support/lstrings.h" #include "support/textutils.h" +#include + +using namespace std; + namespace lyx { @@ -105,20 +109,38 @@ Inset * InsetMathChar::clone() const void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const { - bool const mathfont = isMathFont(mi.base.fontname); - if (mathfont && subst_) { + 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_) && mi.base.fontname == "mathnormal") { + } 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_; + } } } @@ -138,6 +160,10 @@ void InsetMathChar::draw(PainterInfo & pi, int x, int y) const return; } } + // cmmi has almost no left bearing: simulate this + if (pi.base.fontname == "mathnormal") { + x += max(-theFontMetrics(pi.base.font).lbearing(char_), 0); + } pi.draw(x, y, char_); } diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp index b5e70fd631..fc72b6b078 100644 --- a/src/mathed/InsetMathScript.cpp +++ b/src/mathed/InsetMathScript.cpp @@ -226,7 +226,8 @@ int InsetMathScript::dx0(BufferView const & bv) const { LASSERT(hasDown(), return 0); Dimension const dim = dimension(bv); - return hasLimits() ? (dim.wid - down().dimension(bv).width()) / 2 : nwid(bv); + return hasLimits() ? (dim.wid - down().dimension(bv).width()) / 2 + : nwid(bv) + min(nker(&bv), 0); } @@ -234,7 +235,8 @@ int InsetMathScript::dx1(BufferView const & bv) const { LASSERT(hasUp(), return 0); Dimension const dim = dimension(bv); - return hasLimits() ? (dim.wid - up().dimension(bv).width()) / 2 : nwid(bv) + nker(&bv); + return hasLimits() ? (dim.wid - up().dimension(bv).width()) / 2 + : nwid(bv) + max(nker(&bv), 0); } @@ -265,10 +267,8 @@ int InsetMathScript::ndes(BufferView const & bv) const int InsetMathScript::nker(BufferView const * bv) const { - if (!nuc().empty()) { - int kerning = nuc().kerning(bv); - return kerning > 0 ? kerning : 0; - } + if (!nuc().empty()) + return nuc().kerning(bv); return 0; } @@ -320,9 +320,9 @@ void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid = max(dim.wid, dimdown.width()); } else { if (hasUp()) - dim.wid = max(dim.wid, nker(mi.base.bv) + dimup.width()); + dim.wid = max(dim.wid, max(nker(mi.base.bv), 0) + dimup.width()); if (hasDown()) - dim.wid = max(dim.wid, dimdown.width()); + dim.wid = max(dim.wid, min(nker(mi.base.bv), 0) + dimdown.width()); dim.wid += nwid(bv); } int na = nasc(bv); diff --git a/src/mathed/InsetMathScript.h b/src/mathed/InsetMathScript.h index d0707439b9..0b96d03ce2 100644 --- a/src/mathed/InsetMathScript.h +++ b/src/mathed/InsetMathScript.h @@ -135,7 +135,10 @@ private: int nasc(BufferView const &) const; /// returns descent of nucleus if any int ndes(BufferView const &) const; - /// returns superscript kerning of nucleus if any + /// Italic correction: amount of displacement between subscript and + /// superscript in math mode as per Appendix G, rule 18f. A positive value + /// shifts the superscript to the right, and a negative value shifts the + /// subscript to the left. int nker(BufferView const * bv) const; /// where do we have to draw the scripts? bool hasLimits() const; diff --git a/src/mathed/InsetMathSideset.h b/src/mathed/InsetMathSideset.h index d5be86316c..e1b70df295 100644 --- a/src/mathed/InsetMathSideset.h +++ b/src/mathed/InsetMathSideset.h @@ -104,7 +104,7 @@ private: int nasc(BufferView const &) const; /// returns descent of nucleus if any int ndes(BufferView const &) const; - /// returns subscript and superscript kerning of nucleus if any + /// Italic correction as described in InsetMathScript.h int nker(BufferView const * bv) const; /// Whether there are two left scripts or one single cell bool scriptl_; diff --git a/src/mathed/InsetMathSpecialChar.cpp b/src/mathed/InsetMathSpecialChar.cpp index 4525ff5309..701bcc8686 100644 --- a/src/mathed/InsetMathSpecialChar.cpp +++ b/src/mathed/InsetMathSpecialChar.cpp @@ -61,7 +61,7 @@ void InsetMathSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const } 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_); } } diff --git a/src/mathed/MathData.h b/src/mathed/MathData.h index a1ce7a6df0..1d2617c8dd 100644 --- a/src/mathed/MathData.h +++ b/src/mathed/MathData.h @@ -166,7 +166,7 @@ public: int slevel() const { return slevel_; } /// additional super/subscript shift int sshift() const { return sshift_; } - /// superscript kerning + /// Italic correction as described in InsetMathScript.h int kerning(BufferView const *) const { return kerning_; } /// void swap(MathData & ar) { base_type::swap(ar); } diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index daf437fc67..1c4f89ca8d 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -556,7 +556,7 @@ int mathed_char_width(FontInfo const & font, char_type c) int mathed_char_kerning(FontInfo const & font, char_type c) { frontend::FontMetrics const & fm = theFontMetrics(font); - return fm.rbearing(c) - fm.width(c); + return max(0, fm.rbearing(c) - fm.width(c)); } -- 2.39.5