Add a way to update GraphicsLayerCA visibleRects without having to do a flush
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Mar 2013 05:18:42 +0000 (05:18 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Mar 2013 05:18:42 +0000 (05:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=113459

Reviewed by Tim Horton.

Some platforms need to update TiledBacking visible rects from
outside of WebKit, for example if they use delegated scrolling.
They want to avoid forcing layout to be up-to-date when doing this.

Currently, updating the visibleRect happens when the GraphicsLayerCA
layer are being flushed, but that makes some assumptions about
layout being up-to-date.

To fix this, add a light-weight pass over the layer tree that
uses TransformState to compute the visibleRect for each
layer, and only if the visibleRect would cause a change in the
tiles in a TiledBacking trigger a layer flush.

* platform/graphics/GraphicsLayer.h:
(WebCore::GraphicsLayer::recomputeVisibleRects):
* platform/graphics/TiledBacking.h:
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::recursiveComputeVisibleRect):
(WebCore::GraphicsLayerCA::recomputeVisibleRects):
(WebCore::GraphicsLayerCA::computeVisibleRect):
* platform/graphics/ca/GraphicsLayerCA.h:
* platform/graphics/ca/mac/TileController.h:
* platform/graphics/ca/mac/TileController.mm:
(WebCore::TileController::tilesWouldChangeForVisibleRect):
(WebCore::TileController::computeTileCoverageRect):
(WebCore::TileController::revalidateTiles):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/platform/graphics/TiledBacking.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
Source/WebCore/platform/graphics/ca/mac/TileController.h
Source/WebCore/platform/graphics/ca/mac/TileController.mm

index 1bc4d80..6d559f7 100644 (file)
@@ -1,3 +1,37 @@
+2013-03-27  Simon Fraser  <simon.fraser@apple.com>
+
+        Add a way to update GraphicsLayerCA visibleRects without having to do a flush
+        https://bugs.webkit.org/show_bug.cgi?id=113459
+
+        Reviewed by Tim Horton.
+        
+        Some platforms need to update TiledBacking visible rects from
+        outside of WebKit, for example if they use delegated scrolling.
+        They want to avoid forcing layout to be up-to-date when doing this.
+        
+        Currently, updating the visibleRect happens when the GraphicsLayerCA
+        layer are being flushed, but that makes some assumptions about
+        layout being up-to-date.
+        
+        To fix this, add a light-weight pass over the layer tree that
+        uses TransformState to compute the visibleRect for each
+        layer, and only if the visibleRect would cause a change in the
+        tiles in a TiledBacking trigger a layer flush.
+
+        * platform/graphics/GraphicsLayer.h:
+        (WebCore::GraphicsLayer::recomputeVisibleRects):
+        * platform/graphics/TiledBacking.h:
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::recursiveComputeVisibleRect):
+        (WebCore::GraphicsLayerCA::recomputeVisibleRects):
+        (WebCore::GraphicsLayerCA::computeVisibleRect):
+        * platform/graphics/ca/GraphicsLayerCA.h:
+        * platform/graphics/ca/mac/TileController.h:
+        * platform/graphics/ca/mac/TileController.mm:
+        (WebCore::TileController::tilesWouldChangeForVisibleRect):
+        (WebCore::TileController::computeTileCoverageRect):
+        (WebCore::TileController::revalidateTiles):
+
 2013-03-27  Philip Rogers  <pdr@google.com>
 
         Rename toScriptElement -> toScriptElementIfPossible
index 8a022fb..5d347e2 100644 (file)
@@ -408,8 +408,11 @@ public:
     // and descendant layers, and this layer only.
     virtual void flushCompositingState(const FloatRect& /* clipRect */) { }
     virtual void flushCompositingStateForThisLayerOnly() { }
-    
-    // Return a string with a human readable form of the layer tree, If debug is true 
+
+    // Walk the layer tree, recomputing the visible rects of layer with TiledBacking, on platforms that use it.
+    virtual void recomputeVisibleRects(const FloatRect& /* clipRect */) { }
+
+    // Return a string with a human readable form of the layer tree, If debug is true
     // pointers for the layers and timing data will be included in the returned string.
     String layerTreeAsText(LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const;
 
index ffa9ba9..2e66f60 100644 (file)
@@ -46,6 +46,7 @@ public:
 
     virtual void setVisibleRect(const FloatRect&) = 0;
     virtual FloatRect visibleRect() const = 0;
+    virtual bool tilesWouldChangeForVisibleRect(const FloatRect&) const = 0;
 
     virtual void setExposedRect(const FloatRect&) = 0;
     virtual void setClipsToExposedRect(bool) = 0;
index e1fc505..b56d44c 100644 (file)
@@ -907,25 +907,66 @@ void GraphicsLayerCA::flushCompositingStateForThisLayerOnly()
         client()->didCommitChangesForLayer(this);
 }
 
