From 65a6cc1fc3bc71a53e6f004a9b18e8dd1d32ecf2 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Tue, 24 May 2016 12:08:24 +0200 Subject: [PATCH] Cleanup of spacing in mathed This is a first cleanup step. More complex rules have to be implemented on top of this. Use proper spacing \thinmuskip, \medmuskip and \thickmuskip instead of ad-hoc values. Rename isRelOp to isMathRel and introduce isMathBin and isMathPunct (for InsetMathChar and InsetMathSymbol). Update the categories of characters in InsetMathChar according to LaTeX source (fontmath.ltx). Set correctly the spacing around mathrel, mathbin and mathpunct elements. Use \thinmuskip around MathDelim instead of a hardcoded 4. This is related to bug #8883. --- src/mathed/InsetMath.h | 8 +++++-- src/mathed/InsetMathChar.cpp | 44 +++++++++++++++++++++------------- src/mathed/InsetMathChar.h | 6 ++++- src/mathed/InsetMathDelim.cpp | 9 +++---- src/mathed/InsetMathHull.cpp | 2 +- src/mathed/InsetMathSymbol.cpp | 41 +++++++++++++++++++++---------- src/mathed/InsetMathSymbol.h | 6 ++++- src/mathed/MathSupport.cpp | 41 +++++++++++++++++++++++++++++++ src/mathed/MathSupport.h | 6 +++++ 9 files changed, 125 insertions(+), 38 deletions(-) diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index b23ffb5179..088fce6c2b 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -162,8 +162,12 @@ public: /// identifies things that can get scripts virtual bool isScriptable() const { return false; } - /// is the a relational operator (used for splitting equations) - virtual bool isRelOp() const { return false; } + /// identifies a binary operators (used for spacing) + virtual bool isMathBin() const { return false; } + /// identifies relational operators (used for spacing and splitting equations) + virtual bool isMathRel() const { return false; } + /// identifies punctuation (used for spacing) + virtual bool isMathPunct() const { return false; } /// will this get written as a single block in {..} virtual bool extraBraces() const { return false; } diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index 713e1353e6..2879ac91fc 100644 --- a/src/mathed/InsetMathChar.cpp +++ b/src/mathed/InsetMathChar.cpp @@ -26,7 +26,6 @@ #include "support/debug.h" #include "support/lstrings.h" -#include "support/lyxlib.h" #include "support/textutils.h" @@ -35,12 +34,6 @@ namespace lyx { extern bool has_math_fonts; -static bool isBinaryOp(char_type c) -{ - return support::contains("+-<>=/*", static_cast(c)); -} - - static bool slanted(char_type c) { return isAlphaASCII(c) || Encodings::isMathAlpha(c); @@ -76,11 +69,15 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const dim = fm.dimension(char_); kerning_ = fm.rbearing(char_) - dim.wid; } - int const em = mathed_font_em(mi.base.font); - if (isBinaryOp(char_)) - dim.wid += support::iround(0.5 * em); + 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); else if (char_ == '\'') - dim.wid += support::iround(0.1667 * em); + // 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_); @@ -94,11 +91,12 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const void InsetMathChar::draw(PainterInfo & pi, int x, int y) const { //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << std::endl; - int const em = mathed_font_em(pi.base.font); - if (isBinaryOp(char_)) - x += support::iround(0.25 * em); + if (isMathBin()) + x += mathed_medmuskip(pi.base.font); + else if (isMathRel()) + x += mathed_thickmuskip(pi.base.font); else if (char_ == '\'') - x += support::iround(0.0833 * em); + x += mathed_thinmuskip(pi.base.font) / 2; #if 1 if (char_ == '=' && has_math_fonts) { FontSetChanger dummy(pi.base, "cmr"); @@ -237,9 +235,21 @@ void InsetMathChar::htmlize(HtmlStream & ms) const } -bool InsetMathChar::isRelOp() const +bool InsetMathChar::isMathBin() const { - return char_ == '=' || char_ == '<' || char_ == '>'; + return support::contains("+-*", static_cast(char_)); +} + + +bool InsetMathChar::isMathRel() const +{ + return support::contains("<>=:", static_cast(char_)); +} + + +bool InsetMathChar::isMathPunct() const +{ + return support::contains(",;", static_cast(char_)); } diff --git a/src/mathed/InsetMathChar.h b/src/mathed/InsetMathChar.h index 65fac82fff..67bbc64e8c 100644 --- a/src/mathed/InsetMathChar.h +++ b/src/mathed/InsetMathChar.h @@ -49,7 +49,11 @@ public: /// char_type getChar() const { return char_; } /// - bool isRelOp() const; + bool isMathBin() const; + /// + bool isMathRel() const; + /// + bool isMathPunct() const; /// InsetCode lyxCode() const { return MATH_CHAR_CODE; } diff --git a/src/mathed/InsetMathDelim.cpp b/src/mathed/InsetMathDelim.cpp index 8e8b6e295b..b10d37ad69 100644 --- a/src/mathed/InsetMathDelim.cpp +++ b/src/mathed/InsetMathDelim.cpp @@ -115,7 +115,7 @@ void InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const dw_ = 8; if (dw_ < 4) dw_ = 4; - dim.wid = dim0.width() + 2 * dw_ + 8; + dim.wid = dim0.width() + 2 * dw_ + 2 * mathed_thinmuskip(mi.base.font); dim.asc = max(a0, d0) + h0; dim.des = max(a0, d0) - h0; } @@ -125,9 +125,10 @@ void InsetMathDelim::draw(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); int const b = y - dim.asc; - cell(0).draw(pi, x + dw_ + 4, y); - mathed_draw_deco(pi, x + 4, b, dw_, dim.height(), left_); - mathed_draw_deco(pi, x + dim.width() - dw_ - 4, + int const skip = mathed_thinmuskip(pi.base.font); + cell(0).draw(pi, x + dw_ + skip, y); + mathed_draw_deco(pi, x + skip, b, dw_, dim.height(), left_); + mathed_draw_deco(pi, x + dim.width() - dw_ - skip, b, dw_, dim.height(), right_); setPosCache(pi, x, y); } diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 48792a81ae..34955147e2 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -106,7 +106,7 @@ namespace { size_t firstRelOp(MathData const & ar) { for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->isRelOp()) + if ((*it)->isMathRel()) return it - ar.begin(); return ar.size(); } diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index a160dec684..a04f6e0bcf 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -21,7 +21,6 @@ #include "support/debug.h" #include "support/docstream.h" -#include "support/lyxlib.h" #include "support/textutils.h" #include @@ -68,7 +67,6 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const sym_->extra == "mathalpha" && mi.base.fontname == "mathit"; std::string const font = italic_upcase_greek ? "cmm" : sym_->inset; - int const em = mathed_font_em(mi.base.font); FontSetChanger dummy(mi.base, from_ascii(font)); mathed_string_dim(mi.base.font, sym_->draw, dim); docstring::const_reverse_iterator rit = sym_->draw.rbegin(); @@ -80,10 +78,15 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const dim.des -= h_; } // seperate things a bit - if (isRelOp()) - dim.wid += support::iround(0.5 * em); - else - dim.wid += support::iround(0.1667 * em); + 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); scriptable_ = false; if (mi.base.style == LM_ST_DISPLAY) @@ -105,11 +108,13 @@ void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const sym_->extra == "mathalpha" && pi.base.fontname == "mathit"; std::string const font = italic_upcase_greek ? "cmm" : sym_->inset; - int const em = mathed_font_em(pi.base.font); - if (isRelOp()) - x += support::iround(0.25 * em); - else - x += support::iround(0.0833 * em); + 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); FontSetChanger dummy(pi.base, from_ascii(font)); pi.draw(x, y - h_, sym_->draw); @@ -122,12 +127,24 @@ InsetMath::mode_type InsetMathSymbol::currentMode() const } -bool InsetMathSymbol::isRelOp() const +bool InsetMathSymbol::isMathBin() const +{ + return sym_->extra == "mathbin"; +} + + +bool InsetMathSymbol::isMathRel() const { return sym_->extra == "mathrel"; } +bool InsetMathSymbol::isMathPunct() const +{ + return sym_->extra == "mathpunct"; +} + + bool InsetMathSymbol::isOrdAlpha() const { return sym_->extra == "mathord" || sym_->extra == "mathalpha"; diff --git a/src/mathed/InsetMathSymbol.h b/src/mathed/InsetMathSymbol.h index bb18217a84..6ca3ded7d1 100644 --- a/src/mathed/InsetMathSymbol.h +++ b/src/mathed/InsetMathSymbol.h @@ -40,7 +40,11 @@ public: /// mode_type currentMode() const; /// - bool isRelOp() const; + bool isMathRel() const; + /// + bool isMathBin() const; + /// + bool isMathPunct() const; /// bool isOrdAlpha() const; /// do we take scripts? diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 9801151129..7769176e7a 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -25,6 +25,7 @@ #include "support/debug.h" #include "support/docstream.h" +#include "support/lyxlib.h" #include #include @@ -506,6 +507,46 @@ int mathed_font_em(FontInfo const & font) return theFontMetrics(font).em(); } +/* The math units. Quoting TeX by Topic, p.205: + * + * Spacing around mathematical objects is measured in mu units. A mu + * is 1/18th part of \fontdimen6 of the font in family 2 in the + * current style, the ‘quad’ value of the symbol font. + * + * A \thickmuskip (default value in plain TeX: 5mu plus 5mu) is + * inserted around (binary) relations, except where these are preceded + * or followed by other relations or punctuation, and except if they + * follow an open, or precede a close symbol. + * + * A \medmuskip (default value in plain TeX: 4mu plus 2mu minus 4mu) + * is put around binary operators. + * + * A \thinmuskip (default value in plain TeX: 3mu) follows after + * punctuation, and is put around inner objects, except where these + * are followed by a close or preceded by an open symbol, and except + * if the other object is a large operator or a binary relation. + */ + +int mathed_thinmuskip(FontInfo font) +{ + font.setFamily(SYMBOL_FAMILY); + return support::iround(3.0 / 18 * theFontMetrics(font).em()); +} + + +int mathed_medmuskip(FontInfo font) +{ + font.setFamily(SYMBOL_FAMILY); + return support::iround(4.0 / 18 * theFontMetrics(font).em()); +} + + +int mathed_thickmuskip(FontInfo font) +{ + font.setFamily(SYMBOL_FAMILY); + return support::iround(5.0 / 18 * theFontMetrics(font).em()); +} + int mathed_char_width(FontInfo const & font, char_type c) { diff --git a/src/mathed/MathSupport.h b/src/mathed/MathSupport.h index aa5ef2adc2..c14f21a807 100644 --- a/src/mathed/MathSupport.h +++ b/src/mathed/MathSupport.h @@ -29,6 +29,12 @@ class InsetMath; int mathed_font_em(FontInfo const &); +int mathed_thinmuskip(FontInfo font); + +int mathed_medmuskip(FontInfo font); + +int mathed_thickmuskip(FontInfo font); + int mathed_char_width(FontInfo const &, char_type c); int mathed_char_kerning(FontInfo const &, char_type c);