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.
This commit is contained in:
Jean-Marc Lasgouttes 2016-05-24 12:08:24 +02:00 committed by Richard Heck
parent 320b616c50
commit 65a6cc1fc3
9 changed files with 125 additions and 38 deletions

View File

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

View File

@ -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<char>(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>(char_));
}
bool InsetMathChar::isMathRel() const
{
return support::contains("<>=:", static_cast<char>(char_));
}
bool InsetMathChar::isMathPunct() const
{
return support::contains(",;", static_cast<char>(char_));
}

View File

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

View File

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

View File

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

View File

@ -21,7 +21,6 @@
#include "support/debug.h"
#include "support/docstream.h"
#include "support/lyxlib.h"
#include "support/textutils.h"
#include <boost/scoped_ptr.hpp>
@ -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";

View File

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

View File

@ -25,6 +25,7 @@
#include "support/debug.h"
#include "support/docstream.h"
#include "support/lyxlib.h"
#include <map>
#include <algorithm>
@ -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)
{

View File

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