+void GraphicsLayerCA::recursiveComputeVisibleRect(const TransformState& state)
+{
+    TransformState localState = state;
+    
+    // This may be called at times when layout has not been updated, so we want to avoid calling out to the client
+    // for animating transforms.
+    FloatRect visibleRect = computeVisibleRect(localState, 0);
+    if (visibleRect != m_visibleRect) {
+        m_visibleRect = visibleRect;
+        if (TiledBacking* tiledBacking = this->tiledBacking()) {
+            if (tiledBacking->tilesWouldChangeForVisibleRect(m_visibleRect))
+                noteLayerPropertyChanged(VisibleRectChanged);
+        }
+    }
+
+    if (m_maskLayer) {
+        GraphicsLayerCA* maskLayerCA = static_cast<GraphicsLayerCA*>(m_maskLayer);
+        maskLayerCA->recursiveComputeVisibleRect(localState);
+    }
+
+    const Vector<GraphicsLayer*>& childLayers = children();
+    size_t numChildren = childLayers.size();
+    
+    for (size_t i = 0; i < numChildren; ++i) {
+        GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+        curChild->recursiveComputeVisibleRect(localState);
+    }
+
+    if (m_replicaLayer)
+        static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveComputeVisibleRect(localState);
+}
+
+void GraphicsLayerCA::recomputeVisibleRects(const FloatRect& clipRect)
+{
+    TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
+    recursiveComputeVisibleRect(state);
+}
+
 TiledBacking* GraphicsLayerCA::tiledBacking() const
 {
     return m_layer->tiledBacking();
 }
 
