[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