Fix for 3975039, scrolling is slow in huge RSS views. Optimize the calculation...
authorhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Feb 2005 17:33:10 +0000 (17:33 +0000)
committerhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Feb 2005 17:33:10 +0000 (17:33 +0000)
layers.  Also optimize layer movement when scrolling overflow sections.

        Reviewed by darin

        * khtml/rendering/render_layer.cpp:
        (throw):
        (ClipRects::operator delete):
        (ClipRects::detach):
        (RenderLayer::RenderLayer):
        (RenderLayer::~RenderLayer):
        (RenderLayer::updateLayerPosition):
        (RenderLayer::removeOnlyThisLayer):
        (RenderLayer::insertOnlyThisLayer):
        (RenderLayer::scrollToOffset):
        (RenderLayer::hitTest):
        (RenderLayer::calculateClipRects):
        (RenderLayer::calculateRects):
        (RenderLayer::containsPoint):
        (RenderLayer::clearClipRects):
        (RenderLayer::clearClipRect):
        * khtml/rendering/render_layer.h:
        (khtml::ClipRects::m_refCnt):
        (khtml::ClipRects::overflowClipRect):
        (khtml::ClipRects::fixedClipRect):
        (khtml::ClipRects::posClipRect):
        (khtml::ClipRects::ref):
        (khtml::ClipRects::deref):
        (khtml::RenderLayer::clipRects):
        * khtml/rendering/render_object.cpp:
        (RenderObject::setStyle):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8692 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog-2005-08-23
WebCore/khtml/rendering/render_layer.cpp
WebCore/khtml/rendering/render_layer.h
WebCore/khtml/rendering/render_object.cpp

index ebe73776f409b796b64524a68e5eacd521a082e9..ef9b8ec0420cca770b5e617f05c98d411bc10e91 100644 (file)
@@ -1,3 +1,37 @@
+2005-02-25  David Hyatt  <hyatt@apple.com>
+
+       Fix for 3975039, scrolling is slow in huge RSS views.  Optimize the calculation of clip rects for overflow:hidden
+       layers.  Also optimize layer movement when scrolling overflow sections.
+       
+        Reviewed by darin
+
+        * khtml/rendering/render_layer.cpp:
+        (throw):
+        (ClipRects::operator delete):
+        (ClipRects::detach):
+        (RenderLayer::RenderLayer):
+        (RenderLayer::~RenderLayer):
+        (RenderLayer::updateLayerPosition):
+        (RenderLayer::removeOnlyThisLayer):
+        (RenderLayer::insertOnlyThisLayer):
+        (RenderLayer::scrollToOffset):
+        (RenderLayer::hitTest):
+        (RenderLayer::calculateClipRects):
+        (RenderLayer::calculateRects):
+        (RenderLayer::containsPoint):
+        (RenderLayer::clearClipRects):
+        (RenderLayer::clearClipRect):
+        * khtml/rendering/render_layer.h:
+        (khtml::ClipRects::m_refCnt):
+        (khtml::ClipRects::overflowClipRect):
+        (khtml::ClipRects::fixedClipRect):
+        (khtml::ClipRects::posClipRect):
+        (khtml::ClipRects::ref):
+        (khtml::ClipRects::deref):
+        (khtml::RenderLayer::clipRects):
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::setStyle):
+
 2005-02-24  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Darin and Dave a while ago.
index 505bb8a93a86b9453a074d2486677eb2480cd915..39ee3fb10397887f2cad2962ace1aad843f4c677 100644 (file)
@@ -70,6 +70,25 @@ QScrollBar* RenderLayer::gScrollBar = 0;
 static bool inRenderLayerDetach;
 #endif
 
+void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+    return renderArena->allocate(sz);
+}
+
+void ClipRects::operator delete(void* ptr, size_t sz)
+{
+    // Stash size where detach can find it.
+    *(size_t *)ptr = sz;
+}
+
+void ClipRects::detach(RenderArena* renderArena)
+{
+    delete this;
+    
+    // Recover the size left there for us by operator delete and free the memory.
+    renderArena->free(*(size_t *)this, this);
+}
+
 void
 RenderScrollMediator::slotValueChanged(int val)
 {
@@ -98,6 +117,7 @@ m_vBar( 0 ),
 m_scrollMediator( 0 ),
 m_posZOrderList( 0 ),
 m_negZOrderList( 0 ),
+m_clipRects( 0 ) ,
 m_scrollDimensionsDirty( true ),
 m_zOrderListsDirty( true ),
 m_usedTransparency( false ),
@@ -115,6 +135,9 @@ RenderLayer::~RenderLayer()
     delete m_posZOrderList;
     delete m_negZOrderList;
     delete m_marquee;
+    
+    // Make sure we have no lingering clip rects.
+    clearClipRect();
 }
 
 void RenderLayer::computeRepaintRects()