-FloatRect GraphicsLayerCA::computeVisibleRect(TransformState& state) const
+FloatRect GraphicsLayerCA::computeVisibleRect(TransformState& state, ComputeVisibleRectFlags flags) const
 {
     bool preserve3D = preserves3D() || (parent() ? parent()->preserves3D() : false);
     TransformState::TransformAccumulation accumulation = preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform;
 
     TransformationMatrix layerTransform;
     FloatPoint position = m_position;
-    if (m_client)
-        m_client->customPositionForVisibleRectComputation(this, position);
+    if (client())
+        client()->customPositionForVisibleRectComputation(this, position);
 
     layerTransform.translate(position.x(), position.y());
 
     TransformationMatrix currentTransform;
-    if (client() && client()->getCurrentTransform(this, currentTransform) && !currentTransform.isIdentity()) {
+    if (!(flags & RespectAnimatingTransforms) || !client() || !client()->getCurrentTransform(this, currentTransform))
+        currentTransform = m_transform;
+    
+    if (!currentTransform.isIdentity()) {
         FloatPoint3D absoluteAnchorPoint(anchorPoint());
         absoluteAnchorPoint.scale(size().width(), size().height(), 1);
         layerTransform.translate3d(absoluteAnchorPoint.x(), absoluteAnchorPoint.y(), absoluteAnchorPoint.z());
index 2aaf6a9..7695ae5 100644 (file)
@@ -142,6 +142,9 @@ public:
     virtual void flushCompositingState(const FloatRect&);
     virtual void flushCompositingStateForThisLayerOnly();
 
+    void recursiveComputeVisibleRect(const TransformState&);
+    virtual void recomputeVisibleRects(const FloatRect& clipRect);
+
     virtual TiledBacking* tiledBacking() const OVERRIDE;
 
     bool allowTiledLayer() const { return m_allowTiledLayer; }
@@ -243,7 +246,9 @@ private:
 
     void computePixelAlignment(float pixelAlignmentScale, const FloatPoint& positionRelativeToBase,
         FloatPoint& position, FloatSize&, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset) const;
-    FloatRect computeVisibleRect(TransformState&) const;
+    enum ComputeVisibleRectFlag { RespectAnimatingTransforms = 1 << 0 };
+    typedef unsigned ComputeVisibleRectFlags;
+    FloatRect computeVisibleRect(TransformState&, ComputeVisibleRectFlags = RespectAnimatingTransforms) const;
     const FloatRect& visibleRect() const { return m_visibleRect; }
     
     FloatRect adjustTiledLayerVisibleRect(TiledBacking*, const FloatRect& oldVisibleRect, const FloatSize& oldSize) const;
index 7ad7a46..65d99b7 100644 (file)
@@ -107,6 +107,7 @@ private:
 
     // TiledBacking member functions.
     virtual void setVisibleRect(const FloatRect&) OVERRIDE;
+    virtual bool tilesWouldChangeForVisibleRect(const FloatRect&) const OVERRIDE;
     virtual void setExposedRect(const FloatRect&) OVERRIDE;
     virtual bool clipsToExposedRect() OVERRIDE { return m_clipsToExposedRect; }
     virtual void setClipsToExposedRect(bool) OVERRIDE;
@@ -133,7 +134,7 @@ private:
     IntRect rectForTileIndex(const TileIndex&) const;
     void getTileIndexRangeForRect(const IntRect&, TileIndex& topLeft, TileIndex& bottomRight) const;
 
-    FloatRect computeTileCoverageRect(const FloatRect& previousVisibleRect) const;
+    FloatRect computeTileCoverageRect(const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect) const;
     IntSize tileSizeForCoverageRect(const FloatRect&) const;
 
     void scheduleTileRevalidation(double interval);
index 8643c9e..0ad1239 100644 (file)
@@ -306,6 +306,35 @@ void TileController::setVisibleRect(const FloatRect& visibleRect)
     revalidateTiles();
 }
 
+bool TileController::tilesWouldChangeForVisibleRect(const FloatRect& newVisibleRect) const
+{
+    FloatRect visibleRect = newVisibleRect;
+
+    if (m_clipsToExposedRect)
+        visibleRect.intersect(m_exposedRect);
+
+    if (visibleRect.isEmpty() || bounds().isEmpty())
+        return false;
+        
+    FloatRect currentTileCoverageRect = computeTileCoverageRect(m_visibleRect, newVisibleRect);
+    FloatRect scaledRect(currentTileCoverageRect);
+    scaledRect.scale(m_scale);
+    IntRect currentCoverageRectInTileCoords(enclosingIntRect(scaledRect));
+
+    IntSize newTileSize = tileSizeForCoverageRect(currentTileCoverageRect);
+    bool tileSizeChanged = newTileSize != m_tileSize;
+    if (tileSizeChanged)
+        return true;
+
+    TileIndex topLeft;
+    TileIndex bottomRight;
+    getTileIndexRangeForRect(currentCoverageRectInTileCoords, topLeft, bottomRight);
+
+    IntRect coverageRect = rectForTileIndex(topLeft);
+    coverageRect.unite(rectForTileIndex(bottomRight));
+    return coverageRect != m_primaryTileCoverageRect;
+}
+
 void TileController::setExposedRect(const FloatRect& exposedRect)
 {
     if (m_exposedRect == exposedRect)
@@ -417,9 +446,9 @@ void TileController::getTileIndexRangeForRect(const IntRect& rect, TileIndex& to
     bottomRight.setY(max(bottomYRatio - 1, 0));
 }
 
-FloatRect TileController::computeTileCoverageRect(const FloatRect& previousVisibleRect) const
+FloatRect TileController::computeTileCoverageRect(const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect) const
 {
-    FloatRect visibleRect = m_visibleRect;
+    FloatRect visibleRect = currentVisibleRect;
 
     if (m_clipsToExposedRect)
         visibleRect.intersect(m_exposedRect);
@@ -591,7 +620,7 @@ void TileController::revalidateTiles(TileValidationPolicyFlags foregroundValidat
     
     TileValidationPolicyFlags validationPolicy = m_isInWindow ? foregroundValidationPolicy : backgroundValidationPolicy;
     
-    FloatRect tileCoverageRect = computeTileCoverageRect(m_visibleRectAtLastRevalidate);
+    FloatRect tileCoverageRect = computeTileCoverageRect(m_visibleRectAtLastRevalidate, m_visibleRect);
     FloatRect scaledRect(tileCoverageRect);
     scaledRect.scale(m_scale);
     IntRect coverageRectInTileCoords(enclosingIntRect(scaledRect));