[prev in list] [next in list] [prev in thread] [next in thread]
List: koffice-devel
Subject: redraw pixmap caching v3, and a question
From: Jaymz Julian <jaymz () dspaudio ! com>
Date: 2002-08-10 16:52:01
[Download RAW message or body]
hi again guys!
so, people managed to break my last two methods of redraw caching, which
is probably beacuase they were primitive and proof of concept at best
etc. So, today I rewrote it using linked lists instead of fixed arrays,
and tried to get the advantages of both of the algorythms into one (as I
mentioend with my last patch, one was fast at the end of paragraphs, and
one was fast at the start of paragtraphs :-p)
So, this more "sane" version of the code works in every situation that
I've thrown at it, althoguh I did manage to get into one very long loop,
which I havn't managed to duplicate yet (anyone have any
ideas? ^_^). This is the version which i think should be fixable into
something usable.
I have a couple of questions:
a) I'm still not checking the selection buffer, because I havn't
worked out a way to do that compare quickly yet - if anyone knows off the
top of their head, that'd save me much time and make me happy ^_
b) you'll notice that the background is always set to Qt::white,
and not the actyal background color - this is becasue, it etiher came out
corrupted, or black when I did (look in KoTextParag.cc line #571,. and
comment that out to make it use your system background color. I left out
the printer check to, but that's a one liner, and I wanted to fix this
first)
btw, this version of the routine also increases the performance of kword
in zoom mode by a factor of around 8:1-10:1 on my p3-500 ^_^ (when zoomed
to 500%), so perhaps if someone wants to test it, that's the way to do it
(zoomed kword is also sluggish on my p3 system)
- Jaymz
--
Jaymz Julian aka A Life in Hell
Coder, Visionary, Fat Ass.
And remember, it's spelt '31337', but pronounced 'lame'!
["kword-redraw-cache-v3.patch" (TEXT/PLAIN)]
Index: kotextparag.cc
===================================================================
RCS file: /home/kde/koffice/lib/kotext/kotextparag.cc,v
retrieving revision 1.98
diff -u -3 -p -r1.98 kotextparag.cc
--- kotextparag.cc 7 Aug 2002 16:56:33 -0000 1.98
+++ kotextparag.cc 10 Aug 2002 16:27:01 -0000
@@ -26,6 +26,7 @@
#include <klocale.h>
#include <assert.h>
#include <kdebug.h>
+#include <stdlib.h>
/////
@@ -425,6 +426,8 @@ void KoTextParag::paint( QPainter &paint
}
}
+#define CACHE_THRESHOLD 10
+#define MAX_ITERATIONS 4
// Called by KoTextParag::paintDefault
// Draw a set of characters with the same formattings.
// Reimplemented here to convert coordinates first, and call @ref \
drawFormattingChars. @@ -449,14 +452,13 @@ void KoTextParag::drawParagString( QPain
int h_pix = zh->layoutUnitToPixelY( lastY, h );
//kdDebug(32500) << "KoTextParag::drawParagString h(LU)=" << h << " lastY(LU)=" \
<< lastY
// << " h(PIX)=" << h_pix << " lastY(PIX)=" << lastY_pix << endl;
-
- if ( lastFormat->textBackgroundColor().isValid() )
- painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, \
lastFormat->textBackgroundColor() );
-
- // don't want to draw line breaks but want them when drawing formatting chars
+
+ // metric calculation stuff moved from below
int draw_len = len;
int draw_startX = startX;
int draw_bw = bw_pix;
+
+ // don't want to draw line breaks but want them when drawing formatting chars
if ( at( start + len - 1 )->c == '\n' )
{
draw_len--;
@@ -465,22 +467,159 @@ void KoTextParag::drawParagString( QPain
draw_startX = at( start + draw_len - 1 )->x;
}
int draw_startX_pix = zh->layoutUnitToPixelX( draw_startX ) /* + at( rightToLeft \
? start+draw_len-1 : start )->pixelxadj*/; +
+
+ // cache handing stuff
+ // FIXME: make this use a linked list of some description, for fast insertion \
and iterating + bool dataFound=false;
+ int numIterations=0;
+
+ // move this into cacheInfo struct
+ static int totalIterations=0;
+
+ QString cacheString=s.mid(start, len);
+ //kdDebug() << "cacheString: " << cacheString << "\n";
+// kdDebug() << lastResult << "\n";
- drawParagStringInternal( painter, s, start, draw_len, draw_startX_pix,
- lastY_pix, baseLine_pix,
- draw_bw,
- h_pix, drawSelections, lastFormat, i, selectionStarts,
- selectionEnds, cg, rightToLeft, zh );
-
- if ( !textDocument()->drawingShadow() && textDocument()->drawFormattingChars() )
- {
- drawFormattingChars( painter, s, start, len,
- startX, lastY, baseLine, h,
- startX_pix, lastY_pix, baseLine_pix, bw_pix, h_pix,
- drawSelections,
- lastFormat, i, selectionStarts,
- selectionEnds, cg, rightToLeft );
+ paragCacheList::iterator myCacheData;
+
+ if(workingSection == 0)
+ {
+ myCacheData=cacheList.begin();
+ lastCache=cacheList.begin();
+ }
+ else
+ {
+ myCacheData=lastCache;
+ }
+
+// for(myCacheData=cacheList.begin(); myCacheData != cacheList.end() ; \
myCacheData++ ) + for(myCacheData=lastCache; myCacheData != cacheList.end() ; \
myCacheData++ ) + {
+ if( (*myCacheData).contents == cacheString &&
+ (*myCacheData).paintHeight == h_pix &&
+ (*myCacheData).paintWidth == draw_bw &&
+ (*myCacheData).drawSelections == drawSelections &&
+ (*myCacheData).rightToLeft == rightToLeft )
+ {
+ dataFound=true;
+ goto jumpOut;
+ }
+ if((*myCacheData).lastUse > CACHE_THRESHOLD)
+ {
+ myCacheData=cacheList.erase(myCacheData);
+ myCacheData--;
+ }
+ numIterations++;
+ }
+
+ // cut and paste from above to complete the loop - should I use a #define or an
+ // inline function here?
+ for(myCacheData=cacheList.begin(); myCacheData != lastCache ; myCacheData++ )
+ {
+ if( (*myCacheData).contents == cacheString &&
+ (*myCacheData).paintHeight == h_pix &&
+ (*myCacheData).paintWidth == draw_bw &&
+ (*myCacheData).drawSelections == drawSelections &&
+ (*myCacheData).rightToLeft == rightToLeft )
+ {
+ dataFound=true;
+ goto jumpOut;
+ }
+ // garbage collect
+ if((*myCacheData).lastUse > CACHE_THRESHOLD)
+ {
+ myCacheData=cacheList.erase(myCacheData);
+ if(myCacheData != cacheList.begin())
+ myCacheData--;
+ }
+ numIterations++;
+ }
+jumpOut:
+ totalIterations+=numIterations;
+// if(numIterations>MAX_ITERATIONS)
+// {
+// kdDebug() << "iterations: " << numIterations << " ::: " << \
totalIterations << " ::: " << cacheList.count() << "\n"; +// }
+
+ // if no data was found, insert a new node into the list
+ // FIXME: for now, we're actully appending the node....
+ if(!dataFound)
+ {
+ paragCacheInfo temp;
+ //myCacheData=cacheList.append(temp);
+ if(cacheList.count() > 0)
+ {
+ lastCache++;
+ myCacheData=cacheList.insert(lastCache, temp);
+ }
+ else
+ myCacheData=cacheList.append(temp);
+
+ //kdDebug() << "Cache miss: section " << workingSection << "\n";
+
+ QPixmap *cachePixmap=new QPixmap(bw_pix, h_pix);
+ QPainter *myPainter=new QPainter(cachePixmap);
+ myPainter->setBackgroundMode(QPainter::TransparentMode);
+
+ if ( lastFormat->textBackgroundColor().isValid() )
+ //painter.fillRect( startX_pix, lastY_pix, bw_pix, h_pix, \
lastFormat->textBackgroundColor() ); + cachePixmap->fill( \
lastFormat->textBackgroundColor() ); + else
+ {
+ QColor fillColor = backgroundColor() ? *backgroundColor() : \
QColor(QColorGroup::Base); + fillColor=Qt::white;
+ // transparent shite
+ //cachePixmap->fill(Qt::color0);
+ cachePixmap->fill(fillColor);
+ }
+
+ // call the actual drawing functions
+ drawParagStringInternal( *myPainter, s, start, draw_len, 0,
+ 0, baseLine_pix,
+ draw_bw,
+ h_pix, drawSelections, lastFormat, i, \
selectionStarts, + selectionEnds, cg, \
rightToLeft, zh ); +
+ if ( !textDocument()->drawingShadow() && \
textDocument()->drawFormattingChars() ) + {
+ drawFormattingChars( painter, s, start, len,
+ startX, lastY, baseLine, h,
+ 0, 0, baseLine_pix, bw_pix, h_pix,
+ drawSelections,
+ lastFormat, i, selectionStarts,
+ selectionEnds, cg, rightToLeft );
+ }
+
+ // clearn up and draw
+ myPainter->end();
+ delete myPainter;
+ painter.drawPixmap(draw_startX_pix, lastY_pix, *cachePixmap);
+
+ // update the cache
+ (*myCacheData).cachedPixmap=cachePixmap;
+ (*myCacheData).paintHeight=h_pix;
+ (*myCacheData).paintWidth=draw_bw;
+ (*myCacheData).contents=cacheString;
+ (*myCacheData).rightToLeft=rightToLeft;
+ (*myCacheData).drawSelections=drawSelections;
+ (*myCacheData).lastUse=0;
}
+ else
+ {
+ // unacceptably expensive cache search? copy it where we'll find it!
+ if(numIterations>MAX_ITERATIONS)
+ {
+ paragCacheInfo temp;
+ lastCache++;
+ myCacheData=cacheList.insert(lastCache, *myCacheData);
+ }
+ (*myCacheData).lastUse=0;
+ painter.drawPixmap(draw_startX_pix, lastY_pix, \
*((*myCacheData).cachedPixmap)); + }
+
+ // for the iteration stuffs
+ lastCache=myCacheData;
}
// Copied from the original KoTextParag
Index: qrichtext.cpp
===================================================================
RCS file: /home/kde/koffice/lib/kotext/qrichtext.cpp,v
retrieving revision 1.81
diff -u -3 -p -r1.81 qrichtext.cpp
--- qrichtext.cpp 7 Aug 2002 16:08:10 -0000 1.81
+++ qrichtext.cpp 10 Aug 2002 16:27:09 -0000
@@ -3758,6 +3758,14 @@ KoTextParag::~KoTextParag()
{
emit document()->paragraphDeleted( this );
}
+
+ // iterate through the cache list and delete the pixmaps, since they aren't \
cleaned up automagically. + for(paragCacheList::iterator c=cacheList.begin(); c != \
cacheList.end(); c++) + if((*c).cachedPixmap != NULL)
+ {
+ delete (*c).cachedPixmap;
+ (*c).cachedPixmap=NULL;
+ }
//kdDebug(32500) << "KoTextParag::~KoTextParag " << this << endl;
////
}
@@ -4258,6 +4266,11 @@ void KoTextParag::paintDefault( QPainter
QString qstr = str->toString();
+ // reset the working section
+ workingSection=0;
+ for(paragCacheList::iterator c=cacheList.begin(); c != cacheList.end(); c++)
+ (*c).lastUse++;
+
const int nSels = doc ? doc->numSelections() : 1;
QMemArray<int> selectionStarts( nSels );
QMemArray<int> selectionEnds( nSels );
@@ -4349,10 +4362,12 @@ void KoTextParag::paintDefault( QPainter
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 ); +
+ drawParagString( painter, qstr, paintStart, paintEnd - paintStart \
+ 1, startX, lastY, + lastBaseLine, bw, lasth, \
drawSelections, + lastFormat, i, selectionStarts, \
selectionEnds, cg, lastDirection ); +
+ workingSection++;
}
if ( !chr->isCustom() ) {
paintStart = i;
@@ -4407,9 +4422,11 @@ void KoTextParag::paintDefault( QPainter
}
}
int x = startX;
+ //kdDebug() << "Drawing: " << "end" << " paintStart: " << paintStart << \
"\n";
drawParagString( painter, qstr, paintStart, paintEnd-paintStart+1, x, lastY,
lastBaseLine, bw, h, drawSelections,
lastFormat, i, selectionStarts, selectionEnds, cg, \
lastDirection ); + workingSection++;
}
// if we should draw a cursor, draw it now
Index: qrichtext_p.h
===================================================================
RCS file: /home/kde/koffice/lib/kotext/qrichtext_p.h,v
retrieving revision 1.38
diff -u -3 -p -r1.38 qrichtext_p.h
--- qrichtext_p.h 30 Jul 2002 11:41:28 -0000 1.38
+++ qrichtext_p.h 10 Aug 2002 16:27:09 -0000
@@ -108,6 +108,19 @@ class KoTextDocCommand;
#include "korichtext.h"
////
+typedef struct
+{
+ int paintWidth;
+ int paintHeight;
+ bool drawSelections;
+ bool rightToLeft;
+ int lastUse;
+ QString contents;
+ QPixmap *cachedPixmap;
+} paragCacheInfo;
+
+typedef QValueList<paragCacheInfo> paragCacheList;
+
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class Q_EXPORT KoTextStringChar
@@ -1398,7 +1411,11 @@ private:
KoTextDocCommandHistory *commandHistory;
int list_val;
QColor *bgcol;
-
+
+ // info for redraw cache
+ paragCacheList cacheList;
+ paragCacheList::iterator lastCache;
+ int workingSection;
};
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_______________________________________________
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