@@ -160,6 +183,9 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
 
 void RenderLayer::updateLayerPosition()
 {
+    // Clear our cached clip rect information.
+    clearClipRect();
+
     // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
     // don't need to ever update our layer position here.
     if (renderer()->isCanvas())
@@ -378,6 +404,9 @@ void RenderLayer::removeOnlyThisLayer()
     if (!m_parent)
         return;
     
+    // Dirty the clip rects.
+    clearClipRects();
+
     // Remove us from the parent.
     RenderLayer* parent = m_parent;
     RenderLayer* nextSib = nextSibling();
@@ -409,6 +438,9 @@ void RenderLayer::insertOnlyThisLayer()
     // Remove all descendant layers from the hierarchy and add them to the new position.
     for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
         curr->moveLayers(m_parent, this);
+        
+    // Clear out all the clip rects.
+    clearClipRects();
 }
 
 void 
@@ -481,7 +513,7 @@ RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
 
     // Update the positions of our child layers.
     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
-        child->updateLayerPositions();
+        child->updateLayerPositions(false, false);
     
 #if APPLE_CHANGES
     // Move our widgets.
@@ -959,7 +991,7 @@ RenderLayer::hitTest(RenderObject::NodeInfo& info, int x, int y)
 
     // Next set up the correct :hover/:active state along the new chain.
     updateHoverActiveState(info);
-
+    
     // Now return whether we were inside this layer (this will always be true for the root
     // layer).
     return insideLayer;
@@ -1044,11 +1076,25 @@ RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
     return 0;
 }
 
-void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
-                                     QRect& posClipRect, QRect& fixedClipRect)
+void RenderLayer::calculateClipRects(const RenderLayer* rootLayer)
 {
-    if (parent())
-        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
+    if (m_clipRects)
+        return; // We have the correct cached value.
+
+    if (!parent()) {
+        // The root layer's clip rect is always just its dimensions.
+        m_clipRects = new (m_object->renderArena()) ClipRects(QRect(0,0,width(),height()));
+        m_clipRects->ref();
+        return;
+    }
+
+    // Ensure that our parent's clip has been calculated so that we can examine the values.
+    parent()->calculateClipRects(rootLayer);
+
+    // Set up our three rects to initially match the parent rects.
+    QRect posClipRect(parent()->clipRects()->posClipRect());
+    QRect overflowClipRect(parent()->clipRects()->overflowClipRect());
+    QRect fixedClipRect(parent()->clipRects()->fixedClipRect());
 
     // A fixed object is essentially the root of its containing block hierarchy, so when
     // we encounter such an object, we reset our clip rects to the fixedClipRect.
@@ -1079,25 +1125,35 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overfl
             fixedClipRect = fixedClipRect.intersect(newPosClip);
         }
     }
+    
+    // If our clip rects match our parent's clip, then we can just share its data structure and
+    // ref count.
+    if (posClipRect == parent()->clipRects()->posClipRect() &&
+        overflowClipRect == parent()->clipRects()->overflowClipRect() &&
+        fixedClipRect == parent()->clipRects()->fixedClipRect())
+        m_clipRects = parent()->clipRects();
+    else
+        m_clipRects = new (m_object->renderArena()) ClipRects(overflowClipRect, fixedClipRect, posClipRect);
+    m_clipRects->ref();
 }
 
 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
                                  QRect& backgroundRect, QRect& foregroundRect)
 {
-    QRect overflowClipRect = paintDirtyRect;
-    QRect posClipRect = paintDirtyRect;
-    QRect fixedClipRect = paintDirtyRect;
-    if (parent())
-        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
-
+    if (parent()) {
+        parent()->calculateClipRects(rootLayer);
+        backgroundRect = m_object->style()->position() == FIXED ? parent()->clipRects()->fixedClipRect() :
+                         (m_object->isPositioned() ? parent()->clipRects()->posClipRect() : 
+                                                     parent()->clipRects()->overflowClipRect());
+        backgroundRect = backgroundRect.intersect(paintDirtyRect);
+    } else
+        backgroundRect = paintDirtyRect;
+    foregroundRect = backgroundRect;
+    
     int x = 0;
     int y = 0;
     convertToLayerCoords(rootLayer, x, y);
     layerBounds = QRect(x,y,width(),height());
-
-    backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect :
-        (m_object->isPositioned() ? posClipRect : overflowClipRect);
-    foregroundRect = backgroundRect;
     
     // Update the clip rects that will be passed to child layers.
     if (m_object->hasOverflowClip() || m_object->hasClip()) {
@@ -1143,6 +1199,25 @@ bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
     return mustExamineRenderer(renderer()) || damageRect.contains(x, y);
 }
 
+void RenderLayer::clearClipRects()
+{
+    if (!m_clipRects)
+        return;
+
+    clearClipRect();
+    
+    for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
+        l->clearClipRects();
+}
+
+void RenderLayer::clearClipRect()
+{
+    if (m_clipRects) {
+        m_clipRects->deref(m_object->renderArena());
+        m_clipRects = 0;
+    }
+}
+
 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
 // content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
 static RenderObject* hoverAncestor(RenderObject* obj)
index 6b15d9bd63d5a4fd44979b2a3cd020caeddeb5bc..1a185827aec89e87a25bf74bf3e8a3c2c42ce028 100644 (file)
@@ -75,6 +75,39 @@ private:
     RenderLayer* m_layer;
 };
 
