From 8f98ec35e41b8cbeda39dd95aa812c3a6839c152 Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Fri, 1 Dec 2006 16:12:24 +0000 Subject: [PATCH] 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 --- src/dimension.C | 8 +++ src/dimension.h | 8 ++- src/frontends/FontMetrics.h | 9 +-- src/frontends/NoGuiFontMetrics.h | 2 + src/frontends/qt4/GuiFontMetrics.C | 101 +++++++++++++++++++---------- src/frontends/qt4/GuiFontMetrics.h | 49 +++++++++----- src/mathed/InsetMathBrace.C | 6 +- src/mathed/InsetMathChar.C | 10 +-- src/mathed/InsetMathDelim.C | 2 +- src/mathed/InsetMathDots.C | 2 +- src/mathed/MathData.C | 2 +- src/mathed/MathSupport.C | 9 --- src/mathed/MathSupport.h | 1 - src/rowpainter.C | 2 +- 14 files changed, 130 insertions(+), 81 deletions(-) diff --git a/src/dimension.C b/src/dimension.C index c7cbdbc937..847fdd71f5 100644 --- a/src/dimension.C +++ b/src/dimension.C @@ -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 diff --git a/src/dimension.h b/src/dimension.h index bf42106de0..26bd71064b 100644 --- a/src/dimension.h +++ b/src/dimension.h @@ -12,6 +12,7 @@ #ifndef DIMENSION_H #define DIMENSION_H +#include "support/types.h" namespace lyx { @@ -25,6 +26,8 @@ public: /// initialize data 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) { wid = dim.wid; asc = dim.asc; @@ -35,8 +38,11 @@ public: void operator+=(Dimension const & dim); /// set to empty box 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); + /// set to a char dimensions for a given font. + void set(LyXFont const & font, char_type c); + /// get height int height() const { return asc + des; } /// get ascent diff --git a/src/frontends/FontMetrics.h b/src/frontends/FontMetrics.h index 829b5cec1f..20c7808f9f 100644 --- a/src/frontends/FontMetrics.h +++ b/src/frontends/FontMetrics.h @@ -58,6 +58,8 @@ public: virtual int maxAscent() const = 0; /// return the maximum descent of the font 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 virtual int ascent(char_type c) const = 0; /// return the descent of the char in the font @@ -103,13 +105,6 @@ public: 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 inline int width(docstring const & s) const { diff --git a/src/frontends/NoGuiFontMetrics.h b/src/frontends/NoGuiFontMetrics.h index 6bbdcaed10..5faaf685f8 100644 --- a/src/frontends/NoGuiFontMetrics.h +++ b/src/frontends/NoGuiFontMetrics.h @@ -31,6 +31,8 @@ public: virtual int maxDescent() const { return 1; } + virtual int width(char_type) const { return 1; } + virtual int ascent(char_type) const { return 1; } int descent(char_type) const { return 1; } diff --git a/src/frontends/qt4/GuiFontMetrics.C b/src/frontends/qt4/GuiFontMetrics.C index d1ed0ecea8..a10381096f 100644 --- a/src/frontends/qt4/GuiFontMetrics.C +++ b/src/frontends/qt4/GuiFontMetrics.C @@ -19,9 +19,6 @@ #include "support/unicode.h" -using lyx::char_type; -using lyx::docstring; - using std::string; namespace lyx { @@ -32,8 +29,11 @@ GuiFontMetrics::GuiFontMetrics(QFont const & font) : metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false) { #ifdef USE_LYX_FONTCACHE - for (int i = 0; i != 65536; ++i) - widthcache_[i] = -1; + for (int i = 0; i != 65536; ++i) { + metrics_cache_[i].width = -1000; + metrics_cache_[i].ascent = -1000; + metrics_cache_[i].descent = -1000; + } #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 { 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. if (ls == 1 && !smallcaps_shape_) { - QChar const c = ucs4_to_qchar(s[0]); - return width(c.unicode()); + return width(s[0]); } - QString ucs2; - ucs4_to_qstring(s, ls, ucs2); - - if (smallcaps_shape_) + if (smallcaps_shape_) { + QString ucs2; + ucs4_to_qstring(s, ls, ucs2); return smallcapsWidth(ucs2); + } int w = 0; for (unsigned int i = 0; i < ls; ++i) - w += width(ucs2[i].unicode()); + w += width(s[i]); return w; } @@ -178,14 +163,64 @@ void GuiFontMetrics::buttonText(docstring const & str, descent = metrics_.descent() + d; } -#ifdef USE_LYX_FONTCACHE -int GuiFontMetrics::width(unsigned short val) const +#ifndef USE_LYX_FONTCACHE + +int GuiFontMetrics::ascent(char_type c) const { - if (widthcache_[val] == -1) - widthcache_[val] = metrics_.width(QChar(val)); - return widthcache_[val]; + 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; +} + +#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(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(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(c); + if (metrics_cache_[val].descent == -1000) + fillCache(val); + + return metrics_cache_[val].descent; +} + #endif -} -} +} // frontend +} // lyx diff --git a/src/frontends/qt4/GuiFontMetrics.h b/src/frontends/qt4/GuiFontMetrics.h index 194c8f828d..d310741cc3 100644 --- a/src/frontends/qt4/GuiFontMetrics.h +++ b/src/frontends/qt4/GuiFontMetrics.h @@ -27,6 +27,14 @@ namespace lyx { namespace frontend { +struct CharMetrics +{ + int width; + int ascent; + int descent; +}; + + class GuiFontMetrics: public FontMetrics { public: @@ -38,17 +46,24 @@ public: virtual int maxAscent() const; virtual int maxDescent() const; - virtual int ascent(lyx::char_type c) const; - int descent(lyx::char_type c) const; - virtual int lbearing(lyx::char_type c) const; - virtual int rbearing(lyx::char_type c) const; - virtual int width(lyx::char_type const * s, size_t n) const; - virtual int signedWidth(lyx::docstring const & s) const; - virtual void rectText(lyx::docstring const & str, +#ifndef USE_LYX_FONTCACHE + virtual int width(char_type c) const { + return metrics_.width(QChar(static_cast(c))); + } +#else + virtual int width(char_type c) const; +#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 & ascent, int & descent) const; - virtual void buttonText(lyx::docstring const & str, + virtual void buttonText(docstring const & str, int & width, int & ascent, int & descent) const; @@ -64,16 +79,16 @@ private: bool smallcaps_shape_; -#ifndef USE_LYX_FONTCACHE - /// Return pixel width for the given unicode char - int width(unsigned short val) const { return metrics_.width(QChar(val)); } - -#else - /// Return pixel width for the given unicode char - int width(unsigned short val) const; - +#ifdef USE_LYX_FONTCACHE + /// fill in \c metrics_cache_ at specified value. + void fillCache(unsigned short val) const; /// 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 }; diff --git a/src/mathed/InsetMathBrace.C b/src/mathed/InsetMathBrace.C index 736a47250a..acae12e684 100644 --- a/src/mathed/InsetMathBrace.C +++ b/src/mathed/InsetMathBrace.C @@ -46,8 +46,7 @@ auto_ptr InsetMathBrace::doClone() const bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi); - Dimension t; - mathed_char_dim(mi.base.font, '{', t); + Dimension t(mi.base.font, '{'); dim.asc = max(cell(0).ascent(), t.asc); dim.des = max(cell(0).descent(), t.des); 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; font.setColor(LColor::latex); - Dimension t; - mathed_char_dim(font, '{', t); + Dimension t(font, '{'); pi.pain.text(x, y, '{', font); cell(0).draw(pi, x + t.wid, y); pi.pain.text(x + t.wid + cell(0).width(), y, '}', font); diff --git a/src/mathed/InsetMathChar.C b/src/mathed/InsetMathChar.C index aadcbc06cc..004fb2283d 100644 --- a/src/mathed/InsetMathChar.C +++ b/src/mathed/InsetMathChar.C @@ -62,15 +62,15 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const #if 1 if (char_ == '=' && has_math_fonts) { 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) { 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") { ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE); - mathed_char_dim(mi.base.font, char_, dim); + dim.set(mi.base.font, char_); } 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'); if (isBinaryOp(char_)) @@ -79,7 +79,7 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid += static_cast(0.1667*em+0.5); #else whichFont(font_, code_, mi); - mathed_char_dim(font_, char_, dim); + dim.set(font_, char_); if (isBinaryOp(char_, code_)) width_ += 2 * theFontMetrics(font_).width(' '); lyxerr << "InsetMathChar::metrics: " << dim << endl; diff --git a/src/mathed/InsetMathDelim.C b/src/mathed/InsetMathDelim.C index f74b81e3bb..2805ac9863 100644 --- a/src/mathed/InsetMathDelim.C +++ b/src/mathed/InsetMathDelim.C @@ -75,7 +75,7 @@ bool InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const { cell(0).metrics(mi); Dimension t; - mathed_char_dim(mi.base.font, 'I', t); + t.set(mi.base.font, 'I'); int h0 = (t.asc + t.des) / 2; int a0 = max(cell(0).ascent(), t.asc) - h0; int d0 = max(cell(0).descent(), t.des) + h0; diff --git a/src/mathed/InsetMathDots.C b/src/mathed/InsetMathDots.C index 5178aa6432..3f87f29f53 100644 --- a/src/mathed/InsetMathDots.C +++ b/src/mathed/InsetMathDots.C @@ -37,7 +37,7 @@ auto_ptr InsetMathDots::doClone() 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; if (key_->name == "cdots" || key_->name == "dotsb" || key_->name == "dotsm" || key_->name == "dotsi") diff --git a/src/mathed/MathData.C b/src/mathed/MathData.C index f36bf570ba..06dd9db4d1 100644 --- a/src/mathed/MathData.C +++ b/src/mathed/MathData.C @@ -241,7 +241,7 @@ bool isInside(DocIterator const & it, MathArray const & ar, void MathArray::metrics(MetricsInfo & mi) const { - mathed_char_dim(mi.base.font, 'I', dim_); + dim_.set(mi.base.font, 'I'); if (empty()) return; diff --git a/src/mathed/MathSupport.C b/src/mathed/MathSupport.C index 333ddaa7c0..ff35c7c527 100644 --- a/src/mathed/MathSupport.C +++ b/src/mathed/MathSupport.C @@ -367,15 +367,6 @@ deco_struct const * search_deco(docstring const & name) } // 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) { return theFontMetrics(font).width(c); diff --git a/src/mathed/MathSupport.h b/src/mathed/MathSupport.h index a1396e2338..d872b371f9 100644 --- a/src/mathed/MathSupport.h +++ b/src/mathed/MathSupport.h @@ -28,7 +28,6 @@ class MathAtom; class InsetMath; -void mathed_char_dim(LyXFont const &, char_type c, Dimension & dim); int mathed_char_width(LyXFont const &, char_type c); void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, diff --git a/src/rowpainter.C b/src/rowpainter.C index 6074cd07b9..5b83338af9 100644 --- a/src/rowpainter.C +++ b/src/rowpainter.C @@ -949,7 +949,7 @@ void paintPar rp.paintChangeBar(); if (rit == rb) rp.paintFirst(); - rp.paintText(); + rp.paintText(); if (rit + 1 == re) rp.paintLast(); }