This commit fixes the following bug:

http://bugzilla.lyx.org/show_bug.cgi?id=2900

The only drawback is that it requires about 20Mo extra-memory when loading the UserGuide. If it turns out to be too much, we can switch to a QHash based solution instead of a table.

* dimension.[Ch]:
  - Dimension(LyXFont const, char_typec): new ctor
  - set(LyXFont const & font, char_type c): new method.

* frontends/FontMetrics.h:
  - width(char_type): is now a pure virtual method.

* GuiFontMetrics:
  - CharMetrics: new structure;
  - the metrics cache now also cache ascent and descent. This is especially useful for mathed.

* MathSupport.[Ch]:
  - mathed_char_dim(): deleted. We now use Dimension::set() directly instead.

* rowpainter.C: fixe empty space.



git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16124 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2006-12-01 16:12:24 +00:00
parent 7cf79bc298
commit 8f98ec35e4
14 changed files with 130 additions and 81 deletions

View File

@ -36,4 +36,12 @@ void Dimension::clear(LyXFont const & font)
} }
void Dimension::set(LyXFont const & font, char_type c)
{
frontend::FontMetrics const & fm = theFontMetrics(font);
des = fm.descent(c);
asc = fm.ascent(c);
wid = fm.width(c);
}
} // namespace lyx } // namespace lyx

View File

