2009-04-07 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2009 22:06:19 +0000 (22:06 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2009 22:06:19 +0000 (22:06 +0000)
        Reviewed by Dan Bernstein

        https://bugs.webkit.org/show_bug.cgi?id=25082

        Clean up repaint logic when RenderLayers become and stop being composited.

        * rendering/RenderLayer.h:
        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::rendererContentChanged):
        (WebCore::RenderLayer::repaintIncludingNonCompositingDescendants):
        New compositing-only method that repaints a layer and all its non-composited descendants.
        Takes a repaintContainer for performance; all the repaints necessarily share the same
        repaintContainer.

        * rendering/RenderLayerCompositor.h:
        * rendering/RenderLayerCompositor.cpp:
        (WebCore::RenderLayerCompositor::updateLayerCompositingState):
        Rather than use calculateCompositedBounds() to compute the repaint rect (which gave
        the wrong answer when the composited layer tree was in flux), use the new
        repaintOnCompositingChange() method.

        (WebCore::RenderLayerCompositor::repaintOnCompositingChange):
        Call repaintIncludingNonCompositingDescendants(), and if necessary make sure
        that the view/layer drawing synchronization happens.

        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
        Do a repaintOnCompositingChange() when a layer is going to be composited. This is
        a good place because we haven't started to change the compositing tree.

        (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree):
        After we've finished updating all the descendant layers, we can do a repaint for
        layers that ceased compositing.

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

WebCore/ChangeLog
WebCore/rendering/RenderLayer.cpp
WebCore/rendering/RenderLayer.h
WebCore/rendering/RenderLayerCompositor.cpp
WebCore/rendering/RenderLayerCompositor.h

index 06698c7..9a858ae 100644 (file)
 
 2009-04-07  Simon Fraser  <simon.fraser@apple.com>
 
+        Reviewed by Dan Bernstein
+
+        https://bugs.webkit.org/show_bug.cgi?id=25082
+        
+        Clean up repaint logic when RenderLayers become and stop being composited.
+
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::rendererContentChanged):
+        (WebCore::RenderLayer::repaintIncludingNonCompositingDescendants):
+        New compositing-only method that repaints a layer and all its non-composited descendants.
+        Takes a repaintContainer for performance; all the repaints necessarily share the same
+        repaintContainer.
+
+        * rendering/RenderLayerCompositor.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::updateLayerCompositingState):
+        Rather than use calculateCompositedBounds() to compute the repaint rect (which gave
+        the wrong answer when the composited layer tree was in flux), use the new
+        repaintOnCompositingChange() method.
+        
+        (WebCore::RenderLayerCompositor::repaintOnCompositingChange):
+        Call repaintIncludingNonCompositingDescendants(), and if necessary make sure
+        that the view/layer drawing synchronization happens.
+        
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
+        Do a repaintOnCompositingChange() when a layer is going to be composited. This is
+        a good place because we haven't started to change the compositing tree.
+        
+        (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree):
+        After we've finished updating all the descendant layers, we can do a repaint for
+        layers that ceased compositing.
+
+2009-04-07  Simon Fraser  <simon.fraser@apple.com>
+
         Reviewed by Dave Hyatt
         
         https://bugs.webkit.org/show_bug.cgi?id=25069
index 08f169d..e5b302c 100644 (file)
@@ -225,12 +225,12 @@ RenderLayerCompositor* RenderLayer::compositor() const
     ASSERT(renderer()->view());
     return renderer()->view()->compositor();
 }
-    
+
 void RenderLayer::rendererContentChanged()
 {
     if (m_backing)
         m_backing->rendererContentChanged();
-}    
+}
 #endif // USE(ACCELERATED_COMPOSITING)
 
 void RenderLayer::setStaticY(int staticY)
@@ -3008,6 +3008,17 @@ void RenderLayer::setBackingNeedsRepaintInRect(const IntRect& r)
     } else
         backing()->setContentsNeedDisplayInRect(r);
 }
+
+// Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
+void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer)
+{
+    renderer()->repaintUsingContainer(repaintContainer, renderer()->clippedOverflowRectForRepaint(repaintContainer));
+
+    for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
+        if (!curr->isComposited())
+            curr->repaintIncludingNonCompositingDescendants(repaintContainer);
+    }
+}
 #endif
 
 bool RenderLayer::shouldBeNormalFlowOnly() const
index f13edbb..25cabb0 100644 (file)
@@ -188,6 +188,7 @@ public:
     // if layer compositing is being used,
     void setBackingNeedsRepaint();
     void setBackingNeedsRepaintInRect(const IntRect& r); // r is in the coordinate space of the layer's render object
+    void repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer);
 #endif
 
     void styleChanged(StyleDifference, const RenderStyle*);
index 09d435e..75d0dd8 100644 (file)
@@ -174,20 +174,18 @@ void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
     ASSERT(updateRoot || !m_compositingLayersNeedUpdate);
 }
 
-bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer)
+bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, CompositingChangeRepaint shouldRepaint)
 {
     bool needsLayer = needsToBeComposited(layer);
     bool layerChanged = false;
 
-    RenderBoxModelObject* repaintContainer = 0;
-    IntRect repaintRect;
-
     if (needsLayer) {
         enableCompositingMode();
         if (!layer->backing()) {
-            // Get the repaint container before we make backing for this layer
-            repaintContainer = layer->renderer()->containerForRepaint();
-            repaintRect = calculateCompositedBounds(layer, repaintContainer ? repaintContainer->layer() : layer->root());
+
+            // If we need to repaint, do so before making backing
+            if (shouldRepaint == CompositingChangeRepaintNow)
+                repaintOnCompositingChange(layer);
 
             layer->ensureBacking();
             layerChanged = true;
@@ -195,25 +193,14 @@ bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer)
     } else {
         if (layer->backing()) {
             layer->clearBacking();
-            // Get the repaint container now that we've cleared the backing
-            repaintContainer = layer->renderer()->containerForRepaint();
-            repaintRect = calculateCompositedBounds(layer, repaintContainer ? repaintContainer->layer() : layer->root());
             layerChanged = true;
+
+            // If we need to repaint, do so now that we've removed the backing
+            if (shouldRepaint == CompositingChangeRepaintNow)
+                repaintOnCompositingChange(layer);
         }
     }
     
-    if (layerChanged) {
-        // Invalidate the destination into which this layer used to render.
-        layer->renderer()->repaintUsingContainer(repaintContainer, repaintRect);
-
-        if (!repaintContainer || repaintContainer == m_renderView) {
-            // The contents of this layer may be moving between the window
-            // and a GraphicsLayer, so we need to make sure the window system
-            // synchronizes those changes on the screen.
-            m_renderView->frameView()->setNeedsOneShotDrawingSynchronization();
-        }
-    }
-
     // See if we need content or clipping layers. Methods called here should assume
     // that the compositing state of descendant layers has not been updated yet.
     if (layer->backing() && layer->backing()->updateGraphicsLayerConfiguration())
@@ -222,6 +209,21 @@ bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer)
     return layerChanged;
 }
 
+void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer)
+{
+    RenderBoxModelObject* repaintContainer = layer->renderer()->containerForRepaint();
+    if (!repaintContainer)
+        repaintContainer = m_renderView;
+
+    layer->repaintIncludingNonCompositingDescendants(repaintContainer);
+    if (repaintContainer == m_renderView) {
+        // The contents of this layer may be moving between the window
+        // and a GraphicsLayer, so we need to make sure the window system
+        // synchronizes those changes on the screen.
+        m_renderView->frameView()->setNeedsOneShotDrawingSynchronization();
+    }
+}
+
 // The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant
 // RenderLayers that are rendered by the composited RenderLayer.
 IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox)
@@ -340,11 +342,15 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, s
     layer->setHasCompositingDescendant(false);
     layer->setMustOverlayCompositedLayers(ioCompState.m_subtreeIsCompositing);
     
-    const bool isCompositingLayer = needsToBeComposited(layer);
-    ioCompState.m_subtreeIsCompositing = isCompositingLayer;
+    const bool willBeComposited = needsToBeComposited(layer);
+    // If we are going to become composited, repaint the old rendering destination
+    if (!layer->isComposited() && willBeComposited)
+        repaintOnCompositingChange(layer);
+
+    ioCompState.m_subtreeIsCompositing = willBeComposited;
 
     CompositingState childState = ioCompState;
-    if (isCompositingLayer)
+    if (willBeComposited)
         childState.m_compositingAncestor = layer;
 
     // The children of this stacking context don't need to composite, unless there is
@@ -447,10 +453,12 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer)
 
 void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState)
 {
+    bool wasComposited = layer->isComposited();
+
     // Make the layer compositing if necessary, and set up clipping and content layers.
     // Note that we can only do work here that is independent of whether the descendant layers
-    // have been processed.
-    updateLayerCompositingState(layer);
+    // have been processed. computeCompositingRequirements() will already have done the repaint if necessary.
+    updateLayerCompositingState(layer, CompositingChangeWillRepaintLater);
 
     // host the document layer in the RenderView's root layer
     if (layer->isRootLayer())
@@ -524,6 +532,10 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, stru
     if (layerBacking) {
         // Do work here that requires that we've processed all of the descendant layers
         layerBacking->updateGraphicsLayerGeometry();
+    } else if (wasComposited) {
+        // We stopped being a compositing layer. Now that our descendants have been udated, we can
+        // repaint our new rendering destination.
+        repaintOnCompositingChange(layer);
     }
 }
 
index d926d01..76cb35f 100644 (file)
@@ -62,8 +62,9 @@ public:
     // Rebuild the tree of compositing layers
     void updateCompositingLayers(RenderLayer* updateRoot = 0);
 
-    // Update the compositing state of the given layer. Returns true if that state changed
-    bool updateLayerCompositingState(RenderLayer*);
+    // Update the compositing state of the given layer. Returns true if that state changed.
+    enum CompositingChangeRepaint { CompositingChangeRepaintNow, CompositingChangeWillRepaintLater };
+    bool updateLayerCompositingState(RenderLayer*, CompositingChangeRepaint = CompositingChangeRepaintNow);
 
     // Whether layer's backing needs a graphics layer to do clipping by an ancestor (non-stacking-context parent with overflow).
     bool clippedByAncestor(RenderLayer*) const;
@@ -75,6 +76,9 @@ public:
     // Return the bounding box required for compositing layer and its childern, relative to ancestorLayer.
     // If layerBoundingBox is not 0, on return it contains the bounding box of this layer only.
     IntRect calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox = 0);
+
+    // Repaint the appropriate layers when the given RenderLayer starts or stops being composited.
+    void repaintOnCompositingChange(RenderLayer*);
     
     // Notify us that a layer has been added or removed
     void layerWasAdded(RenderLayer* parent, RenderLayer* child);