Incremental Repainting Patch

David Hyatt hyatt at apple.com
Sat Sep 27 15:15:34 CEST 2003


This code has landed in the Safari tree, with the 
INCREMENTAL_REPAINTING flag disabled.  Here are my list of known issues 
with the patch.  I am sure there are many more undiscovered bugs 
lurking, since this is a very scary change:

(1) List bullets on list items with an outside list-style-position 
don't repaint the bullet when repaint() is called.

(2) Page cache detaching is causing repaint()s to try to be scheduled.  
Crashes the browser.  These repaints aren't necessary.

(3) XUL box model needs some dynamic tests and to have repaint() code 
written inside layout().

(4) Go to: http://www.javascript-games.org/indexdyn.html?betaversion.  
Open up the Links window.  Scroll it.  As you drag the scroller, it 
stops responding.

(5) http://www.meyerweb.com/eric/css/edge/ has a repaint glitch.  A 
square sits behind the content.

(6) Tables need to repaint their positioned descendants in the layout() 
method.

(7) setNeedsLayout should dirty the normal flow parent for positioned 
elements that omit left/top and therefore need to calculate a normal 
flow position.

-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/ChangeLog,v
retrieving revision 1.2022
diff -u -p -r1.2022 ChangeLog
--- ChangeLog	2003/09/25 21:09:03	1.2022
+++ ChangeLog	2003/09/26 00:50:19
@@ -1,3 +1,85 @@
+2003-09-25  David Hyatt  <hyatt at apple.com>
+
+        * khtml/html/html_documentimpl.cpp:
+        (HTMLDocumentImpl::close):
+        * khtml/khtmlview.cpp:
+        (KHTMLView::KHTMLView):
+        * khtml/khtmlview.h:
+        * khtml/rendering/render_block.cpp:
+        * khtml/rendering/render_block.h:
+        * khtml/rendering/render_box.cpp:
+        (RenderBox::setStyle):
+        (RenderBox::setPixmap):
+        (RenderBox::getAbsoluteRepaintRect):
+        (RenderBox::computeAbsoluteRepaintRect):
+        (RenderBox::repaintIfMoved):
+        (RenderBox::calcAbsoluteHorizontal):
+        (RenderBox::calcAbsoluteVertical):
+        * khtml/rendering/render_box.h:
+        * khtml/rendering/render_canvas.cpp:
+        (RenderCanvas::layout):
+        (RenderCanvas::repaintViewRectangle):
+        (RenderCanvas::getAbsoluteRepaintRect):
+        (RenderCanvas::computeAbsoluteRepaintRect):
+        * khtml/rendering/render_canvas.h:
+        * khtml/rendering/render_container.cpp:
+        (RenderContainer::addChild):
+        (RenderContainer::removeChildNode):
+        (RenderContainer::removeChild):
+        (RenderContainer::appendChildNode):
+        (RenderContainer::insertChildNode):
+        * khtml/rendering/render_flexbox.cpp:
+        * khtml/rendering/render_flow.cpp:
+        (RenderFlow::getAbsoluteRepaintRect):
+        * khtml/rendering/render_flow.h:
+        * khtml/rendering/render_image.cpp:
+        (RenderImage::setPixmap):
+        (RenderImage::layout):
+        * khtml/rendering/render_inline.cpp:
+        (RenderInline::addChildToFlow):
+        * khtml/rendering/render_layer.cpp:
+        (RenderLayer::convertToLayerCoords):
+        * khtml/rendering/render_list.cpp:
+        (RenderListMarker::setPixmap):
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::RenderObject):
+        (RenderObject::setNeedsLayout):
+        (RenderObject::setChildNeedsLayout):
+        (RenderObject::markContainingBlocksForLayout):
+        (RenderObject::containingBlock):
+        (RenderObject::repaint):
+        (RenderObject::repaintRectangle):
+        (RenderObject::repaintAfterLayoutIfNeeded):
+        (RenderObject::repaintIfMoved):
+        (RenderObject::repaintPositionedAndFloatingDescendants):
+        (RenderObject::getAbsoluteRepaintRect):
+        (RenderObject::getAbsoluteRepaintRectIncludingDescendants):
+        (RenderObject::computeAbsoluteRepaintRect):
+        (RenderObject::setStyle):
+        (RenderObject::container):
+        (RenderObject::detach):
+        (RenderObject::scheduleRelayout):
+        * khtml/rendering/render_object.h:
+        * khtml/rendering/render_style.cpp:
+        (RenderStyle::diff):
+        * khtml/rendering/render_table.cpp:
+        (RenderTable::layout):
+        (RenderTableRow::getAbsoluteRepaintRect):
+        (RenderTableCell::computeAbsoluteRepaintRect):
+        * khtml/rendering/render_table.h:
+        * khtml/xml/dom_nodeimpl.cpp:
+        (NodeBaseImpl::insertBefore):
+        (NodeBaseImpl::replaceChild):
+        (NodeBaseImpl::appendChild):
+        * kwq/KWQKHTMLPart.mm:
+        (KWQKHTMLPart::clearTimers):
+        * kwq/KWQRenderTreeDebug.cpp:
+        (write):
+        (externalRepresentation):
+        * kwq/KWQRenderTreeDebug.h:
+

Index: khtml/khtmlview.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/khtmlview.cpp,v
retrieving revision 1.68
diff -u -p -r1.68 khtml/khtmlview.cpp
--- khtml/khtmlview.cpp	2003/08/22 00:45:21	1.68
+++ khtml/khtmlview.cpp	2003/09/26 00:50:19
@@ -96,8 +96,7 @@ public:
         paintBuffer=0;
         formCompletions=0;
         prevScrollbarVisible = true;
-	timerId = 0;
-        repaintTimerId = 0;
+	layoutTimerId = 0;
         complete = false;
         mousePressed = false;
 	tooltip = 0;
@@ -139,13 +138,10 @@ public:
 	clickCount = 0;
 	isDoubleClick = false;
 	scrollingSelf = false;
-	timerId = 0;
-        repaintTimerId = 0;
+	layoutTimerId = 0;
         complete = false;
         mousePressed = false;
-        firstRelayout = true;
         layoutSchedulingEnabled = true;
-        updateRect = QRect();
     }
 
     QPainter *tp;
@@ -174,14 +170,11 @@ public:
 
     int prevMouseX, prevMouseY;
     bool scrollingSelf;
-    int timerId;
+    int layoutTimerId;
 
-    int repaintTimerId;
     bool complete;
-    bool firstRelayout;
     bool layoutSchedulingEnabled;
     bool mousePressed;
-    QRect updateRect;
     KHTMLToolTip *tooltip;
 };
 