@ -12,6 +12,7 @@
#ifndef DIMENSION_H #ifndef DIMENSION_H
#define DIMENSION_H #define DIMENSION_H
#include "support/types.h"
namespace lyx { namespace lyx {
@ -25,6 +26,8 @@ public:
/// initialize data /// initialize data
Dimension(int w, int a, int d) : wid(w), asc(a), des(d) {} Dimension(int w, int a, int d) : wid(w), asc(a), des(d) {}
Dimension(LyXFont const & font, char_type c) { set(font, c); }
Dimension & operator=(Dimension const & dim) { Dimension & operator=(Dimension const & dim) {
wid = dim.wid; wid = dim.wid;
asc = dim.asc; asc = dim.asc;
@ -35,8 +38,11 @@ public:
void operator+=(Dimension const & dim); void operator+=(Dimension const & dim);
/// set to empty box /// set to empty box
void clear() { wid = asc = des = 0; } void clear() { wid = asc = des = 0; }
/// set to empty box suitble for given font /// set to empty box suitble for given font.
void clear(LyXFont const & font); void clear(LyXFont const & font);
/// set to a char dimensions for a given font.
void set(LyXFont const & font, char_type c);
/// get height /// get height
int height() const { return asc + des; } int height() const { return asc + des; }
/// get ascent /// get ascent

View File

@ -58,6 +58,8 @@ public:
virtual int maxAscent() const = 0; virtual int maxAscent() const = 0;
/// return the maximum descent of the font /// return the maximum descent of the font
virtual int maxDescent() const = 0; virtual int maxDescent() const = 0;
/// return the width of the char in the font
virtual int width(char_type c) const = 0;
/// return the ascent of the char in the font /// return the ascent of the char in the font
virtual int ascent(char_type c) const = 0; virtual int ascent(char_type c) const = 0;
/// return the descent of the char in the font /// return the descent of the char in the font
@ -103,13 +105,6 @@ public:
return (rbearing(c) - lbearing(c)) / 2; return (rbearing(c) - lbearing(c)) / 2;
} }
/// return the width of the char in the font
inline int width(char_type c) const
{
char_type tmp[2] = { c, L'\0'};
return width(tmp, 1);
}
/// return the width of the string in the font /// return the width of the string in the font
inline int width(docstring const & s) const inline int width(docstring const & s) const
{ {

View File

@ -31,6 +31,8 @@ public:
virtual int maxDescent() const { return 1; } virtual int maxDescent() const { return 1; }
virtual int width(char_type) const { return 1; }
virtual int ascent(char_type) const { return 1; } virtual int ascent(char_type) const { return 1; }
int descent(char_type) const { return 1; } int descent(char_type) const { return 1; }

View File

@ -19,9 +19,6 @@
#include "support/unicode.h" #include "support/unicode.h"
using lyx::char_type;
using lyx::docstring;
using std::string; using std::string;
namespace lyx { namespace lyx {
@ -32,8 +29,11 @@ GuiFontMetrics::GuiFontMetrics(QFont const & font)
: metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false) : metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false)
{ {
#ifdef USE_LYX_FONTCACHE #ifdef USE_LYX_FONTCACHE
for (int i = 0; i != 65536; ++i) for (int i = 0; i != 65536; ++i) {
widthcache_[i] = -1; metrics_cache_[i].width = -1000;
metrics_cache_[i].ascent = -1000;
metrics_cache_[i].descent = -1000;
}
#endif #endif
} }
@ -58,20 +58,6 @@ int GuiFontMetrics::maxDescent() const
} }
int GuiFontMetrics::ascent(char_type c) const
{
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
return -r.top();
}
int GuiFontMetrics::descent(char_type c) const
{
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
return r.bottom() + 1;
}
int GuiFontMetrics::lbearing(char_type c) const int GuiFontMetrics::lbearing(char_type c) const
{ {
return metrics_.leftBearing(ucs4_to_qchar(c)); return metrics_.leftBearing(ucs4_to_qchar(c));
@ -110,19 +96,18 @@ int GuiFontMetrics::width(char_type const * s, size_t ls) const
// casts in reality. // casts in reality.
if (ls == 1 && !smallcaps_shape_) { if (ls == 1 && !smallcaps_shape_) {
QChar const c = ucs4_to_qchar(s[0]); return width(s[0]);
return width(c.unicode());
} }
if (smallcaps_shape_) {
QString ucs2; QString ucs2;
ucs4_to_qstring(s, ls, ucs2); ucs4_to_qstring(s, ls, ucs2);
if (smallcaps_shape_)
return smallcapsWidth(ucs2); return smallcapsWidth(ucs2);
}
int w = 0; int w = 0;
for (unsigned int i = 0; i < ls; ++i) for (unsigned int i = 0; i < ls; ++i)
w += width(ucs2[i].unicode()); w += width(s[i]);
return w; return w;
} }
@ -178,14 +163,64 @@ void GuiFontMetrics::buttonText(docstring const & str,
descent = metrics_.descent() + d; descent = metrics_.descent() + d;
} }
#ifdef USE_LYX_FONTCACHE #ifndef USE_LYX_FONTCACHE
int GuiFontMetrics::width(unsigned short val) const
int GuiFontMetrics::ascent(char_type c) const
{ {
if (widthcache_[val] == -1) QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
widthcache_[val] = metrics_.width(QChar(val)); return -r.top();
return widthcache_[val];
} }
int GuiFontMetrics::descent(char_type c) const
{
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
return r.bottom() + 1;
}
#else
void GuiFontMetrics::fillCache(unsigned short val) const
{
QRect const & r = metrics_.boundingRect(QChar(val));
metrics_cache_[val].descent = r.bottom() + 1;
metrics_cache_[val].ascent = -r.top();
// We could as well compute the width but this is not really
// needed for now as it is done directly in width() below.
//metrics_cache_[val].width = metrics_.width(QChar(val));
}
int GuiFontMetrics::width(char_type c) const
{
unsigned short val = static_cast<unsigned short>(c);
if (metrics_cache_[val].width == -1000)
metrics_cache_[val].width = metrics_.width(QChar(val));
return metrics_cache_[val].width;
}
int GuiFontMetrics::ascent(char_type c) const
{
unsigned short val = static_cast<unsigned short>(c);
if (metrics_cache_[val].ascent == -1000)
fillCache(val);
return metrics_cache_[val].ascent;
}
int GuiFontMetrics::descent(char_type c) const
{
unsigned short val = static_cast<unsigned short>(c);
if (metrics_cache_[val].descent == -1000)
fillCache(val);
return metrics_cache_[val].descent;
}
#endif #endif
} } // frontend
} } // lyx

View File

