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.

Reply via email to