[prev in list] [next in list] [prev in thread] [next in thread] 

List:       koffice-devel
Subject:    kword/kpresenter 1.2.1 linecache stuff
From:       Jaymz Julian <jaymz () dspaudio ! com>
Date:       2003-03-29 2:34:55
[Download RAW message or body]

so, the people i laughingly call my colleguges decided they wanted to move
to v1.2.1, meaning that they expected me to magically pull performance out
of the ether again.

you have no interest in this, it's only here for curiosity.  for those who
remember the stuff i was hacking on around 1.2 release, which is none of
you :), this patch caches redraws for each line in a bunch of
QPictures.  ythis is not the ideal soution, but it's one i was able to
come up with without fully understanding kword and rewriting large chunks
:)

it also makes zoomed mode paletable on my p3-500 (tho i think that's
related to my xserver, it's xinerama, which happens to be, on a p3-500,
slow as fucking molasses).

	- jj

-- 
Jaymz Julian aka A Life in Hell
Coder, Visionary, Fat Ass.
My opinions may have changed, but not the fact that I am right.

["linecache-1.2.1.diff" (TEXT/PLAIN)]

diff -ur /bigish/koffice/koffice-1.2.1.orig/lib/kotext/qrichtext.cpp \
                kotext/qrichtext.cpp
--- /bigish/koffice/koffice-1.2.1.orig/lib/kotext/qrichtext.cpp	2002-10-21 \
                00:20:33.000000000 +1000
+++ kotext/qrichtext.cpp	2003-03-29 12:59:20.000000000 +1100
@@ -3693,6 +3693,10 @@
     {
         emit document()->paragraphDeleted( this );
     }
+
+    for(int i=0;i<(int)cacheData.size();i++)
+	    if(!cacheData[i].cachedPicture)
+		    delete cacheData[i].cachedPicture;
     //kdDebug(32500) << "KoTextParag::~KoTextParag " << this << endl;
     ////
 }
@@ -4203,7 +4207,6 @@
     // This is necessary with the current code, but in theory it shouldn't
     // be necessary, if Xft really gives us fully proportionnal chars....
 #define CHECK_PIXELXADJ
-
 #ifdef CHECK_PIXELXADJ
     int lastXAdj = 0;
 #endif
@@ -4242,140 +4245,231 @@
     int paintEnd = -1;
     int lasth = 0;
     int i = 0;
-    if ( m_lineChanged > 0 )
+
+    // Draw them lines!
+    line=m_lineChanged;
+    if(line<0) line=0;
+    int numLines=lines();
+    
+    for(;line<numLines;line++)
     {
-        //qDebug( "painting paragraph %p id:%d from line %d", (void*)this, \
                paragId(), m_lineChanged );
-        lineStartOfLine( m_lineChanged, &i );
-        line = m_lineChanged - 1; // ++ is the first thing that will happen in the \
                loop