@ -27,6 +27,14 @@
namespace lyx { namespace lyx {
namespace frontend { namespace frontend {
struct CharMetrics
{
int width;
int ascent;
int descent;
};
class GuiFontMetrics: public FontMetrics class GuiFontMetrics: public FontMetrics
{ {
public: public:
@ -38,17 +46,24 @@ public:
virtual int maxAscent() const; virtual int maxAscent() const;
virtual int maxDescent() const; virtual int maxDescent() const;
virtual int ascent(lyx::char_type c) const; #ifndef USE_LYX_FONTCACHE
int descent(lyx::char_type c) const; virtual int width(char_type c) const {
virtual int lbearing(lyx::char_type c) const; return metrics_.width(QChar(static_cast<short int>(c)));
virtual int rbearing(lyx::char_type c) const; }
virtual int width(lyx::char_type const * s, size_t n) const; #else
virtual int signedWidth(lyx::docstring const & s) const; virtual int width(char_type c) const;
virtual void rectText(lyx::docstring const & str, #endif
virtual int ascent(char_type c) const;
virtual int descent(char_type c) const;
virtual int lbearing(char_type c) const;
virtual int rbearing(char_type c) const;
virtual int width(char_type const * s, size_t n) const;
virtual int signedWidth(docstring const & s) const;
virtual void rectText(docstring const & str,
int & width, int & width,
int & ascent, int & ascent,
int & descent) const; int & descent) const;
virtual void buttonText(lyx::docstring const & str, virtual void buttonText(docstring const & str,
int & width, int & width,
int & ascent, int & ascent,
int & descent) const; int & descent) const;
@ -64,16 +79,16 @@ private:
bool smallcaps_shape_; bool smallcaps_shape_;
#ifndef USE_LYX_FONTCACHE #ifdef USE_LYX_FONTCACHE
/// Return pixel width for the given unicode char /// fill in \c metrics_cache_ at specified value.
int width(unsigned short val) const { return metrics_.width(QChar(val)); } void fillCache(unsigned short val) const;
#else
/// Return pixel width for the given unicode char
int width(unsigned short val) const;
/// Cache of char widths /// Cache of char widths
mutable int widthcache_[65536]; /** This cache adds 20Mo of memory to the LyX executable when
* loading UserGuide.lyx which contains a good number of fonts. If
* this turns out to be too much, we can switch to a \c QHash based
* solution.
**/
mutable CharMetrics metrics_cache_[65536];
#endif // USE_LYX_FONTCACHE #endif // USE_LYX_FONTCACHE
}; };

View File

@ -46,8 +46,7 @@ auto_ptr<InsetBase> InsetMathBrace::doClone() const
bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const
{ {
cell(0).metrics(mi); cell(0).metrics(mi);
Dimension t; Dimension t(mi.base.font, '{');
mathed_char_dim(mi.base.font, '{', t);
dim.asc = max(cell(0).ascent(), t.asc); dim.asc = max(cell(0).ascent(), t.asc);
dim.des = max(cell(0).descent(), t.des); dim.des = max(cell(0).descent(), t.des);
dim.wid = cell(0).width() + 2 * t.wid; dim.wid = cell(0).width() + 2 * t.wid;
@ -63,8 +62,7 @@ void InsetMathBrace::draw(PainterInfo & pi, int x, int y) const
{ {
LyXFont font = pi.base.font; LyXFont font = pi.base.font;
font.setColor(LColor::latex); font.setColor(LColor::latex);
Dimension t; Dimension t(font, '{');
mathed_char_dim(font, '{', t);
pi.pain.text(x, y, '{', font); pi.pain.text(x, y, '{', font);
cell(0).draw(pi, x + t.wid, y); cell(0).draw(pi, x + t.wid, y);
pi.pain.text(x + t.wid + cell(0).width(), y, '}', font); pi.pain.text(x + t.wid + cell(0).width(), y, '}', font);

View File

@ -62,15 +62,15 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
#if 1 #if 1
if (char_ == '=' && has_math_fonts) { if (char_ == '=' && has_math_fonts) {
FontSetChanger dummy(mi.base, "cmr"); FontSetChanger dummy(mi.base, "cmr");
mathed_char_dim(mi.base.font, char_, dim); dim.set(mi.base.font, char_);
} else if ((char_ == '>' || char_ == '<') && has_math_fonts) { } else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
FontSetChanger dummy(mi.base, "cmm"); FontSetChanger dummy(mi.base, "cmm");
mathed_char_dim(mi.base.font, char_, dim); dim.set(mi.base.font, char_);
} else if (!slanted(char_) && mi.base.fontname == "mathnormal") { } else if (!slanted(char_) && mi.base.fontname == "mathnormal") {
ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE); ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE);
mathed_char_dim(mi.base.font, char_, dim); dim.set(mi.base.font, char_);
} else { } else {
mathed_char_dim(mi.base.font, char_, dim); dim.set(mi.base.font, char_);
} }
int const em = mathed_char_width(mi.base.font, 'M'); int const em = mathed_char_width(mi.base.font, 'M');
if (isBinaryOp(char_)) if (isBinaryOp(char_))
@ -79,7 +79,7 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
dim.wid += static_cast<int>(0.1667*em+0.5); dim.wid += static_cast<int>(0.1667*em+0.5);
#else #else
whichFont(font_, code_, mi); whichFont(font_, code_, mi);
mathed_char_dim(font_, char_, dim); dim.set(font_, char_);
if (isBinaryOp(char_, code_)) if (isBinaryOp(char_, code_))
width_ += 2 * theFontMetrics(font_).width(' '); width_ += 2 * theFontMetrics(font_).width(' ');
lyxerr << "InsetMathChar::metrics: " << dim << endl; lyxerr << "InsetMathChar::metrics: " << dim << endl;

View File

@ -75,7 +75,7 @@ bool InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const
{ {
cell(0).metrics(mi); cell(0).metrics(mi);
Dimension t; Dimension t;
mathed_char_dim(mi.base.font, 'I', t); t.set(mi.base.font, 'I');
int h0 = (t.asc + t.des) / 2; int h0 = (t.asc + t.des) / 2;
int a0 = max(cell(0).ascent(), t.asc) - h0; int a0 = max(cell(0).ascent(), t.asc) - h0;
int d0 = max(cell(0).descent(), t.des) + h0; int d0 = max(cell(0).descent(), t.des) + h0;

View File

@ -37,7 +37,7 @@ auto_ptr<InsetBase> InsetMathDots::doClone() const
bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const
{ {
mathed_char_dim(mi.base.font, 'M', dim); dim.set(mi.base.font, 'M');
dh_ = 0; dh_ = 0;
if (key_->name == "cdots" || key_->name == "dotsb" if (key_->name == "cdots" || key_->name == "dotsb"
|| key_->name == "dotsm" || key_->name == "dotsi") || key_->name == "dotsm" || key_->name == "dotsi")

View File

@ -241,7 +241,7 @@ bool isInside(DocIterator const & it, MathArray const & ar,
void MathArray::metrics(MetricsInfo & mi) const void MathArray::metrics(MetricsInfo & mi) const
{ {
mathed_char_dim(mi.base.font, 'I', dim_); dim_.set(mi.base.font, 'I');
if (empty()) if (empty())
return; return;

View File

@ -367,15 +367,6 @@ deco_struct const * search_deco(docstring const & name)
} // namespace anon } // namespace anon
void mathed_char_dim(LyXFont const & font, char_type c, Dimension & dim)
{
frontend::FontMetrics const & fm = theFontMetrics(font);
dim.des = fm.descent(c);
dim.asc = fm.ascent(c);
dim.wid = fm.width(c);
}
int mathed_char_width(LyXFont const & font, char_type c) int mathed_char_width(LyXFont const & font, char_type c)
{ {
return theFontMetrics(font).width(c); return theFontMetrics(font).width(c);

View File

@ -28,7 +28,6 @@ class MathAtom;
class InsetMath; class InsetMath;
void mathed_char_dim(LyXFont const &, char_type c, Dimension & dim);
int mathed_char_width(LyXFont const &, char_type c); int mathed_char_width(LyXFont const &, char_type c);
void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,