The following patch reduces the number of calls to getFont by the two following means:
1/ in RowPainter::paintChars, determine the current font span (range with same font around of some position) first; this means that it is not necessary to check the font of each character. 2/ have RowPainter::paintFromPos pass the current font to the relevant paintXXX method, since it is already known While gprof shows that LyXText::getFont is an important offender, it is difficult to know to what extent it hurts. In particular, I cannot get gprof to take in account the time spent in qt library methods (this means all the actual painting is missing, for example). Some weeks ago, I was able to test drawing speed with something like: time src/lyx -x 'command-sequence file-open Customization.lyx ; repeat 300 screen-down ; lyx-quit' 2>/dev/null However, this does not seem to work with the latest code, since no drawing seems to happen... I would be glad to get some insight about how profiling could be done. Other than that, I think the patch is a good thing in general and propose to apply it, maybe once some people have taken the time to look at it and try it. There is still a lot of room for improvement in particular in LyXText::rowBreakPoint and LyXText::setRowWidth. For your enjoyment, I also attach the patch that removes font metrics caching for qt, which I think is also relevant. JMarc
Index: src/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/ChangeLog,v retrieving revision 1.2196 diff -u -p -r1.2196 ChangeLog --- src/ChangeLog 7 Jun 2005 16:50:00 -0000 1.2196 +++ src/ChangeLog 8 Jun 2005 15:13:12 -0000 @@ -1,3 +1,19 @@ +2005-06-08 Jean-Marc Lasgouttes <[EMAIL PROTECTED]> + + * rowpainter.C (paintInset, paintHebrewComposeChar) + (paintArabicComposeChar, paintChars): add a LyXFont argument. + (paintChars): use getFontSpan to reduce calls to getFont to a + minimum; use Paragraph::lookupChange instead of isXXXText. + (paintForeignMark): rename LyXFont argument. + (paintFromPos): pass a LyXFont object to the various paintXXX + methods. + + * FontIterator.C (FontIterator, operator++): use + Paragraph::getFontSpan + + * paragraph.C (getFontSpan): replace getEndOfFontSpan with a + version that returns the font span as a pair. + 2005-06-07 Georg Baum <[EMAIL PROTECTED]> * lyx_main.C (parse_execute): Fix last fix: is_gui = false Index: src/FontIterator.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/FontIterator.C,v retrieving revision 1.7 diff -u -p -r1.7 FontIterator.C --- src/FontIterator.C 11 Apr 2005 13:35:15 -0000 1.7 +++ src/FontIterator.C 8 Jun 2005 15:13:12 -0000 @@ -22,7 +22,7 @@ FontIterator::FontIterator(LyXText const lyx::pos_type pos) : text_(text), par_(par), pos_(pos), font_(text.getFont(par, pos)), - endspan_(par.getEndPosOfFontSpan(pos)), + endspan_(par.getFontSpan(pos).second), bodypos_(par.beginOfBody()) {} @@ -44,7 +44,7 @@ FontIterator & FontIterator::operator++( ++pos_; if (pos_ > endspan_ || pos_ == bodypos_) { font_ = text_.getFont(par_, pos_); - endspan_ = par_.getEndPosOfFontSpan(pos_); + endspan_ = par_.getFontSpan(pos_).second; } return *this; } Index: src/paragraph.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/paragraph.C,v retrieving revision 1.405 diff -u -p -r1.405 paragraph.C --- src/paragraph.C 5 May 2005 18:33:47 -0000 1.405 +++ src/paragraph.C 8 Jun 2005 15:13:12 -0000 @@ -346,20 +346,23 @@ LyXFont const Paragraph::getFontSettings } -lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const +std::pair<lyx::pos_type, lyx::pos_type> Paragraph::getFontSpan(lyx::pos_type pos) const { BOOST_ASSERT(pos <= size()); + lyx::pos_type start = 0; Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin(); Pimpl::FontList::const_iterator end = pimpl_->fontlist.end(); - for (; cit != end; ++cit) + for (; cit != end; ++cit) { if (cit->pos() >= pos) - return cit->pos(); + return std::make_pair(start, cit->pos()); + start = cit->pos() - 1; + } // This should not happen, but if so, we take no chances. //lyxerr << "Paragraph::getEndPosOfFontSpan: This should not happen!" // << endl; - return pos; + return std::make_pair(pos, pos); } Index: src/paragraph.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/paragraph.h,v retrieving revision 1.148 diff -u -p -r1.148 paragraph.h --- src/paragraph.h 26 Apr 2005 11:12:10 -0000 1.148 +++ src/paragraph.h 8 Jun 2005 15:13:12 -0000 @@ -29,6 +29,7 @@ #include <boost/assert.hpp> #include <string> +#include <utility> class Buffer; class BufferParams; @@ -280,11 +281,12 @@ public: LyXFont const & outerfont) const; /** * The font returned by the above functions is the same in a - * span of characters. This method will return the last position - * in the paragraph for which that font is the same. - * This can be used to avoid unnecessary calls to getFont. + * span of characters. This method will return the first and + * the last last positions in the paragraph for which that + * font is the same. This can be used to avoid unnecessary + * calls to getFont. */ - lyx::pos_type getEndPosOfFontSpan(lyx::pos_type pos) const; + std::pair<lyx::pos_type, lyx::pos_type> getFontSpan(lyx::pos_type pos) const; /// /// this is a bottleneck. value_type getChar(lyx::pos_type pos) const Index: src/rowpainter.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/rowpainter.C,v retrieving revision 1.150 diff -u -p -r1.150 rowpainter.C --- src/rowpainter.C 31 May 2005 14:40:25 -0000 1.150 +++ src/rowpainter.C 8 Jun 2005 15:13:12 -0000 @@ -69,13 +69,14 @@ public: void paintText(); private: - void paintForeignMark(double orig_x, LyXFont const & orig_font); - void paintHebrewComposeChar(lyx::pos_type & vpos); - void paintArabicComposeChar(lyx::pos_type & vpos); - void paintChars(lyx::pos_type & vpos, bool hebrew, bool arabic); + void paintForeignMark(double orig_x, LyXFont const & font); + void paintHebrewComposeChar(lyx::pos_type & vpos, LyXFont const & font); + void paintArabicComposeChar(lyx::pos_type & vpos, LyXFont const & font); + void paintChars(lyx::pos_type & vpos, LyXFont font, + bool hebrew, bool arabic); int paintAppendixStart(int y); void paintFromPos(lyx::pos_type & vpos); - void paintInset(lyx::pos_type const pos); + void paintInset(lyx::pos_type const pos, LyXFont const & font); /// return left margin int leftMargin() const; @@ -173,12 +174,12 @@ int RowPainter::leftMargin() const } -void RowPainter::paintInset(pos_type const pos) +void RowPainter::paintInset(pos_type const pos, LyXFont const & font) { InsetBase const * inset = par_.getInset(pos); BOOST_ASSERT(inset); PainterInfo pi(const_cast<BufferView *>(&bv_), pain_); - pi.base.font = getFont(pos); + pi.base.font = font; pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0); theCoords.insets().add(inset, int(x_), yo_); inset->drawSelection(pi, int(x_), yo_); @@ -187,7 +188,7 @@ void RowPainter::paintInset(pos_type con } -void RowPainter::paintHebrewComposeChar(pos_type & vpos) +void RowPainter::paintHebrewComposeChar(pos_type & vpos, LyXFont const & font) { pos_type pos = text_.bidi.vis2log(vpos); @@ -198,7 +199,6 @@ void RowPainter::paintHebrewComposeChar( str += c; ++vpos; - LyXFont const & font = getFont(pos); int const width = font_metrics::width(c, font); int dx = 0; @@ -221,7 +221,7 @@ void RowPainter::paintHebrewComposeChar( } -void RowPainter::paintArabicComposeChar(pos_type & vpos) +void RowPainter::paintArabicComposeChar(pos_type & vpos, LyXFont const & font) { pos_type pos = text_.bidi.vis2log(vpos); string str; @@ -232,7 +232,6 @@ void RowPainter::paintArabicComposeChar( str += c; ++vpos; - LyXFont const & font = getFont(pos); int const width = font_metrics::width(c, font); int dx = 0; @@ -251,34 +250,36 @@ void RowPainter::paintArabicComposeChar( } -void RowPainter::paintChars(pos_type & vpos, bool hebrew, bool arabic) +void RowPainter::paintChars(pos_type & vpos, LyXFont font, + bool hebrew, bool arabic) { pos_type pos = text_.bidi.vis2log(vpos); pos_type const end = row_.endpos(); - LyXFont orig_font = getFont(pos); + std::pair<lyx::pos_type, lyx::pos_type> const font_span + = par_.getFontSpan(pos); + string str; + + const Change::Type prev_change = par_.lookupChange(pos); // first character - string str; str += par_.getChar(pos); if (arabic) { unsigned char c = str[0]; str[0] = par_.transformChar(c, pos); } - bool prev_struckout = isDeletedText(par_, pos); - bool prev_newtext = isInsertedText(par_, pos); - // collect as much similar chars as we can - for (++vpos; vpos < end && (pos = text_.bidi.vis2log(vpos)) >= 0; ++vpos) { - char c = par_.getChar(pos); - - if (!IsPrintableNonspace(c)) + for (++vpos ; vpos < end ; ++vpos) { + pos = text_.bidi.vis2log(vpos); + if (pos < font_span.first || pos > font_span.second) break; - if (prev_struckout != isDeletedText(par_, pos)) + if (prev_change != par_.lookupChange(pos)) break; - if (prev_newtext != isInsertedText(par_, pos)) + char c = par_.getChar(pos); + + if (!IsPrintableNonspace(c)) break; if (arabic && Encodings::IsComposeChar_arabic(c)) @@ -287,34 +288,31 @@ void RowPainter::paintChars(pos_type & v if (hebrew && Encodings::IsComposeChar_hebrew(c)) break; - if (orig_font != getFont(pos)) - break; - if (arabic) c = par_.transformChar(c, pos); str += c; } - if (prev_struckout) - orig_font.setColor(LColor::strikeout); - else if (prev_newtext) - orig_font.setColor(LColor::newtext); + if (prev_change == Change::DELETED) + font.setColor(LColor::strikeout); + else if (prev_change == Change::INSERTED) + font.setColor(LColor::newtext); // Draw text and set the new x position //lyxerr << "paint row: yo_ " << yo_ << "\n"; - pain_.text(int(x_), yo_, str, orig_font); - x_ += font_metrics::width(str, orig_font); + pain_.text(int(x_), yo_, str, font); + x_ += font_metrics::width(str, font); } -void RowPainter::paintForeignMark(double orig_x, LyXFont const & orig_font) +void RowPainter::paintForeignMark(double orig_x, LyXFont const & font) { if (!lyxrc.mark_foreign_language) return; - if (orig_font.language() == latex_language) + if (font.language() == latex_language) return; - if (orig_font.language() == bv_.buffer()->params().language) + if (font.language() == bv_.buffer()->params().language) return; int const y = yo_ + 1; @@ -333,7 +331,7 @@ void RowPainter::paintFromPos(pos_type & char const c = par_.getChar(pos); if (c == Paragraph::META_INSET) { - paintInset(pos); + paintInset(pos, orig_font); ++vpos; paintForeignMark(orig_x, orig_font); return; @@ -352,11 +350,11 @@ void RowPainter::paintFromPos(pos_type & if ((!hebrew && !arabic) || (hebrew && !Encodings::IsComposeChar_hebrew(c)) || (arabic && !Encodings::IsComposeChar_arabic(c))) { - paintChars(vpos, hebrew, arabic); + paintChars(vpos, orig_font, hebrew, arabic); } else if (hebrew) { - paintHebrewComposeChar(vpos); + paintHebrewComposeChar(vpos, orig_font); } else if (arabic) { - paintArabicComposeChar(vpos); + paintArabicComposeChar(vpos, orig_font); } paintForeignMark(orig_x, orig_font);
Index: src/frontends/qt2/ChangeLog =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/ChangeLog,v retrieving revision 1.790 diff -u -p -r1.790 ChangeLog --- src/frontends/qt2/ChangeLog 6 Jun 2005 12:34:28 -0000 1.790 +++ src/frontends/qt2/ChangeLog 8 Jun 2005 13:27:52 -0000 @@ -1,3 +1,9 @@ +2005-04-04 Jean-Marc Lasgouttes <[EMAIL PROTECTED]> + + * qfont_loader.h: + * qfont_loader.C (charwidth): do no do font width caching with + Qt >= 3.1.0. + 2005-06-06 Lars Gullik Bjonnes <[EMAIL PROTECTED]> (Committed Martin Vermeer <[EMAIL PROTECTED]>) Index: src/frontends/qt2/qfont_loader.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/qfont_loader.C,v retrieving revision 1.53 diff -u -p -r1.53 qfont_loader.C --- src/frontends/qt2/qfont_loader.C 27 Jan 2005 21:05:36 -0000 1.53 +++ src/frontends/qt2/qfont_loader.C 8 Jun 2005 13:27:52 -0000 @@ -375,6 +375,9 @@ qfont_loader::font_info * qfont_loader:: int qfont_loader::charwidth(LyXFont const & f, Uchar val) { +// Starting with version 3.1.0, Qt/X11 does its own caching of +// character width, so it is not necessary to provide ours. +#if QT_VERSION < 0x030100 font_info * fi = getfontinfo(f); font_info::WidthCache::const_iterator cit = fi->widthcache.find(val); @@ -384,6 +387,9 @@ int qfont_loader::charwidth(LyXFont cons int const w = fi->metrics.width(QChar(val)); fi->widthcache[val] = w; return w; +#else + return getfontinfo(f)->metrics.width(QChar(val)); +#endif } Index: src/frontends/qt2/qfont_loader.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/qt2/qfont_loader.h,v retrieving revision 1.15 diff -u -p -r1.15 qfont_loader.h --- src/frontends/qt2/qfont_loader.h 19 Jan 2005 15:03:30 -0000 1.15 +++ src/frontends/qt2/qfont_loader.h 8 Jun 2005 13:27:52 -0000 @@ -13,7 +13,9 @@ #define QFONTLOADER_H +#if QT_VERSION < 0x030100 #include <map> +#endif #include "encoding.h" #include "lyxfont.h" @@ -65,9 +67,11 @@ private: /// metrics on the font QFontMetrics metrics; +#if QT_VERSION < 0x030100 typedef std::map<Uchar, int> WidthCache; /// cache of char widths WidthCache widthcache; +#endif }; /// get font info (font + metrics) for the given LyX font. Does not fail.