-    }
-    //else
-    //    qDebug( "painting paragraph %p id:%d", (void*)this, paragId() );
-    int paintStart = i;
-    for ( ; i < length(); i++ ) {
-	chr = at( i );
-
-        cw = chr->width;
-
-	// init a new line
-	if ( chr->lineStart ) {
-	    ++line;
-	    lineInfo( line, cy, h, baseLine );
-	    lasth = h;
-	    if ( clipy != -1 && cy > clipy - r.y() + cliph ) // outside clip area, leave
-		break;
-	    if ( lastBaseLine == 0 )
-		lastBaseLine = baseLine;
-	}
+	// get the length of the line
+	int lineLen=0;
+	int cursorLine= -1;
+	if(cursor)
+		lineStartOfChar( cursor->index(), 0, &cursorLine );
+	else
+		cursorLine = -1;
 
-	// check for cursor mark
-	if ( cursor && this == cursor->parag() && i == cursor->index() ) {
-	    curx = cursor->x();
-	    curline = line;
-            KoTextStringChar *c = chr;
-            if ( i > 0 )
-                --c;
-            curh = c->height();
-            cury = cy + baseLine - c->ascent();
-	}
-
-	// first time - start again...
-	if ( !lastFormat || lastY == -1 ) {
-	    lastFormat = chr->format();
-	    lastY = cy;
-	    startX = chr->x;
-	    paintEnd = i;
-	    bw = cw;
-	    if ( !chr->isCustom() )
-		continue;
-	}
+	int nextLine;
+	int startOfLine;
+	lineStartOfLine(line, &startOfLine);
 
-	// check if selection state changed
-	bool selectionChange = FALSE;
-	if ( drawSelections ) {
-	    for ( int j = 0; j < nSels; ++j ) {
-		selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i;
-		if ( selectionChange )
-		    break;
-	    }
-	}
+	if(line==(numLines-1))
+                nextLine=length();
+        else
+                lineStartOfLine(line+1, &nextLine);
+	lineLen=nextLine-startOfLine;
+	
+	// init this line
+	lineInfo( line, cy, h, baseLine );
+	lasth = h;
+	if ( clipy != -1 && cy > clipy - r.y() + cliph ) // outside clip area, leave
+	    break;
+	if ( lastBaseLine == 0 )
+	lastBaseLine = baseLine;
 
-	//if something (format, etc.) changed, draw what we have so far
-	if ( ( ( alignment() & Qt::AlignJustify ) == Qt::AlignJustify && paintEnd != -1 && \
                at(paintEnd)->c.isSpace() ) ||
-#ifdef CHECK_PIXELXADJ
-               lastXAdj != chr->pixelxadj ||
-#endif
-	       lastDirection != (bool)chr->rightToLeft ||
-	       chr->startOfRun ||
-	       lastY != cy || chr->format() != lastFormat ||
-	       ( paintEnd != -1 && at( paintEnd )->c =='\t' ) || chr->c == '\t' ||
-	       ( paintEnd != -1 && at( paintEnd )->c.unicode() == 0xad ) || \
                chr->c.unicode() == 0xad ||
-	       selectionChange || chr->isCustom() ) {
-
-            if ( paintStart <= paintEnd ) {
-		if ( chr->isCustom() && chr->customItem()->placement() == \
                KoTextCustomItem::PlaceInline ) {
-		    qstr.replace(i,1," ");
-		}
-                // QRT hack removed from this place, it broke justified spaces
-		drawParagString( painter, qstr, paintStart, paintEnd - paintStart + 1, startX, \
                lastY,
-				 lastBaseLine, bw, lasth, drawSelections,
-				 lastFormat, i, selectionStarts, selectionEnds, cg, lastDirection );
-	    }
-	    if ( !chr->isCustom() ) {
-		paintStart = i;
-		paintEnd = i;
+    	// initialise the line
+	int paintStart = startOfLine;
+	paintEnd = startOfLine;
+	lastY = cy;
+	chr = at(startOfLine);
+	startX=chr->x;
+	bw=cw=chr->width;
+
+	// only reset lastFormat if it wasn't set before!
+	if(!lastFormat)
 		lastFormat = chr->format();
-		lastY = cy;
-		startX = chr->x;
-		bw = cw;
-	    } else {
-		if ( chr->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
-                    chr->customItem()->draw( &painter, chr->x, cy + baseLine - \
                chr->customItem()->ascent(), clipx - r.x(), clipy - r.y(), clipw, \
                cliph, cg,
-					     drawSelections && nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] \
>                 i );
-		    paintStart = i+1;
-		    paintEnd = -1;
-		    lastFormat = chr->format();
-		    lastY = cy;
-		    startX = chr->x + chr->width;
-		    bw = 0;
-		} else {
-		    chr->customItem()->resize( pntr, chr->customItem()->width );
-		    paintStart = i+1;
-		    paintEnd = -1;
-		    lastFormat = chr->format();
-		    lastY = cy;
-		    startX = chr->x + chr->width;
-		    bw = 0;
-		}
-	    }
-	} else {
-	    if( chr->rightToLeft ) {
-		startX = chr->x;
-	    }
-	    paintEnd = i;
-	    bw += cw;
+
+	// make sure that we can fit this line
+	if(cacheData.size()<=line)
+	{
+		cacheData.resize(line+1);
+		cacheData[line].cachedPicture=NULL;
+		cacheData[line].lastFormat=NULL;
+	}
+
+	// check if we need a redraw on this line or not
+	bool needRedraw;
+	if(cacheData[line].cachedPicture==NULL ||
+	   cacheData[line].clipx != clipx ||
+	   cacheData[line].clipy != clipy ||
+	   cacheData[line].clipw != clipw ||
+	   cacheData[line].cliph != cliph ||
+	   cacheData[line].cy != cy ||
+	   cacheData[line].h != h ||
+	   cacheData[line].drawSelections != drawSelections ||
+	   cacheData[line].rightToLeft != lastDirection ||
+	   cacheData[line].contents != qstr.mid(startOfLine, lineLen) ||
+	   cacheData[line].lastFormat != lastFormat ||
+	   cursorLine == line)
+		needRedraw=true;
+	else
+	{
+		needRedraw=false;
+		// check selections - do this here, because it takes some CPU
+		if(drawSelections)
+			if((int)cacheData[line].selections.size()==lineLen)
+			{
+				for(i=0;i<lineLen;i++)
+					if(cacheData[line].selections[i]!=hasSelection(i+startOfLine))
+						needRedraw=true;
+			}
+			else
+			{
+				// This condition should never happen, but test it just incase I'm an idiot ^_^
+				needRedraw=true;
+			}
+
 	}
-	lastBaseLine = baseLine;
-	lasth = h;
-	lastDirection = chr->rightToLeft;
-#ifdef CHECK_PIXELXADJ
-        lastXAdj = chr->pixelxadj;
-#endif
-    }
 