@@ -210,7 +203,9 @@ KHTMLView::KHTMLView( KHTMLPart *part, Q
 {
     m_medium = "screen";
 
+#ifndef INCREMENTAL_REPAINTING
     m_layoutObject = 0;
+#endif
     
     m_part = part;
 #if APPLE_CHANGES
@@ -416,35 +411,61 @@ void KHTMLView::adjustViewSize()
 
 void KHTMLView::layout()
 {
+    d->layoutSchedulingEnabled=false;
+    khtml::RenderCanvas* root = 0;
     if( m_part->xmlDocImpl() ) {
         DOM::DocumentImpl *document = m_part->xmlDocImpl();
 
-        khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
+        root = static_cast<khtml::RenderCanvas *>(document->renderer());
         if ( !root ) return;
 
-         if (document->isHTMLDocument()) {
+        if (document->isHTMLDocument()) {
              NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
              if(body && body->renderer() && body->id() == ID_FRAMESET) {
                  QScrollView::setVScrollBarMode(AlwaysOff);
                  QScrollView::setHScrollBarMode(AlwaysOff);
                  body->renderer()->setNeedsLayout(true);
              }
-         }
+        }
 
         _height = visibleHeight();
         _width = visibleWidth();
 
-        //QTime qt;
-        //qt.start();
-        root->setNeedsLayoutAndMinMaxRecalc();
-        // avoid recursing into relayouts because of scrollbar-flicker
-
         root->layout();
 
         //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
     } else {
         _width = visibleWidth();
     }
+
+    d->layoutSchedulingEnabled=true;
+    killTimer(d->layoutTimerId);
+    d->layoutTimerId = 0;
+
+    if (!root)
+        return;
+    
+#ifdef INCREMENTAL_REPAINTING
+    if (root->needsLayout()) {
+#else
+    // Do not allow a full layout if we had a clip object set.
+    if ( root->needsLayout() && !m_layoutObject) {
+#endif
+        //qDebug("needs layout, delaying repaint");
+        scheduleRelayout();
+        return;
+    }
+    resizeContents(root->docWidth(), root->docHeight());
+    setStaticBackground(d->useSlowRepaints);
+
+#ifndef INCREMENTAL_REPAINTING
+    if (m_layoutObject) {
+        m_layoutObject->repaint();
+        m_layoutObject = 0;
+    }
+    else
+        root->repaint();
+#endif
 }
 
 //
@@ -1535,152 +1556,61 @@ void KHTMLView::slotScrollBarMoved()
         d->scrollBarMoved = true;
 }
 
+void KHTMLView::repaintRectangle(const QRect& r, bool immediate)
+{
+#ifndef INCREMENTAL_REPAINTING
+    if (d->layoutTimerId) // Don't bother scheduling a repaint when a layout is pending.
+        return;
+#endif
+
+    updateContents(r, immediate);
+}
+
 void KHTMLView::timerEvent ( QTimerEvent *e )
 {
 //    kdDebug() << "timer event " << e->timerId() << endl;
-    if (e->timerId()==d->timerId)
-    {
-        d->firstRelayout = false;
-        killTimer(d->timerId);
-
-        d->layoutSchedulingEnabled=false;
+    if (e->timerId()==d->layoutTimerId)
         layout();
-        d->layoutSchedulingEnabled=true;
-
-        d->timerId = 0;
-
-        //scheduleRepaint(contentsX(),contentsY(),visibleWidth(),visibleHeight());
-        d->updateRect = QRect(contentsX(),contentsY(),visibleWidth(),visibleHeight());
-    }
-
-    if( m_part && m_part->xmlDocImpl() ) {
-        DOM::DocumentImpl *document = m_part->xmlDocImpl();
-        khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
-        if (root){
-            // Do not allow a full layout if we had a clip object set.
-            if ( root->needsLayout() && !m_layoutObject) {
-                killTimer(d->repaintTimerId);
-                d->repaintTimerId = 0;
-                //qDebug("needs layout, delaying repaint");
-                scheduleRelayout();
-                return;
-            }
-            resizeContents(root->docWidth(), root->docHeight());
-        }
-    }
-    setStaticBackground(d->useSlowRepaints);
-
-//        kdDebug() << "scheduled repaint "<< d->repaintTimerId  << endl;
-    // If we have an overflow:hidden object, we cache the current update rect and then
-    // clear the update rect, so that when we call repaint(), the union of the layout
-    // object's rect and the current update rect is just the layout object's' rect.
-    QRect oldUpdateRect = d->updateRect;
-    bool hasRepaintTimer = d->repaintTimerId;
-    if (m_layoutObject) {
-        d->updateRect = QRect();
-        m_layoutObject->repaint();
-    }
-    
-    // Now we paint.  This will be either a full paint or just the paint of a clipped
-    // object's area.
-    updateContents( d->updateRect );
-    killTimer(d->repaintTimerId);
-    d->repaintTimerId = 0;
-
-    if (m_layoutObject) {
-        // Restore the update rect, and if we had a repaint pending before the clipped
-        // object did its paint, go ahead and reschedule that paint to occur as soon
-        // as possible.
-        d->updateRect = oldUpdateRect;
-        if (hasRepaintTimer)
-            scheduleRepaint(d->updateRect.x(), d->updateRect.y(), d->updateRect.width(),
-                            d->updateRect.height());
-        m_layoutObject = 0;
-    }
 }
 
+#ifdef INCREMENTAL_REPAINTING
+void KHTMLView::scheduleRelayout()
+#else
 void KHTMLView::scheduleRelayout(khtml::RenderObject* clippedObj)
+#endif
 {
     if (!d->layoutSchedulingEnabled)
         return;
-        
+
+#ifndef INCREMENTAL_REPAINTING
     if (m_layoutObject != clippedObj)
-        m_layoutObject = 0;
+      m_layoutObject = 0;
+#endif
     
-    if (d->timerId)
+    if (d->layoutTimerId)
         return;
 
+#ifndef INCREMENTAL_REPAINTING
     m_layoutObject = clippedObj;
-    
+#endif
+
     bool parsing = false;
     if( m_part->xmlDocImpl() ) {
         parsing = m_part->xmlDocImpl()->parsing();
     }
 
-    d->timerId = startTimer( parsing ? 1000 : 0 );
+    d->layoutTimerId = startTimer( parsing ? 1000 : 0 );
 }
 
 void KHTMLView::unscheduleRelayout()
 {
-    if (!d->timerId)
+    if (!d->layoutTimerId)
         return;
 
-    killTimer(d->timerId);
-    d->timerId = 0;
+    killTimer(d->layoutTimerId);
+    d->layoutTimerId = 0;
 }
 
-void KHTMLView::unscheduleRepaint()
-{
-    if (!d->repaintTimerId)
-        return;
-
-    killTimer(d->repaintTimerId);
-    d->repaintTimerId = 0;
-}
-
-void KHTMLView::scheduleRepaint(int x, int y, int w, int h)
-{
-
-    //kdDebug() << "scheduleRepaint(" << x << "," << y << "," << w << "," << h << ")" << endl;
-
-
-    bool parsing = false;
-    if( m_part->xmlDocImpl() ) {
-        parsing = m_part->xmlDocImpl()->parsing();
-    }
-
-//     kdDebug() << "parsing " << parsing << endl;
-//     kdDebug() << "complete " << d->complete << endl;
-
-    int time;
-
-    // if complete...
-    if (d->complete)
-        // ...repaint immediatly
-        time = 0;
-    else
-    {
-        if (parsing)
-            // not complete and still parsing
-            time = 300;
-        else
-            // not complete, not parsing, extend the timer if it exists
-            // otherwise, repaint immediatly
-            time = d->repaintTimerId ? 400 : 0;
-    }
-
-    if (d->repaintTimerId) {
-        killTimer(d->repaintTimerId);
-        d->updateRect = d->updateRect.unite(QRect(x,y,w,h));
-    } else
-        d->updateRect = QRect(x,y,w,h);
-
-    d->repaintTimerId = startTimer( time );
-
-//     kdDebug() << "starting timer " << time << endl;
-}
-
-
 void KHTMLView::complete()
 {
 //     kdDebug() << "KHTMLView::complete()" << endl;
@@ -1688,20 +1618,11 @@ void KHTMLView::complete()
     d->complete = true;
 
     // is there a relayout pending?
-    if (d->timerId)
+    if (d->layoutTimerId)
     {
 //         kdDebug() << "requesting relayout now" << endl;
-        // do it now
-        killTimer(d->timerId);
-        d->timerId = startTimer( 0 );
-    }
-
-    // is there a repaint pending?
-    if (d->repaintTimerId)
-    {
-//         kdDebug() << "requesting repaint now" << endl;
         // do it now
-        killTimer(d->repaintTimerId);
-        d->repaintTimerId = startTimer( 1 );
+        killTimer(d->layoutTimerId);
+        d->layoutTimerId = startTimer( 0 );
     }
 }
Index: khtml/khtmlview.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/khtmlview.h,v
retrieving revision 1.26
diff -u -p -r1.26 khtml/khtmlview.h
--- khtml/khtmlview.h	2003/08/22 04:18:56	1.26
+++ khtml/khtmlview.h	2003/09/26 00:50:19
@@ -187,6 +187,8 @@ public:
 
     void timerEvent ( QTimerEvent * );
 
+    void repaintRectangle(const QRect& r, bool immediate);
+    
 #if APPLE_CHANGES
     QWidget *topLevelWidget() const;
     QPoint mapToGlobal(const QPoint &) const;
@@ -204,12 +206,13 @@ private:
 
     void resetCursor();
 
+#ifdef INCREMENTAL_REPAINTING
+    void scheduleRelayout();
+#else
     void scheduleRelayout(khtml::RenderObject* clippedObj=0);
+#endif
     void unscheduleRelayout();
 
-    void scheduleRepaint(int x, int y, int w, int h);
-    void unscheduleRepaint();
-    
     /**
      * Paints the HTML document to a QPainter.
      * The document will be scaled to match the width of
@@ -256,9 +259,11 @@ private:
 
     void complete();
 
+#ifndef INCREMENTAL_REPAINTING
     // Returns the clipped object we will repaint when we perform our scheduled layout.
     khtml::RenderObject* layoutObject() { return m_layoutObject; }
-
+#endif
+    
     // ------------------------------------- member variables ------------------------------------
  private:
     unsigned _refCount;
@@ -273,10 +278,12 @@ private:
     KHTMLViewPrivate *d;
 
     QString m_medium;   // media type
-    
+
+#ifndef INCREMENTAL_REPAINTING
     // An overflow: hidden clipped object.  If this is set, a scheduled layout will only repaint
     // the object's clipped area, and it will not do a full repaint.
     khtml::RenderObject* m_layoutObject;
+#endif
 };
 
 #endif
Index: khtml/html/html_documentimpl.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/html/html_documentimpl.cpp,v
retrieving revision 1.45
diff -u -p -r1.45 khtml/html/html_documentimpl.cpp
--- khtml/html/html_documentimpl.cpp	2003/09/20 01:22:02	1.45
+++ khtml/html/html_documentimpl.cpp	2003/09/26 00:50:19
@@ -346,11 +346,9 @@ void HTMLDocumentImpl::close()
     if (body() && doload) {
         updateRendering();
         
-        // Always do a layout/repaint after loading.
-        if (renderer()) {
-            renderer()->layoutIfNeeded();
-            renderer()->repaint();
-        }
+        // Always do a layout after loading if needed.
+        if (renderer() && renderer()->needsLayout())
+            view()->layout();
     }
 }
 
Index: khtml/rendering/render_block.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.cpp,v
retrieving revision 1.57
diff -u -p -r1.57 khtml/rendering/render_block.cpp
--- khtml/rendering/render_block.cpp	2003/09/19 22:54:38	1.57
+++ khtml/rendering/render_block.cpp	2003/09/26 00:50:19
@@ -100,8 +100,6 @@ void RenderBlock::addChildToFlow(RenderO
     if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER)
         beforeChild = lastChild();
     
-    setNeedsLayout(true);
-
     bool madeBoxesNonInline = FALSE;
 
     RenderStyle* pseudoStyle=0;
@@ -311,10 +309,7 @@ void RenderBlock::makeChildrenNonInline(
         box->appendChildNode(removeChildNode(inlineRunEnd));
         box->close();
         box->setPos(box->xPos(), -500000);
-        box->setNeedsLayout(true);
     }
-
-    setNeedsLayout(true);
 }
 
 void RenderBlock::removeChild(RenderObject *oldChild)
@@ -360,7 +355,6 @@ void RenderBlock::removeChild(RenderObje
             appendChildNode(anonBlock->removeChildNode(no));
             no->setNeedsLayoutAndMinMaxRecalc();
         }
-        setNeedsLayoutAndMinMaxRecalc();
         
         // Nuke the now-empty block.
         anonBlock->detach(renderArena());
@@ -415,12 +409,28 @@ void RenderBlock::layoutBlock(bool relay
     //     t.start();
     KHTMLAssert( needsLayout() );
     KHTMLAssert( minMaxKnown() );
-    
+
     if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
         return;	    		                     // cause us to come in here.  Just bail. -dwh
 
-    int oldWidth = m_width;
+    if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
+        // All we have to is lay out our positioned objects.
+        layoutPositionedObjects(relayoutChildren);
+        setNeedsLayout(false);
+        return;
+    }
+
+#ifdef INCREMENTAL_REPAINTING
+    // FIXME: For now, if we have dirty inline children, we just always repaint.
+    if (normalChildNeedsLayout() && childrenInline())
+        repaint();
+    
+    QRect oldBounds, oldFullBounds;
+    getAbsoluteRepaintRectIncludingDescendants(oldBounds, oldFullBounds);
+#endif
 
+    int oldWidth = m_width;
+    
     calcWidth();
     m_overflowWidth = m_width;
 
@@ -524,14 +534,22 @@ void RenderBlock::layoutBlock(bool relay
 
     //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl;
 
-    // Always ensure our overflow width is at least as large as our width.
+    // Always ensure our overflow width/height are at least as large as our width/height.
     if (m_overflowWidth < m_width)
         m_overflowWidth = m_width;
-
+    if (m_overflowHeight < m_height)
+        m_overflowHeight = m_height;
+    
     // Update our scrollbars if we're overflow:auto/scroll now that we know if
     // we overflow or not.
     if (style()->scrollsOverflow() && m_layer)
         m_layer->checkScrollbarsAfterLayout();
+
+#ifdef INCREMENTAL_REPAINTING
+    // Repaint with our new bounds if they are different from our old bounds.
+    if (!isCanvas())
+        repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds);
+#endif
     
     setNeedsLayout(false);
 }
@@ -638,7 +656,7 @@ void RenderBlock::layoutBlockChildren( b
         if (relayoutChildren || floatBottom() > m_y ||
             (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
             (child->isRenderBlock() && child->style()->height().isPercent()))
-            child->setNeedsLayout(true);
+            child->setChildNeedsLayout(true);
 
         //         kdDebug( 6040 ) << "   " << child->renderName() << " loop " << child << ", " << child->isInline() << ", " << child->needsLayout() << endl;
         //         kdDebug( 6040 ) << t.elapsed() << endl;
@@ -774,12 +792,17 @@ void RenderBlock::layoutBlockChildren( b
 
         // take care in case we inherited floats
         if (child && floatBottom() > m_height)
-            child->setNeedsLayout(true);
+            child->setChildNeedsLayout(true);
         
         child->calcVerticalMargins();
 
         //kdDebug(0) << "margin = " << margin << " yPos = " << m_height << endl;
 
+#ifdef INCREMENTAL_REPAINTING
+        int oldChildX = child->xPos();
+        int oldChildY = child->yPos();
+#endif
+        
         // Try to guess our correct y position.  In most cases this guess will
         // be correct.  Only if we're wrong (when we compute the real y position)
         // will we have to relayout.
@@ -788,7 +811,7 @@ void RenderBlock::layoutBlockChildren( b
         {
             yPosEstimate += QMAX(prevFlow->collapsedMarginBottom(), child->marginTop());
             if (prevFlow->yPos()+prevFlow->floatBottom() > yPosEstimate)
-                child->setNeedsLayout(true);
+                child->setChildNeedsLayout(true);
             else
                 prevFlow=0;
         }
@@ -910,7 +933,7 @@ void RenderBlock::layoutBlockChildren( b
                     // property set, when the child shifts to clear an item, its width can
                     // change (because it has more available line width).
                     // So go ahead and mark the item as dirty.
-                    child->setNeedsLayout(true);
+                    child->setChildNeedsLayout(true);
 
                 if (child->containsFloats() || containsFloats())
                     child->markAllDescendantsWithFloatsForLayout();
@@ -962,7 +985,7 @@ void RenderBlock::layoutBlockChildren( b
                 // property set, when the child shifts to clear an item, its width can
                 // change (because it has more available line width).
                 // So go ahead an mark the item as dirty.
-                child->setNeedsLayout(true);
+                child->setChildNeedsLayout(true);
             if (child->containsFloats())
                 child->markAllDescendantsWithFloatsForLayout();
             child->layoutIfNeeded();
@@ -1048,6 +1071,14 @@ void RenderBlock::layoutBlockChildren( b
             child->style()->setDisplay(COMPACT);
             treatCompactAsBlock = false;
         }
+
+        // If the child moved, we have to repaint it as well as any floating/positioned
+        // descendants.  An exception is if we need a layout.  In this case, we know we're going to
+        // repaint ourselves (and the child) anyway.
+#ifdef INCREMENTAL_REPAINTING
+        if (!selfNeedsLayout())
+            child->repaintIfMoved(oldChildX, oldChildY);
+#endif
         
         child = child->nextSibling();
     }
@@ -1106,12 +1137,67 @@ void RenderBlock::layoutPositionedObject
         for ( ; (r = it.current()); ++it ) {
             //kdDebug(6040) << "   have a positioned object" << endl;
             if ( relayoutChildren )
-                r->setNeedsLayout(true);
+                r->setChildNeedsLayout(true);
             r->layoutIfNeeded();
         }
     }
 }
 
+#ifdef INCREMENTAL_REPAINTING
+void RenderBlock::getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds)
+{
+    bounds = fullBounds = getAbsoluteRepaintRect();
+    if (m_positionedObjects) {
+        RenderObject* r;
+        QPtrListIterator<RenderObject> it(*m_positionedObjects);
+        for ( ; (r = it.current()); ++it ) {
+            QRect childRect, childFullRect;
+            r->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
+            fullBounds = fullBounds.unite(childFullRect);
+        }
+    }
+
+    // Include any overhanging floats (if we know we're the one to paint them).
+    if (hasOverhangingFloats()) {
+        FloatingObject* r;
+        QPtrListIterator<FloatingObject> it(*m_floatingObjects);
+        for ( ; (r = it.current()); ++it) {
+            // Only repaint the object if our noPaint flag isn't set.
+            if (!r->noPaint) {
+                QRect childRect, childFullRect;
+                r->node->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
+                fullBounds = fullBounds.unite(childFullRect);
+            }
+        }
+    }
+}
+
+void RenderBlock::repaintPositionedAndFloatingDescendants()
+{
+    if (m_positionedObjects) {
+        RenderObject* r;
+        QPtrListIterator<RenderObject> it(*m_positionedObjects);
+        for ( ; (r = it.current()); ++it ) {
+            r->repaint();
+            r->repaintPositionedAndFloatingDescendants();
+        }
+    }
+
+    // Repaint any overhanging floats (if we know we're the one to paint them).
+    if (hasOverhangingFloats()) {
+        FloatingObject* r;
+        QPtrListIterator<FloatingObject> it(*m_floatingObjects);
+        for ( ; (r = it.current()); ++it) {
+            // Only repaint the object if our noPaint flag isn't set.
+            if (!r->noPaint) {
+                r->node->repaint();
+                r->node->repaintPositionedAndFloatingDescendants();
+            }
+        }
+    }
+}
+#endif
+
 void RenderBlock::paint(QPainter* p, int _x, int _y, int _w, int _h, int _tx, int _ty, PaintAction paintAction)
 {
     _tx += m_x;
@@ -1210,7 +1296,7 @@ void RenderBlock::paintFloats(QPainter *
     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
     for ( ; (r = it.current()); ++it) {
         // Only paint the object if our noPaint flag isn't set.
-        if (r->node->isFloating() && !r->noPaint && !r->node->layer()) {
+        if (!r->noPaint && !r->node->layer()) {
             if (paintSelection) {
                 r->node->paint(p, _x, _y, _w, _h,
                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
@@ -2343,14 +2429,6 @@ void RenderBlock::calcBlockMinMaxWidth()
         
         child = child->nextSibling();
     }
-}
-
-void RenderBlock::close()
-{
-    if (lastChild() && lastChild()->isAnonymousBox())
-        lastChild()->close();
-
-    RenderFlow::close();
 }
 
 short RenderBlock::lineHeight(bool b, bool isRootLineBox) const
Index: khtml/rendering/render_block.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.h,v
retrieving revision 1.22
diff -u -p -r1.22 khtml/rendering/render_block.h
--- khtml/rendering/render_block.h	2003/09/19 22:54:38	1.22
+++ khtml/rendering/render_block.h	2003/09/26 00:50:19
@@ -92,7 +92,12 @@ public:
 
     virtual void addChildToFlow(RenderObject* newChild, RenderObject* beforeChild);
     virtual void removeChild(RenderObject *oldChild);
-        
+
+#ifdef INCREMENTAL_REPAINTING
+    virtual void repaintPositionedAndFloatingDescendants();
+    virtual void getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds);
+#endif
+
     virtual void setStyle(RenderStyle* _style);
 
     virtual void layout();
@@ -166,8 +171,6 @@ public:
     virtual void calcMinMaxWidth();
     void calcInlineMinMaxWidth();
     void calcBlockMinMaxWidth();
-
-    virtual void close();
 
     virtual int getBaselineOfFirstLineBox();
     virtual InlineFlowBox* getFirstLineBox();
Index: khtml/rendering/render_box.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.cpp,v
retrieving revision 1.82
diff -u -p -r1.82 khtml/rendering/render_box.cpp
--- khtml/rendering/render_box.cpp	2003/09/19 22:54:38	1.82
+++ khtml/rendering/render_box.cpp	2003/09/26 00:50:19
@@ -71,7 +71,7 @@ void RenderBox::setStyle(RenderStyle *_s
     // The root always paints its background/border.
     if (isRoot())
         setShouldPaintBackgroundOrBorder(true);
-    
+
     setInline(_style->isDisplayInlineType());
     
     switch(_style->position())
@@ -189,8 +189,12 @@ void RenderBox::paint(QPainter *p, int _
 
 void RenderBox::setPixmap(const QPixmap &, const QRect&, CachedImage *image)
 {
-    if(image && image->pixmap_size() == image->valid_rect().size() && parent())
-        repaint();      //repaint bg when it finished loading
+    if (image && image->pixmap_size() == image->valid_rect().size() && parent()) {
+        if (element() && (element()->id() == ID_HTML || element()->id() == ID_BODY))
+            canvas()->repaint(); // repaint the entire canvas, since the background gets propagated up.
+        else
+            repaint();      //repaint bg when it finished loading
+    }
 }
 
 void RenderBox::paintRootBoxDecorations(QPainter *p,int, int _y,
@@ -498,11 +502,6 @@ QRect RenderBox::getClipRect(int tx, int
     return cr;
 }
 
-void RenderBox::close()
-{
-    setNeedsLayoutAndMinMaxRecalc();
-}
-
 short RenderBox::containingBlockWidth() const
 {
     if (isRoot() && canvas()->view())
@@ -569,24 +568,19 @@ void RenderBox::position(InlineBox* box,
     }
 }
 
-void RenderBox::repaint(bool immediate)
+QRect RenderBox::getAbsoluteRepaintRect()
 {
-    //kdDebug( 6040 ) << "repaint!" << endl;
-    if (isRoot() || isBody()) {
-        RenderObject *cb = containingBlock();
-        if(cb != this)
-            cb->repaint(immediate);
-        return;
-    }
     int ow = style() ? style()->outlineWidth() : 0;
-    repaintRectangle(-ow, -ow, overflowWidth(false)+ow*2, overflowHeight(false)+ow*2, immediate);
+    QRect r(-ow, -ow, overflowWidth(false)+ow*2, overflowHeight(false)+ow*2);
+    computeAbsoluteRepaintRect(r);
+    return r;
 }
 
-void RenderBox::repaintRectangle(int x, int y, int w, int h, bool immediate, bool f)
+void RenderBox::computeAbsoluteRepaintRect(QRect& r, bool f)
 {
-    x += m_x;
-    y += m_y;
-    
+    int x = r.x() + m_x;
+    int y = r.y() + m_y;
+     
     // Apply the relative position offset when invalidating a rectangle.  The layer
     // is translated, but the render box isn't, so we need to do this to get the
     // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
@@ -594,7 +588,8 @@ void RenderBox::repaintRectangle(int x, 
     if (style()->position() == RELATIVE)
         relativePositionOffset(x,y);
     
-    if (style()->position()==FIXED) f=true;
+    if (style()->position()==FIXED)
+        f = true;
 
     RenderObject* o = container();
     if (o) {
@@ -603,19 +598,42 @@ void RenderBox::repaintRectangle(int x, 
             QRect boxRect(-ow, -ow, o->width()+ow*2, o->height()+ow*2);
             if (o->layer())
                 o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
-            QRect repaintRect(x, y, w, h);
-            if (!repaintRect.intersects(boxRect))
+            QRect repaintRect(x, y, r.width(), r.height());
+            if (!repaintRect.intersects(boxRect)) {
+                r = QRect();
                 return;
-            repaintRect = repaintRect.intersect(boxRect);
-            x = repaintRect.x();
-            y = repaintRect.y();
-            w = repaintRect.width();
-            h = repaintRect.height();
+            }
+            r = repaintRect.intersect(boxRect);
         }
-        o->repaintRectangle(x, y, w, h, immediate, f);
+        else {
+            r.setX(x);
+            r.setY(y);
+        }
+        o->computeAbsoluteRepaintRect(r, f);
     }
 }
 
+#ifdef INCREMENTAL_REPAINTING
+void RenderBox::repaintIfMoved(int oldX, int oldY)
+{
+    if (isCanvas())
+        return;
+    
+    int newX = m_x;
+    int newY = m_y;
+    if (oldX != newX || oldY != newY) {
+        // The child moved.  Invalidate the object's old and new positions.  We have to do this
+        // since the object may not have gotten a layout.
+        m_x = oldX; m_y = oldY;
+        repaint();
+        repaintPositionedAndFloatingDescendants();
+        m_x = newX; m_y = newY;
+        repaint();
+        repaintPositionedAndFloatingDescendants();
+    }
+}
+#endif
+
 void RenderBox::relativePositionOffset(int &tx, int &ty)
 {
     if(!style()->left().isVariable())
@@ -1003,8 +1021,9 @@ void RenderBox::calcAbsoluteHorizontal()
     int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
 
     l=r=ml=mr=w=AUTO;
-
-    RenderBlock* cb = containingBlock();
+ 
+    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+    RenderObject* cb = container();
     cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
 
     if(!style()->left().isVariable())
@@ -1040,7 +1059,6 @@ void RenderBox::calcAbsoluteHorizontal()
             || style()->right().isStatic())
     {
         RenderObject* po = parent();
-        RenderBlock* cb = containingBlock();
         static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
         while (po && po!=containingBlock()) {
             static_distance+=po->xPos();
@@ -1158,7 +1176,8 @@ void RenderBox::calcAbsoluteVertical()
 
     int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
 
-    RenderObject* cb = containingBlock();
+    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+    RenderObject* cb = container();
     Length hl = cb->style()->height();
     if (hl.isFixed())
         ch = hl.value + cb->paddingTop()
Index: khtml/rendering/render_box.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.h,v
retrieving revision 1.27
diff -u -p -r1.27 khtml/rendering/render_box.h
--- khtml/rendering/render_box.h	2003/09/19 22:54:38	1.27
+++ khtml/rendering/render_box.h	2003/09/26 00:50:19
@@ -50,8 +50,6 @@ public:
     virtual void paint(QPainter *p, int _x, int _y, int _w, int _h,
                        int _tx, int _ty, PaintAction paintAction);
 
-    virtual void close();
-
     virtual void detach(RenderArena* renderArena);
     
     virtual short minWidth() const { return m_minWidth; }
@@ -87,11 +85,14 @@ public:
     
     virtual int lowestPosition(bool includeOverflowInterior=true) const;
     virtual int rightmostPosition(bool includeOverflowInterior=true) const;
-
-    virtual void repaint(bool immediate=false);
 
-    virtual void repaintRectangle(int x, int y, int w, int h, bool immediate=false, bool f=false);
+    virtual QRect getAbsoluteRepaintRect();
+    virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
 
+#ifdef INCREMENTAL_REPAINTING
+    virtual void repaintIfMoved(int oldX, int oldY);
+#endif
+    
     virtual void setPixmap(const QPixmap &, const QRect&, CachedImage *);
 
     virtual short containingBlockWidth() const;
Index: khtml/rendering/render_canvas.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_canvas.cpp,v
retrieving revision 1.6
diff -u -p -r1.6 khtml/rendering/render_canvas.cpp
--- khtml/rendering/render_canvas.cpp	2003/08/22 00:45:21	1.6
+++ khtml/rendering/render_canvas.cpp	2003/09/26 00:50:19
@@ -122,11 +122,17 @@ void RenderCanvas::calcMinMaxWidth()
 
 void RenderCanvas::layout()
 {
+#ifdef INCREMENTAL_REPAINTING
+    QRect oldBounds(m_x, m_y, m_width, m_height);
+#endif
+
     if (m_printingMode)
        m_minWidth = m_width;
 
+    setChildNeedsLayout(true);
+    setMinMaxKnown(false);
     for (RenderObject *c = firstChild(); c; c = c->nextSibling())
-        c->setNeedsLayout(true);
+        c->setChildNeedsLayout(true);
 
 #ifdef SPEED_DEBUG
     QTime qt;
@@ -173,6 +179,12 @@ void RenderCanvas::layout()
     layer()->setHeight(QMAX(doch, m_height));
     layer()->setWidth(QMAX(docw, m_width));
 
+#ifdef INCREMENTAL_REPAINTING
+    QRect newBounds(m_x, m_y, m_width, m_height);
+    if (oldBounds != newBounds)
+        repaint();
+#endif
+    
     setNeedsLayout(false);
 }
 
@@ -255,53 +267,51 @@ void RenderCanvas::paintBoxDecorations(Q
         p->fillRect(_x,_y,_w,_h, view()->palette().active().color(QColorGroup::Base));
 }
 
-void RenderCanvas::repaintRectangle(int x, int y, int w, int h, bool immediate, bool f)
+void RenderCanvas::repaintViewRectangle(const QRect& ur, bool immediate)
 {
-    if (m_printingMode) return;
-//    kdDebug( 6040 ) << "updating views contents (" << x << "/" << y << ") (" << w << "/" << h << ")" << endl;
-
-    if ( f && m_view ) {
-        x += m_view->contentsX();
-        y += m_view->contentsY();
-    }
+    if (m_printingMode || ur.width() == 0 || ur.height() == 0) return;
 
     QRect vr = viewRect();
-    QRect ur(x, y, w, h);
-
-    if (m_view && ur.intersects(vr))
-        if (immediate)
-            m_view->updateContents(ur, true);
-        else
-            m_view->scheduleRepaint(x, y, w, h);
-}
-
-void RenderCanvas::repaint(bool immediate)
-{
-    if (m_view && !m_printingMode) {
-        if (immediate) {
-            m_view->resizeContents(docWidth(), docHeight());
-            m_view->unscheduleRepaint();
-            if (needsLayout()) {
-                m_view->scheduleRelayout();
-                return;
-            }
-            m_view->updateContents(m_view->contentsX(), m_view->contentsY(),
-                                   m_view->visibleWidth(), m_view->visibleHeight(), true);
+    if (m_view && ur.intersects(vr)) {
+        // We always just invalidate the root view, since we could be an iframe that is clipped out
+        // or even invisible.
+        QRect r = ur.intersect(vr);
+        DOM::ElementImpl* elt = element()->getDocument()->ownerElement();
+        if (!elt)
+            m_view->repaintRectangle(r, immediate);
+        else {
+            // Subtract out the contentsX and contentsY offsets to get our coords within the viewing
+            // rectangle.
+            r.setX(r.x() - m_view->contentsX());
+            r.setY(r.y() - m_view->contentsY());
+
+            RenderObject* obj = elt->renderer();
+            r.setX(r.x() + obj->borderLeft()+obj->paddingLeft());
+            r.setY(r.y() + obj->borderTop()+obj->paddingTop());
+            obj->repaintRectangle(r, immediate);
         }
-        else
-            m_view->scheduleRepaint(m_view->contentsX(), m_view->contentsY(),
-                                    m_view->visibleWidth(), m_view->visibleHeight());
     }
 }
+
+QRect RenderCanvas::getAbsoluteRepaintRect()
+{
+    QRect result;
+    if (m_view && !m_printingMode)
+        result = QRect(m_view->contentsX(), m_view->contentsY(),
+                       m_view->visibleWidth(), m_view->visibleHeight());
+    return result;
+}
 
-void RenderCanvas::close()
+void RenderCanvas::computeAbsoluteRepaintRect(QRect& r, bool f)
 {
-    setNeedsLayout(true);
-    if (m_view) {
-        m_view->layout();
+    if (m_printingMode) return;
+
+    if (f && m_view) {
+        r.setX(r.x() + m_view->contentsX());
+        r.setY(r.y() + m_view->contentsY());
     }
-    //printTree();
 }
+
 
 static QRect enclosingPositionedRect (RenderObject *n)
 {
Index: khtml/rendering/render_canvas.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_canvas.h,v
retrieving revision 1.2
diff -u -p -r1.2 khtml/rendering/render_canvas.h
--- khtml/rendering/render_canvas.h	2003/05/09 01:16:29	1.2
+++ khtml/rendering/render_canvas.h	2003/09/26 00:50:19
@@ -44,15 +44,16 @@ public:
     virtual void calcHeight();
     virtual void calcMinMaxWidth();
     virtual bool absolutePosition(int &xPos, int&yPos, bool f = false);
-    virtual void close();
-
+    
     int docHeight() const;
     int docWidth() const;
 
     KHTMLView *view() const { return m_view; }
 
-    virtual void repaint(bool immediate=false);
-    virtual void repaintRectangle(int x, int y, int w, int h, bool immediate = false, bool f=false);
+    virtual QRect getAbsoluteRepaintRect();
+    virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
+    virtual void repaintViewRectangle(const QRect& r, bool immediate = false);
+    
     virtual void paint(QPainter *, int x, int y, int w, int h, int tx, int ty,
                        PaintAction paintAction);
     void paintObject(QPainter *p, int _x, int _y,
Index: khtml/rendering/render_container.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_container.cpp,v
retrieving revision 1.39
diff -u -p -r1.39 khtml/rendering/render_container.cpp
--- khtml/rendering/render_container.cpp	2003/08/20 22:03:24	1.39
+++ khtml/rendering/render_container.cpp	2003/09/26 00:50:19
@@ -149,13 +149,20 @@ void RenderContainer::addChild(RenderObj
 	// just add it...
 	insertChildNode(newChild, beforeChild);
     }
-    newChild->setNeedsLayoutAndMinMaxRecalc();
 }
 
 RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild)
 {
     KHTMLAssert(oldChild->parent() == this);
 
+    // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
+    // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
+    // disappears gets repainted properly.
+    oldChild->setNeedsLayoutAndMinMaxRecalc();
+#ifdef INCREMENTAL_REPAINTING
+    oldChild->repaint();
+#endif
+    
     // Keep our layer hierarchy updated.
     oldChild->removeLayers(enclosingLayer());
    
@@ -192,15 +199,12 @@ RenderObject* RenderContainer::removeChi
     oldChild->setNextSibling(0);
     oldChild->setParent(0);
 
-    setNeedsLayoutAndMinMaxRecalc();
-    
     return oldChild;
 }
 
 void RenderContainer::removeChild(RenderObject *oldChild)
 {
     removeChildNode(oldChild);
-    setNeedsLayout(true);
 }
 
 void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type, RenderObject* child)
@@ -349,7 +353,8 @@ void RenderContainer::appendChildNode(Re
     RenderLayer* layer = enclosingLayer();
     newChild->addLayers(layer, newChild);
 
-    newChild->setNeedsLayoutAndMinMaxRecalc();
+    newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy.
+    setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
 }
 
 void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild)
@@ -380,6 +385,7 @@ void RenderContainer::insertChildNode(Re
     child->addLayers(layer, child);
 
     child->setNeedsLayoutAndMinMaxRecalc();
+    setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
 }
 
 
Index: khtml/rendering/render_flexbox.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_flexbox.cpp,v
retrieving revision 1.3
diff -u -p -r1.3 khtml/rendering/render_flexbox.cpp
--- khtml/rendering/render_flexbox.cpp	2003/08/28 21:24:07	1.3
+++ khtml/rendering/render_flexbox.cpp	2003/09/26 00:50:19
@@ -240,6 +240,13 @@ void RenderFlexibleBox::layoutBlock(bool
     KHTMLAssert(needsLayout());
     KHTMLAssert(minMaxKnown());
 
+    if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
+        // All we have to is lay out our positioned objects.
+        layoutPositionedObjects(relayoutChildren);
+        setNeedsLayout(false);
+        return;
+    }
+    
     int oldWidth = m_width;
     int oldHeight = m_height;
     
Index: khtml/rendering/render_flow.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_flow.cpp,v
retrieving revision 1.109
diff -u -p -r1.109 khtml/rendering/render_flow.cpp
--- khtml/rendering/render_flow.cpp	2003/09/25 16:51:10	1.109
+++ khtml/rendering/render_flow.cpp	2003/09/26 00:50:19
@@ -229,7 +229,7 @@ void RenderFlow::paintLineBoxDecorations
     }
 }
 
-void RenderFlow::repaint(bool immediate)
+QRect RenderFlow::getAbsoluteRepaintRect()
 {
     if (isInlineFlow()) {
         // Find our leftmost position.
@@ -243,19 +243,22 @@ void RenderFlow::repaint(bool immediate)
         int ow = style() ? style()->outlineWidth() : 0;
         if (isCompact())
             left -= m_x;
-        containingBlock()->repaintRectangle(-ow+left, -ow+top,
-                                            width()+ow*2, height()+ow*2, immediate);
+        QRect r(-ow+left, -ow+top, width()+ow*2, height()+ow*2);
+        containingBlock()->computeAbsoluteRepaintRect(r);
+        return r;
     }
     else {
         if (firstLineBox() && firstLineBox()->topOverflow() < 0) {
             int ow = style() ? style()->outlineWidth() : 0;
-            repaintRectangle(-ow, -ow+firstLineBox()->topOverflow(),
-                             overflowWidth(false)+ow*2,
-                             overflowHeight(false)+ow*2-firstLineBox()->topOverflow(), immediate);
+            QRect r(-ow, -ow+firstLineBox()->topOverflow(),
+                    overflowWidth(false)+ow*2,
+                    overflowHeight(false)+ow*2-firstLineBox()->topOverflow());
+            computeAbsoluteRepaintRect(r);
+            return r;
         }
-        else
-            return RenderBox::repaint(immediate);
     }
+
+    return RenderBox::getAbsoluteRepaintRect();
 }
 
 int
Index: khtml/rendering/render_flow.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_flow.h,v
retrieving revision 1.43
diff -u -p -r1.43 khtml/rendering/render_flow.h
--- khtml/rendering/render_flow.h	2003/07/25 20:22:33	1.43
+++ khtml/rendering/render_flow.h	2003/09/26 00:50:19
@@ -69,8 +69,8 @@ public:
     void paintLineBoxDecorations(QPainter *p, int _x, int _y,
                                  int _w, int _h, int _tx, int _ty, PaintAction paintAction);
 
-    virtual void repaint(bool immediate = false);
-
+    virtual QRect getAbsoluteRepaintRect();
+    
     virtual int lowestPosition(bool includeOverflowInterior=true) const;
     virtual int rightmostPosition(bool includeOverflowInterior=true) const;
     
Index: khtml/rendering/render_image.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_image.cpp,v
retrieving revision 1.39
diff -u -p -r1.39 khtml/rendering/render_image.cpp
--- khtml/rendering/render_image.cpp	2003/09/19 22:54:38	1.39
+++ khtml/rendering/render_image.cpp	2003/09/26 00:50:19
@@ -157,16 +157,13 @@ void RenderImage::setPixmap( const QPixm
     
     pix = p;
 
-    if(needlayout)
-    {
-        setNeedsLayout(true);
-        setMinMaxKnown(false);
-
-//         kdDebug( 6040 ) << "m_width: : " << m_width << " height: " << m_height << endl;
-//         kdDebug( 6040 ) << "Image: size " << m_width << "/" << m_height << endl;
+    if (needlayout) {
+        if (!selfNeedsLayout())
+            setNeedsLayout(true);
+        if (minMaxKnown())
+            setMinMaxKnown(false);
     }
-    else
-    {
+    else {
         bool completeRepaint = !resizeCache.isNull();
         int cHeight = contentHeight();
         int scaledHeight = intrinsicHeight() ? ((o->valid_rect().height()*cHeight)/intrinsicHeight()) : 0;
@@ -178,11 +175,11 @@ void RenderImage::setPixmap( const QPixm
 
         resizeCache = QPixmap(); // for resized animations
         if(completeRepaint)
-            repaintRectangle(borderLeft()+paddingLeft(), borderTop()+paddingTop(), contentWidth(), contentHeight());
+            repaintRectangle(QRect(borderLeft()+paddingLeft(), borderTop()+paddingTop(), contentWidth(), contentHeight()));
         else
         {
-            repaintRectangle(r.x() + borderLeft() + paddingLeft(), r.y() + borderTop() + paddingTop(),
-                             r.width(), r.height());
+            repaintRectangle(QRect(r.x() + borderLeft() + paddingLeft(), r.y() + borderTop() + paddingTop(),
+                             r.width(), r.height()));
         }
     }
 }
@@ -354,6 +351,10 @@ void RenderImage::layout()
     KHTMLAssert(needsLayout());
     KHTMLAssert( minMaxKnown() );
 
+#ifdef INCREMENTAL_PAINTING
+    QRect oldBounds(getAbsoluteRepaintRect());
+#endif
+    
     short oldwidth = m_width;
     int oldheight = m_height;
 
@@ -381,10 +382,14 @@ void RenderImage::layout()
 	m_height = (int) (m_height/scale);
     }
 #endif
-    
+
     if ( m_width != oldwidth || m_height != oldheight )
         resizeCache = QPixmap();
 
+#ifdef INCREMENTAL_PAINTING
+    repaintAfterLayoutIfNeeded(oldBounds, oldBounds);
+#endif
+    
     setNeedsLayout(false);
 }
 
Index: khtml/rendering/render_inline.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_inline.cpp,v
retrieving revision 1.17
diff -u -p -r1.17 khtml/rendering/render_inline.cpp
--- khtml/rendering/render_inline.cpp	2003/09/19 22:54:38	1.17
+++ khtml/rendering/render_inline.cpp	2003/09/26 00:50:19
@@ -75,8 +75,6 @@ void RenderInline::addChildToFlow(Render
     if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER)
         beforeChild = lastChild();
     
-    setNeedsLayout(true);
-    
     if (!newChild->isText() && newChild->style()->position() != STATIC)
         setOverhangingContents();
     
Index: khtml/rendering/render_layer.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_layer.cpp,v
retrieving revision 1.51
diff -u -p -r1.51 khtml/rendering/render_layer.cpp
--- khtml/rendering/render_layer.cpp	2003/09/25 00:00:28	1.51
+++ khtml/rendering/render_layer.cpp	2003/09/26 00:50:19
@@ -323,6 +323,21 @@ RenderLayer::convertToLayerCoords(const 
     
     parentLayer->convertToLayerCoords(ancestorLayer, x, y);
 
+    if (m_object->style()->position() == ABSOLUTE && parentLayer->renderer()->style()->position() == RELATIVE &&
+        parentLayer->renderer()->isInline() && !parentLayer->renderer()->isReplaced()) {
+        // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
+        // box from the rest of the content, but only in the cases where we know we're positioned
+        // relative to the inline itself.
+        RenderFlow* flow = static_cast<RenderFlow*>(parentLayer->renderer());
+        if (flow->firstLineBox()) {
+            bool isInlineType = m_object->style()->isOriginalDisplayInlineType();
+            if (!m_object->hasStaticX() || (m_object->hasStaticX() && !isInlineType))
+                x += flow->firstLineBox()->xPos();
+            if (!m_object->hasStaticY())
+                y += flow->firstLineBox()->yPos();
+        }
+    }
+    
     x += xPos();
     y += yPos();
 }
Index: khtml/rendering/render_list.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_list.cpp,v
retrieving revision 1.42
diff -u -p -r1.42 khtml/rendering/render_list.cpp
--- khtml/rendering/render_list.cpp	2003/08/12 18:30:32	1.42
+++ khtml/rendering/render_list.cpp	2003/09/26 00:50:19
@@ -495,10 +495,10 @@ void RenderListMarker::setPixmap( const 
         return;
     }
 
-    if(m_width != m_listImage->pixmap_size().width() || m_height != m_listImage->pixmap_size().height())
+    if (m_width != m_listImage->pixmap_size().width() || m_height != m_listImage->pixmap_size().height())
         setNeedsLayoutAndMinMaxRecalc();
     else
-        repaintRectangle(0, 0, m_width, m_height);
+        repaint();
 }
 
 void RenderListMarker::calcMinMaxWidth()
Index: khtml/rendering/render_object.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.cpp,v
retrieving revision 1.98
diff -u -p -r1.98 khtml/rendering/render_object.cpp
--- khtml/rendering/render_object.cpp	2003/09/19 22:54:38	1.98
+++ khtml/rendering/render_object.cpp	2003/09/26 00:50:19
@@ -122,8 +122,9 @@ m_parent( 0 ),
 m_previous( 0 ),
 m_next( 0 ),
 m_verticalPosition( PositionUndefined ),
-m_needsLayout( true ),
-m_unused( false ),
+m_needsLayout( false ),
+m_normalChildNeedsLayout( false ),
+m_posChildNeedsLayout( false ),
 m_minMaxKnown( false ),
 m_floating( false ),
 
@@ -420,32 +421,81 @@ void RenderObject::markAllDescendantsWit
 
 void RenderObject::setNeedsLayout(bool b) 
 {
+#ifdef INCREMENTAL_REPAINTING
+    bool alreadyNeededLayout = m_needsLayout;
+#else
+    bool alreadyNeededLayout = false;
+#endif
     m_needsLayout = b;
+    if (b) {
+        if (!alreadyNeededLayout)
+            markContainingBlocksForLayout();
+    }
+    else {
+        m_posChildNeedsLayout = false;
+        m_normalChildNeedsLayout = false;
+    }
+}
+
+void RenderObject::setChildNeedsLayout(bool b)
+{
+#ifdef INCREMENTAL_REPAINTING
+    bool alreadyNeededLayout = m_normalChildNeedsLayout;
+#else
+    bool alreadyNeededLayout = false;
+#endif
+    m_normalChildNeedsLayout = b;
     if (b) {
-        RenderObject *o = container();
-        RenderObject *root = this;
+        if (!alreadyNeededLayout)
+            markContainingBlocksForLayout();
+    }
+    else {
+        m_posChildNeedsLayout = false;
+        m_normalChildNeedsLayout = false;
+    }
+}
 
-        // If an attempt is made to
-        // setNeedsLayout(true) an object inside a clipped (overflow:hidden) object, we 
-        // have to make sure to repaint only the clipped rectangle.
-        // We do this by passing an argument to scheduleRelayout.  This hint really
-        // shouldn't be needed, and it's unfortunate that it is necessary.  -dwh
+void RenderObject::markContainingBlocksForLayout()
+{
+#ifndef INCREMENTAL_REPAINTING
+    RenderObject* clippedObj = (style()->hidesOverflow() && !isText()) ? this : 0;
+#endif
+    
+    RenderObject *o = container();
+    RenderObject *last = this;
 
-        RenderObject* clippedObj = 
-            (style()->hidesOverflow() && !isText()) ? this : 0;
-        
-        while( o ) {
-            root = o;
-            o->m_needsLayout = true;
-            if (o->style()->hidesOverflow() && !clippedObj)
-                clippedObj = o;
-            o = o->container();
+    while (o) {
+        if (last->style()->position() == FIXED || last->style()->position() == ABSOLUTE) {
+#ifdef INCREMENTAL_REPAINTING
+            if (o->m_posChildNeedsLayout)
+                return;
+#endif
+            o->m_posChildNeedsLayout = true;
         }
-        
-        root->scheduleRelayout(clippedObj);
+        else {
+#ifdef INCREMENTAL_REPAINTING
+            if (o->m_normalChildNeedsLayout)
+                return;
+#endif
+            o->m_normalChildNeedsLayout = true;
+        }
+
+#ifndef INCREMENTAL_REPAINTING
+        if (o->style()->hidesOverflow() && !clippedObj)
+            clippedObj = o;
+#endif
+
+        last = o;
+        o = o->container();
     }
+
+#ifdef INCREMENTAL_REPAINTING
+    last->scheduleRelayout();
+#else
+    last->scheduleRelayout(clippedObj);
+#endif
 }
-    
+
 RenderBlock* RenderObject::containingBlock() const
 {
     if(isTableCell())
@@ -460,8 +510,16 @@ RenderBlock* RenderObject::containingBlo
     }
     else if (m_style->position() == ABSOLUTE) {
         while (o && (o->style()->position() == STATIC || (o->isInline() && !o->isReplaced()))
-               && !o->isRoot() && !o->isCanvas())
+               && !o->isRoot() && !o->isCanvas()) {
+            // For relpositioned inlines, we return the nearest enclosing block.  We don't try
+            // to return the inline itself.  This allows us to avoid having a positioned objects
+            // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
+            // from this method.  The container() method can actually be used to obtain the
+            // inline directly.
+            if (o->style()->position() == RELATIVE && o->isInline() && !o->isReplaced())
+                return o->containingBlock();
             o = o->parent();
+        }
     } else {
         while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
                      || o->isTableCol()))
@@ -844,11 +902,82 @@ void RenderObject::paint(QPainter *p, in
     paintObject(p, x, y, w, h, tx, ty, paintAction);
 }
 
-void RenderObject::repaintRectangle(int x, int y, int w, int h, bool immediate, bool f)
+void RenderObject::repaint(bool immediate)
 {
-    if(parent()) parent()->repaintRectangle(x, y, w, h, immediate, f);
+    RenderObject* c = canvas();
+    if (!c || !c->isCanvas())
+        return;
+    RenderCanvas* canvasObj = static_cast<RenderCanvas*>(c);
+    if (canvasObj->printingMode())
+        return; // Don't repaint if we're printing.
+
+    canvasObj->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);    
 }
 
+void RenderObject::repaintRectangle(const QRect& r, bool immediate)
+{
+    RenderObject* c = canvas();
+    if (!c || !c->isCanvas())
+        return;
+    RenderCanvas* canvasObj = static_cast<RenderCanvas*>(c);
+    if (canvasObj->printingMode())
+        return; // Don't repaint if we're printing.
+
+    QRect absRect(r);
+    computeAbsoluteRepaintRect(absRect);
+    canvasObj->repaintViewRectangle(absRect, immediate);
+}
+
+#ifdef INCREMENTAL_REPAINTING
+void RenderObject::repaintAfterLayoutIfNeeded(const QRect& oldBounds, const QRect& oldFullBounds)
+{
+    if (!isFloatingOrPositioned() && parent() && parent()->selfNeedsLayout())
+        return;
+    
+    QRect newBounds, newFullBounds;
+    getAbsoluteRepaintRectIncludingDescendants(newBounds, newFullBounds);
+    if (newBounds != oldBounds || selfNeedsLayout()) {
+        RenderObject* c = canvas();
+        if (!c || !c->isCanvas())
+            return;
+        RenderCanvas* canvasObj = static_cast<RenderCanvas*>(c);
+        if (canvasObj->printingMode())
+            return; // Don't repaint if we're printing.
+        canvasObj->repaintViewRectangle(oldFullBounds);
+        if (newBounds != oldBounds)
+            canvasObj->repaintViewRectangle(newFullBounds);
+    }
+}
+
+void RenderObject::repaintIfMoved(int x, int y)
+{
+}
+
+void RenderObject::repaintPositionedAndFloatingDescendants()
+{
+}
+#endif
+
+QRect RenderObject::getAbsoluteRepaintRect()
+{
+    if (parent())
+        return parent()->getAbsoluteRepaintRect();
+    return QRect();
+}
+
+#ifdef INCREMENTAL_REPAINTING
+void RenderObject::getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds)
+{
+    bounds = fullBounds = getAbsoluteRepaintRect();
+}
+#endif
+
+void RenderObject::computeAbsoluteRepaintRect(QRect& r, bool f)
+{
+    if (parent())
+        return parent()->computeAbsoluteRepaintRect(r, f);
+}
+
 #ifndef NDEBUG
 
 QString RenderObject::information() const
@@ -998,7 +1127,12 @@ void RenderObject::setStyle(RenderStyle 
 
     RenderStyle::Diff d = m_style ? m_style->diff( style ) : RenderStyle::Layout;
 
-    if (m_style && m_parent && d == RenderStyle::Visible && !isText())
+    // The background of the root element or the body element could propagate up to
+    // the canvas.  Just dirty the entire canvas when our style changes substantially.
+    if (m_style && d >= RenderStyle::Visible && element() &&
+        (element()->id() == ID_HTML || element()->id() == ID_BODY))
+        canvas()->repaint();
+    else if (m_style && m_parent && d == RenderStyle::Visible && !isText())
         // Do a repaint with the old style first, e.g., for example if we go from
         // having an outline to not having an outline.
         repaint();
@@ -1058,7 +1192,7 @@ void RenderObject::setStyle(RenderStyle 
     if ( d >= RenderStyle::Position && m_parent ) {
         //qDebug("triggering relayout");
         setNeedsLayoutAndMinMaxRecalc();
-    } else if ( m_parent && !isText()) {
+    } else if ( m_parent && !isText() && d == RenderStyle::Visible ) {
         //qDebug("triggering repaint");
     	repaint();
     }
@@ -1178,6 +1312,15 @@ RenderCanvas* RenderObject::canvas() con
 
 RenderObject *RenderObject::container() const
 {
+    // This method is extremely similar to containingBlock(), but with a few notable
+    // exceptions.
+    // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
+    // the object is not part of the primary document subtree yet.
+    // (2) For normal flow elements, it just returns the parent.
+    // (3) For absolute positioned elements, it will return a relative positioned inline.
+    // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
+    // the layout of the positioned object.  This does mean that calcAbsoluteHorizontal and
+    // calcAbsoluteVertical have to use container().
     EPosition pos = m_style->position();
     RenderObject *o = 0;
     if( pos == FIXED ) {
@@ -1253,6 +1396,7 @@ RenderArena* RenderObject::renderArena()
 
 void RenderObject::detach(RenderArena* renderArena)
 {
+#ifndef INCREMENTAL_REPAINTING
     // If we're an overflow:hidden object that currently needs layout, we need
     // to make sure the view isn't holding on to us.
     if (needsLayout() && style()->hidesOverflow()) {
@@ -1260,7 +1404,8 @@ void RenderObject::detach(RenderArena* r
         if (r && r->view()->layoutObject() == this)
             r->view()->unscheduleRelayout();
     }
-    
+#endif
+
     remove();
     
     m_next = m_previous = 0;
@@ -1557,12 +1702,20 @@ void RenderObject::recalcMinMaxWidths()
     m_recalcMinMax = false;
 }
 
+#ifdef INCREMENTAL_REPAINTING
+void RenderObject::scheduleRelayout()
+#else
 void RenderObject::scheduleRelayout(RenderObject* clippedObj)
+#endif
 {
     if (!isCanvas()) return;
     KHTMLView *view = static_cast<RenderCanvas *>(this)->view();
-    if ( view )
+    if (view)
+#ifdef INCREMENTAL_REPAINTING
+        view->scheduleRelayout();
+#else
         view->scheduleRelayout(clippedObj);
+#endif
 }
 
 
Index: khtml/rendering/render_object.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.h,v
retrieving revision 1.80
diff -u -p -r1.80 khtml/rendering/render_object.h
--- khtml/rendering/render_object.h	2003/09/19 22:54:38	1.80
+++ khtml/rendering/render_object.h	2003/09/26 00:50:19
@@ -35,6 +35,9 @@
 #include "rendering/render_style.h"
 #include "khtml_events.h"
 
+// Uncomment to turn on incremental repainting.
+// #define INCREMENTAL_REPAINTING 1
+
 class QPainter;
 class QTextStream;
 class CSSStyle;
@@ -237,7 +240,10 @@ public:
     bool mouseInside() const;
     bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS)
     bool shouldPaintBackgroundOrBorder() const { return m_paintBackground; }
-    bool needsLayout() const   { return m_needsLayout; }
+    bool needsLayout() const   { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout; }
+    bool selfNeedsLayout() const { return m_needsLayout; }
+    bool posChildNeedsLayout() const { return m_posChildNeedsLayout; }
+    bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; }
     bool minMaxKnown() const{ return m_minMaxKnown; }
     bool overhangingContents() const { return m_overhangingContents; }
     bool hasFirstLine() const { return m_hasFirstLine; }
@@ -259,8 +265,9 @@ public:
     void setOverhangingContents(bool p=true);
 
     virtual void markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove = 0);
+    void markContainingBlocksForLayout();
     void setNeedsLayout(bool b);
-
+    void setChildNeedsLayout(bool b);
     void setMinMaxKnown(bool b=true) {
 	m_minMaxKnown = b;
 	if ( !b ) {
@@ -289,8 +296,12 @@ public:
     void setReplaced(bool b=true) { m_replaced = b; }
     void setIsSelectionBorder(bool b=true) { m_isSelectionBorder = b; }
 
-    void scheduleRelayout(RenderObject* clippedObj = 0);
-
+#ifdef INCREMENTAL_REPAINTING
+    void scheduleRelayout();
+#else
+    void scheduleRelayout(RenderObject* clippedObj);
+#endif
+    
     virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox);
     
     // for discussion of lineHeight see CSS2 spec
@@ -559,13 +570,37 @@ public:
 
     virtual void setTable(RenderTable*) {};
 
-    // force a complete repaint
-    virtual void repaint(bool immediate = false) { if(m_parent) m_parent->repaint(immediate); }
-    virtual void repaintRectangle(int x, int y, int w, int h, bool immediate = false, bool f=false);
+    // Repaint the entire object.  Called when, e.g., the color of a border changes, or when a border
+    // style changes.
+    void repaint(bool immediate = false);
+
+    // Repaint a specific subrectangle within a given object.  The rect |r| is in the object's coordinate space.
+    void repaintRectangle(const QRect& r, bool immediate = false);
+
+#ifdef INCREMENTAL_REPAINTING
+    // Repaint only if our old bounds and new bounds are different.
+    virtual void repaintAfterLayoutIfNeeded(const QRect& oldBounds, const QRect& oldFullBounds);
 
-    virtual unsigned int length() const { return 1; }
+    // Repaint only if the object moved.
+    virtual void repaintIfMoved(int oldX, int oldY);
 
-    virtual bool isHidden() const { return isFloating() || isPositioned(); }
+    // Called to repaint a block's positioned objects and floats.
+    virtual void repaintPositionedAndFloatingDescendants();
+#endif
+
+    // Returns the rect that should be repainted whenever this object changes.  The rect is in the view's
+    // coordinate space.  This method deals with outlines and overflow.
+    virtual QRect getAbsoluteRepaintRect();
+
+#ifdef INCREMENTAL_REPAINTING
+    virtual void getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& boundsWithChildren);
+#endif
+
+    // Given a rect in the object's coordinate space, this method converts the rectangle to the view's
+    // coordinate space.
+    virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
+    
+    virtual unsigned int length() const { return 1; }
 
     bool isFloatingOrPositioned() const { return (isFloating() || isPositioned()); };
     virtual bool containsFloats() { return false; }
@@ -650,12 +685,13 @@ private:
     short m_verticalPosition;
 
     bool m_needsLayout               : 1;
-    bool m_unused                    : 1;
+    bool m_normalChildNeedsLayout    : 1;
+    bool m_posChildNeedsLayout       : 1;
     bool m_minMaxKnown               : 1;
     bool m_floating                  : 1;
 
     bool m_positioned                : 1;
-    bool m_overhangingContents : 1;
+    bool m_overhangingContents       : 1;
     bool m_relPositioned             : 1;
     bool m_paintBackground           : 1; // if the box has something to paint in the
                                           // background painting phase (background, border, etc)
@@ -665,9 +701,9 @@ private:
     bool m_isText                    : 1;
     bool m_inline                    : 1;
     bool m_replaced                  : 1;
-    bool m_mouseInside : 1;
+    bool m_mouseInside               : 1;
     bool m_hasFirstLine              : 1;
-    bool m_isSelectionBorder          : 1;
+    bool m_isSelectionBorder         : 1;
 
     void arenaDelete(RenderArena *arena, void *objectBase);
 
Index: khtml/rendering/render_style.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_style.cpp,v
retrieving revision 1.27
diff -u -p -r1.27 khtml/rendering/render_style.cpp
--- khtml/rendering/render_style.cpp	2003/07/15 22:32:42	1.27
+++ khtml/rendering/render_style.cpp	2003/09/26 00:50:19
@@ -420,7 +420,8 @@ RenderStyle::Diff RenderStyle::diff( con
 //     DataRef<StyleInheritedData> inherited;
 
     if ( *box.get() != *other->box.get() ||
-        *surround.get() != *other->surround.get() ||
+         !(surround->margin == other->surround->margin) ||
+         !(surround->padding == other->surround->padding) ||
          *css3NonInheritedData->flexibleBox.get() != *other->css3NonInheritedData->flexibleBox.get() ||
         !(inherited->indent == other->inherited->indent) ||
         !(inherited->line_height == other->inherited->line_height) ||
@@ -491,6 +492,25 @@ RenderStyle::Diff RenderStyle::diff( con
          !(noninherited_flags._vertical_align == other->noninherited_flags._vertical_align))
         return Layout;
 
+    // If our border widths change, then we need to layout.  Other changes to borders
+    // only necessitate a repaint.
+    if (borderLeftWidth() != other->borderLeftWidth() ||
+        borderTopWidth() != other->borderTopWidth() ||
+        borderBottomWidth() != other->borderBottomWidth() ||
+        borderRightWidth() != other->borderRightWidth())
+        return Layout;
+
+    // Make sure these left/top/right/bottom checks stay below all layout checks and above
+    // all visible checks.
+    if (other->position() != STATIC && !(surround->offset == other->surround->offset)) {
+     // FIXME: would like to do this at some point, but will need a new hint that indicates
+     // descendants need to be repainted too.
+     //   if (other->position() == RELATIVE)
+     //       return Visible;
+     //   else
+            return Layout;
+    }
+
     // Visible:
 // 	EVisibility _visibility : 2;
 //     EOverflow _overflow : 4 ;
@@ -504,6 +524,7 @@ RenderStyle::Diff RenderStyle::diff( con
         !(noninherited_flags._bg_repeat == other->noninherited_flags._bg_repeat) ||
         !(noninherited_flags._bg_attachment == other->noninherited_flags._bg_attachment) ||
         !(inherited_flags._text_decorations == other->inherited_flags._text_decorations) ||
+        !(surround->border == other->surround->border) ||
         *background.get() != *other->background.get() ||
         !(visual->clip == other->visual->clip) ||
         visual->hasClip != other->visual->hasClip ||
Index: khtml/rendering/render_table.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_table.cpp,v
retrieving revision 1.71
diff -u -p -r1.71 khtml/rendering/render_table.cpp
--- khtml/rendering/render_table.cpp	2003/08/21 00:52:11	1.71
+++ khtml/rendering/render_table.cpp	2003/09/26 00:50:19
@@ -214,8 +214,21 @@ void RenderTable::layout()
     KHTMLAssert( minMaxKnown() );
     KHTMLAssert( !needSectionRecalc );
 
+    if (posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
+        // All we have to is lay out our positioned objects.
+        layoutPositionedObjects(true);
+        setNeedsLayout(false);
+        return;
+    }
+    
     //kdDebug( 6040 ) << renderName() << "(Table)"<< this << " ::layout0() width=" << width() << ", needsLayout=" << needsLayout() << endl;
 
+#ifdef INCREMENTAL_REPAINTING
+    // FIXME: We should be smarter about this, but for now just always repaint a table whenever it
+    // does a layout.
+    repaint();
+#endif
+    
     m_height = 0;
     initMaxMarginValues();
     
@@ -344,6 +357,12 @@ void RenderTable::layout()
     // ### only pass true if width or height changed.
     layoutPositionedObjects( true );
 
+#ifdef INCREMENTAL_REPAINTING
+    // FIXME: We should be smarter about this, but for now just always repaint a table whenever it
+    // does a layout.
+    repaint();
+#endif
+    
     setNeedsLayout(false);
 }
 
@@ -1383,13 +1402,15 @@ void RenderTableRow::layout()
     setNeedsLayout(false);
 }
 
-void RenderTableRow::repaint(bool immediate)
+QRect RenderTableRow::getAbsoluteRepaintRect()
 {
     // For now, just repaint the whole table.
     // FIXME: Find a better way to do this.
     RenderTable* parentTable = table();
     if (parentTable)
-        parentTable->repaint(immediate);
+        return parentTable->getAbsoluteRepaintRect();
+    else
+        return QRect();
 }
 
 // -------------------------------------------------------------------------
@@ -1482,10 +1503,10 @@ void RenderTableCell::close()
 }
 
 
-void RenderTableCell::repaintRectangle(int x, int y, int w, int h, bool immediate, bool f)
+void RenderTableCell::computeAbsoluteRepaintRect(QRect& r, bool f)
 {
-    y += _topExtra;
-    RenderBlock::repaintRectangle(x, y, w, h, immediate, f);
+    r.setY(r.y() + _topExtra);
+    RenderBlock::computeAbsoluteRepaintRect(r, f);
 }
 
 bool RenderTableCell::absolutePosition(int &xPos, int &yPos, bool f)
Index: khtml/rendering/render_table.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_table.h,v
retrieving revision 1.24
diff -u -p -r1.24 khtml/rendering/render_table.h
--- khtml/rendering/render_table.h	2003/08/08 22:26:08	1.24
+++ khtml/rendering/render_table.h	2003/09/26 00:50:19
@@ -280,7 +280,7 @@ public:
     virtual void position(int, int, int, int, int, bool, bool, int) {}
 
     virtual void layout();
-    virtual void repaint(bool immediate=false);
+    virtual QRect getAbsoluteRepaintRect();
     
     RenderTable *table() const { return static_cast<RenderTable *>(parent()->parent()); }
     RenderTableSection *section() const { return static_cast<RenderTableSection *>(parent()); }
@@ -341,7 +341,7 @@ public:
     // lie position to outside observers
     virtual int yPos() const { return m_y + _topExtra; }
 
-    virtual void repaintRectangle(int x, int y, int w, int h, bool immediate = false, bool f=false);
+    virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
     virtual bool absolutePosition(int &xPos, int &yPos, bool f = false);
 
     virtual short baselinePosition( bool = false ) const;
Index: khtml/xml/dom_nodeimpl.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/xml/dom_nodeimpl.cpp,v
retrieving revision 1.37
diff -u -p -r1.37 khtml/xml/dom_nodeimpl.cpp
--- khtml/xml/dom_nodeimpl.cpp	2003/09/19 23:55:42	1.37
+++ khtml/xml/dom_nodeimpl.cpp	2003/09/26 00:50:20
@@ -1228,14 +1228,8 @@ NodeImpl *NodeBaseImpl::insertBefore ( N
 
         // Add child to the rendering tree
         // ### should we detach() it first if it's already attached?
-        if (attached() && !child->attached()) {
+        if (attached() && !child->attached())
             child->attach();
-            // This is extremely important, as otherwise a fresh layout
-            // isn't scheduled, and you end up with stale data (especially
-            // with inline runs of text). -dwh
-            if (child->renderer())
-                child->renderer()->setNeedsLayout(true);
-        }
 
         // Dispatch the mutation events
         dispatchChildInsertedEvents(child,exceptioncode);
@@ -1302,14 +1296,8 @@ NodeImpl *NodeBaseImpl::replaceChild ( N
 
         // Add child to the rendering tree
         // ### should we detach() it first if it's already attached?
-        if (attached() && !child->attached()) {
+        if (attached() && !child->attached())
             child->attach();
-            // This is extremely important, as otherwise a fresh layout
-            // isn't scheduled, and you end up with stale data (especially
-            // with inline runs of text). -dwh
-            if (child->renderer())
-                child->renderer()->setNeedsLayout(true);
-        }
 
         // Dispatch the mutation events
         dispatchChildInsertedEvents(child,exceptioncode);
@@ -1455,14 +1443,8 @@ NodeImpl *NodeBaseImpl::appendChild ( No
 
         // Add child to the rendering tree
         // ### should we detach() it first if it's already attached?
-        if (attached() && !child->attached()) {
+        if (attached() && !child->attached())
             child->attach();
-            // This is extremely important, as otherwise a fresh layout
-            // isn't scheduled, and you end up with stale data (especially
-            // with inline runs of text). -dwh
-            if (child->renderer())
-                child->renderer()->setNeedsLayout(true);
-        }
           
         // Dispatch the mutation events
         dispatchChildInsertedEvents(child,exceptioncode);
Index: kwq/KWQKHTMLPart.mm
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/kwq/KWQKHTMLPart.mm,v
retrieving revision 1.400
diff -u -p -r1.400 kwq/KWQKHTMLPart.mm
--- kwq/KWQKHTMLPart.mm	2003/09/25 16:51:11	1.400
+++ kwq/KWQKHTMLPart.mm	2003/09/26 00:50:20
@@ -1577,10 +1577,8 @@ void KWQKHTMLPart::khtmlMouseReleaseEven
 
 void KWQKHTMLPart::clearTimers(KHTMLView *view)
 {
-    if (view) {
+    if (view)
         view->unscheduleRelayout();
-        view->unscheduleRepaint();
-    }
 }
 
 void KWQKHTMLPart::clearTimers()
Index: kwq/KWQRenderTreeDebug.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/kwq/KWQRenderTreeDebug.cpp,v
retrieving revision 1.14
diff -u -p -r1.14 kwq/KWQRenderTreeDebug.cpp
--- kwq/KWQRenderTreeDebug.cpp	2003/09/25 16:51:11	1.14
+++ kwq/KWQRenderTreeDebug.cpp	2003/09/26 00:50:20
@@ -147,6 +147,7 @@ static void write(QTextStream &ts, const
         if (view) {
             RenderObject *root = KWQ(view->part())->renderer();
             if (root) {
+	        root->layoutIfNeeded();
                 RenderLayer* l = root->layer();
                 if (l)
                     writeLayers(ts, l, l, QRect(l->xPos(), l->yPos(), l->width(), l->height()), indent+1);
@@ -210,12 +211,13 @@ static void writeLayers(QTextStream &ts,
     }
 }
 
-QString externalRepresentation(const RenderObject *o)
+QString externalRepresentation(RenderObject *o)
 {
     QString s;
     {
         QTextStream ts(&s);
         if (o) {
+	    o->layoutIfNeeded();
             RenderLayer* l = o->layer();
             if (l)
                 writeLayers(ts, l, l, QRect(l->xPos(), l->yPos(), l->width(), l->height()));
Index: kwq/KWQRenderTreeDebug.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/kwq/KWQRenderTreeDebug.h,v
retrieving revision 1.2
diff -u -p -r1.2 kwq/KWQRenderTreeDebug.h
--- kwq/KWQRenderTreeDebug.h	2003/02/21 23:14:32	1.2
+++ kwq/KWQRenderTreeDebug.h	2003/09/26 00:50:20
@@ -29,4 +29,4 @@ namespace khtml {
     class RenderObject;
 }
 
-QString externalRepresentation(const khtml::RenderObject *);
+QString externalRepresentation(khtml::RenderObject *);
-------------- next part --------------


dave


More information about the Khtml-devel mailing list