+class ClipRects
+{
+public:
+    ClipRects(const QRect& r) :m_overflowClipRect(r), m_fixedClipRect(r), m_posClipRect(r), m_refCnt(0) {}
+    ClipRects(const QRect& o, const QRect& f, const QRect& p)
+      :m_overflowClipRect(o), m_fixedClipRect(f), m_posClipRect(p), m_refCnt(0) {}
+
+    const QRect& overflowClipRect() { return m_overflowClipRect; }
+    const QRect& fixedClipRect() { return m_fixedClipRect; }
+    const QRect& posClipRect() { return m_posClipRect; }
+
+    void ref() { m_refCnt++; }
+    void deref(RenderArena* renderArena) { if (--m_refCnt == 0) detach(renderArena); }
+    
+    void detach(RenderArena* renderArena);
+
+    // Overloaded new operator.
+    void* operator new(size_t sz, RenderArena* renderArena) throw();    
+
+    // Overridden to prevent the normal delete from being called.
+    void operator delete(void* ptr, size_t sz);
+        
+private:
+    // The normal operator new is disallowed on all render objects.
+    void* operator new(size_t sz) throw();
+
+private:
+    QRect m_overflowClipRect;
+    QRect m_fixedClipRect;
+    QRect m_posClipRect;
+    uint m_refCnt;
+};
+
 // This class handles the auto-scrolling of layers with overflow: marquee.
 class Marquee: public QObject
 {
@@ -211,6 +244,9 @@ public:
     void relativePositionOffset(int& relX, int& relY) {
         relX += m_relX; relY += m_relY;
     }
+     
+    void clearClipRects();
+    void clearClipRect();
 
     // Get the enclosing stacking context for this layer.  A stacking context is a layer
     // that has a non-auto z-index.
@@ -243,8 +279,8 @@ public:
     // for painting/event handling.
     void calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
                         QRect& backgroundRect, QRect& foregroundRect);
-    void calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
-                            QRect& posClipRect, QRect& fixedClipRect);
+    void calculateClipRects(const RenderLayer* rootLayer);
+    ClipRects* clipRects() const { return m_clipRects; }
 
     bool intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const;
     bool containsPoint(int x, int y, const QRect& damageRect) const;
@@ -280,7 +316,7 @@ private:
     RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
                               int x, int y, const QRect& hitTestRect);
     void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0);
-    
+
 protected:   
     RenderObject* m_object;
     
@@ -326,8 +362,11 @@ protected:
     QPtrVector<RenderLayer>* m_posZOrderList;
     QPtrVector<RenderLayer>* m_negZOrderList;
     
+    ClipRects* m_clipRects;      // Cached clip rects used when painting and hit testing.
+
     bool m_scrollDimensionsDirty : 1;
     bool m_zOrderListsDirty : 1;
+
 #if APPLE_CHANGES
     bool m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether
                                  // we ended up painting this layer or any descendants (and therefore need to
index e8382c58917d5a495094d8d01c0f24fb677b931d..c03cae6d73fe2b5005bb2b103dd1a9a8e5d61c54 100644 (file)
@@ -1555,8 +1555,11 @@ void RenderObject::setStyle(RenderStyle *style)
         else if (m_parent && !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.
-            if (d == RenderStyle::RepaintLayer)
+            if (d == RenderStyle::RepaintLayer) {
                 layer()->repaintIncludingDescendants();
+                if (!(m_style->clip() == style->clip()))
+                    layer()->clearClipRects();
+            }
             else if (d == RenderStyle::Repaint)
                 repaint();
         }