-    // if we are through the parag, but still have some stuff left to draw, draw it \
                now
-    if ( paintStart <= paintEnd ) {
-	bool selectionChange = FALSE;
-	if ( drawSelections ) {
-	    for ( int j = 0; j < nSels; ++j ) {
-		selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i;
-		if ( selectionChange )
-		    break;
-	    }
+	// FIXME: mass copy from below, do fixy stuff	
+	if(needRedraw)
+	{
+		//kdDebug() << "Line #" << line << "\n";
+		// update the cache *first*, before the data is modified!
+		cacheData[line].clipx=clipx;
+		cacheData[line].clipy=clipy;
+		cacheData[line].cliph=cliph;
+		cacheData[line].clipw=clipw;
+		cacheData[line].cy=cy;
+		cacheData[line].h=h;
+		cacheData[line].drawSelections=drawSelections;
+		cacheData[line].rightToLeft=lastDirection;
+		cacheData[line].contents=qstr.mid(startOfLine, lineLen);
+		cacheData[line].lastFormat=lastFormat;
+		
+		if(drawSelections)
+		{
+			cacheData[line].selections.resize(lineLen);
+			for(i=0;i<lineLen;i++)
+				cacheData[line].selections[i]=hasSelection(i+startOfLine);
+		}
+
+		// allocate
+		QPicture *myPicture=new QPicture();
+		QPainter myPainter(myPicture);
+
+		// draw the line
+		for(i=startOfLine;i<nextLine;i++)
+		{
+			chr = at( i );
+		        cw = chr->width;
+			// check for cursor mark
+			if ( cursor && this == cursor->parag() && i == cursor->index() ) {
+			    curx = cursor->x();
+			    curline = line;
+		            KoTextStringChar *c = chr;
+		            if ( i > 0 )
+		                --c;
+		            curh = c->height();
+		            cury = cy + baseLine - c->ascent();
+			}
+			// test for end of line
+			bool endOfLine=false;
+			if(i==((startOfLine+lineLen)-1))
+				endOfLine=true;
+			// check if selection state changed
+			bool selectionChange = FALSE;
+			if ( drawSelections ) {
+			    for ( int j = 0; j < nSels; ++j ) {
+				selectionChange = selectionStarts[ j ] == i || selectionEnds[ j ] == i;
+				if ( selectionChange )
+				    break;
+			    }
+			}
+			//if something (format, etc.) changed, draw what we have so far
+			// FIXME: clean this up to fit into the new model
+			if ( ( (alignment() & Qt::AlignJustify) == Qt::AlignJustify && paintEnd != -1 &&  \
at(paintEnd)->c.isSpace() ) || +		#ifdef CHECK_PIXELXADJ
+		            lastXAdj != chr->pixelxadj ||
+		#endif
+			    endOfLine ||
+			    lastDirection != (bool)chr->rightToLeft ||
+			    chr->startOfRun ||
+			    lastY != cy || chr->format() != lastFormat ||
+			    ( paintEnd != -1 && at( paintEnd )->c =='\t' ) || chr->c == '\t' ||
+			    ( paintEnd != -1 && at( paintEnd )->c.unicode() == 0xad ) || chr->c.unicode() \
== 0xad || +			    selectionChange || 
+			    chr->isCustom() 
+			   ) 
+			   {
+		
+			   if ( paintStart <= paintEnd ) {
+				if ( chr->isCustom() && chr->customItem()->placement() == \
KoTextCustomItem::PlaceInline ) { +				    qstr.replace(i,1," ");
+				}
+	
+	  		    drawParagString( myPainter, qstr, paintStart, paintEnd - paintStart + 1, \
startX, lastY, +					 lastBaseLine, bw, lasth, drawSelections,
+					 lastFormat, i, selectionStarts, selectionEnds, cg, lastDirection );
+			    }
+			    if ( !chr->isCustom() ) {
+				paintStart = i;
+				paintEnd = i;
+				lastFormat = chr->format();
+				lastY = cy;
+				startX = chr->x;
+				bw = cw;
+			    } else {
+				if ( chr->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
+		       	            chr->customItem()->draw( &myPainter, chr->x, cy + baseLine - \
chr->customItem()->ascent(), clipx - r.x(), clipy - r.y(), clipw, cliph, cg, +							 \
drawSelections && nSels && selectionStarts[ 0 ] <= i && selectionEnds[ 0 ] > i ); \
+				    paintStart = i+1; +				    paintEnd = -1;
+				    lastFormat = chr->format();
+				    lastY = cy;
+				    startX = chr->x + chr->width;
+				    bw = 0;
+				} else {
+				    chr->customItem()->resize( pntr, chr->customItem()->width );
+				    paintStart = i+1;
+				    paintEnd = -1;
+				    lastFormat = chr->format();
+				    lastY = cy;
+				    startX = chr->x + chr->width;
+				    bw = 0;
+				}
+			    }
+			} else {
+			    if( chr->rightToLeft ) {
+				startX = chr->x;
+			    }
+			    paintEnd = i;
+			    bw += cw;
+			}
+			lastBaseLine = baseLine;
+			lasth = h;
+			lastDirection = chr->rightToLeft;
+		#ifdef CHECK_PIXELXADJ
+		        lastXAdj = chr->pixelxadj;
+		#endif
+		} // end of charecter loop
+
+		// draw it, bitch!
+		myPainter.end();
+		painter.drawPicture(*myPicture);
+
+		// free any picture that we had from before
+		if(!cacheData[line].cachedPicture)
+			free(cacheData[line].cachedPicture);
+	
+		cacheData[line].cachedPicture=myPicture;
+	}
+	else
+	{
+		painter.drawPicture(*(cacheData[line].cachedPicture));
 	}
-	int x = startX;
-	drawParagString( painter, qstr, paintStart, paintEnd-paintStart+1, x, lastY,
-			 lastBaseLine, bw, h, drawSelections,
-			 lastFormat, i, selectionStarts, selectionEnds, cg, lastDirection );
     }
 
     // if we should draw a cursor, draw it now
diff -ur /bigish/koffice/koffice-1.2.1.orig/lib/kotext/qrichtext_p.h \
                kotext/qrichtext_p.h
--- /bigish/koffice/koffice-1.2.1.orig/lib/kotext/qrichtext_p.h	2002-10-19 \
                02:59:09.000000000 +1000
+++ kotext/qrichtext_p.h	2003-03-27 02:33:52.000000000 +1100
@@ -68,6 +68,7 @@
 #include "qcolor.h"
 #include "qsize.h"
 #include "qvaluelist.h"
+#include "qvaluevector.h"
 #include "qvaluestack.h"
 #include "qobject.h"
 #include "qdict.h"
@@ -81,6 +82,7 @@
 #include <limits.h>
 #include "qcomplextext_p.h"
 #include "qapplication.h"
+#include "qpicture.h"
 #endif // QT_H
 
 class KoTextParag;
@@ -108,6 +110,34 @@
 #include "korichtext.h"
 ////
 
+typedef struct
+{
+   // clipping
+   int clipx;
+   int clipy;
+   int clipw;
+   int cliph;
+
+   // line height and positions
+   int cy;
+   int h;
+
+   // line flags
+   bool drawSelections;
+   bool rightToLeft;
+
+   QMemArray<int> selections;
+
+   // line contents and formatting
+   QString contents;
+   KoTextFormat *lastFormat;
+
+   // and finally the picture
+   QPicture *cachedPicture;
+} paragCacheInfo;
+
+typedef QValueVector<paragCacheInfo> paragCacheVector;
+
 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
 class Q_EXPORT KoTextStringChar
@@ -1401,6 +1431,9 @@
     KoTextDocCommandHistory *commandHistory;
     int list_val;
     QColor *bgcol;
+    
+    // info for redraw cache
+    paragCacheVector cacheData;
 };
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



_______________________________________________
koffice-devel mailing list
koffice-devel@mail.kde.org
http://mail.kde.org/mailman/listinfo/koffice-devel

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic