Cache absolute clip rects on RenderLayer for compositing overlap testing
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 May 2012 21:17:33 +0000 (21:17 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 May 2012 21:17:33 +0000 (21:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=87212

Reviewed by Dave Hyatt.

Enhance the cache of ClipRects on RenderLayers to store three
different types of ClipRects, rather than just one.

We need to compute clip rects relative to different layers
for different purposes. For painting, we compute relative to
the compositing layer which is acting as a painting root.
For hit testing, we compute relative to the root, except
for transformed layers. For composting overlap testing, we
compute relative to the root ("absolute"). At other times, we do one-off
computation which we never want to cache ("temporary clip rects").

This change allows us to cache rects for hit testing, and for
compositing overlap testing. This has huge performance benefits
on some pages (bug 84410).

This change also makes ClipRects not arena-allocated, so we
can use RefPtr<ClipRect>.

No testable behavior change.

* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::willBeDestroyed): No need for the
explicit clipRects teardown, since clipRects don't need a live
RenderObject for arena-based destruction.

* rendering/RenderLayer.cpp: Remove arena-related new and delete.
(WebCore::RenderLayer::RenderLayer): No need to explicitly initialize m_clipRects,
since it's an OwnPtr now.
(WebCore::RenderLayer::~RenderLayer): No explicit clipRect teardown required.
(WebCore::RenderLayer::clippingRootForPainting): Renamed to make its purpose
more obvious.
(WebCore::RenderLayer::paintLayer): Use the TemporaryClipRects type when necessary.
(WebCore::RenderLayer::paintLayerContents): Ditto
(WebCore::RenderLayer::hitTestLayer): No longer need to use temporary clipRects when
hit testing since we cache clip rects for hit testing.
(WebCore::RenderLayer::updateClipRects): Take a ClipRectsType and pass it through.
(WebCore::RenderLayer::calculateClipRects): Ditto
(WebCore::RenderLayer::parentClipRects): Ditto
(WebCore::RenderLayer::backgroundClipRect): Ditto
(WebCore::RenderLayer::calculateRects): Take ClipRectsType, which obviates temporaryClipRects.
(WebCore::RenderLayer::childrenClipRect): Use clippingRootForPainting().
(WebCore::RenderLayer::selfClipRect): Ditto
(WebCore::RenderLayer::localClipRect): Ditto
(WebCore::RenderLayer::clearClipRectsIncludingDescendants): Take a type of clip rect to clear
(include all). Allows us to just clear painting clip rects.
(WebCore::RenderLayer::clearClipRects):

* rendering/RenderLayer.h:
(WebCore::ClipRects::create): We don't use RefCounted<> in order to use a bit in
the refCount for a flag. Add create() method.
(WebCore::ClipRects::deref): No longer arena-allocated.
(WebCore::ClipRectsCache::ClipRectsCache): Struct that holds a small
array of the 3 types of clipRects (and, in debug, the layer relative
to which they were computed).
(WebCore::RenderLayer::clipRects):

* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateCompositedBounds): Use AbsoluteClipRects; rootLayer
is always the RenderView's layer here.
(WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): Use TemporaryClipRects.
(WebCore::RenderLayerBacking::setRequiresOwnBackingStore): When this variable changes,
we need to invalidate painting clipRects, since it affects the ancestor relative to which
those rects are computed.

* rendering/RenderLayerBacking.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::updateBacking): When the composited state
of a layer changes, we have to clear all descendant clip rects, since this
can affect the layers relative to which clip rects are computed.
(WebCore::RenderLayerCompositor::addToOverlapMap): Use AbsoluteClipRects.
(WebCore::RenderLayerCompositor::computeCompositingRequirements): No need
to call updateLayerPosition(), since that should have always happened after
layout. That call cleared clip rects, so removing it is very beneficial.
(WebCore::RenderLayerCompositor::clippedByAncestor): Use TemporaryClipRects.

* rendering/RenderTreeAsText.cpp:
(WebCore::writeLayers): Use TemporaryClipRects.

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderTreeAsText.cpp

index 34b5026..3469ca0 100644 (file)
@@ -1,3 +1,88 @@
+2012-05-25  Simon Fraser  <simon.fraser@apple.com>
+
+        Cache absolute clip rects on RenderLayer for compositing overlap testing
+        https://bugs.webkit.org/show_bug.cgi?id=87212
+
+        Reviewed by Dave Hyatt.
+        
+        Enhance the cache of ClipRects on RenderLayers to store three
+        different types of ClipRects, rather than just one.
+        
+        We need to compute clip rects relative to different layers
+        for different purposes. For painting, we compute relative to
+        the compositing layer which is acting as a painting root.
+        For hit testing, we compute relative to the root, except
+        for transformed layers. For composting overlap testing, we
+        compute relative to the root ("absolute"). At other times, we do one-off
+        computation which we never want to cache ("temporary clip rects").
+        
+        This change allows us to cache rects for hit testing, and for
+        compositing overlap testing. This has huge performance benefits
+        on some pages (bug 84410).
+        
+        This change also makes ClipRects not arena-allocated, so we
+        can use RefPtr<ClipRect>.
+
+        No testable behavior change.
+
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::willBeDestroyed): No need for the
+        explicit clipRects teardown, since clipRects don't need a live
+        RenderObject for arena-based destruction.
+
+        * rendering/RenderLayer.cpp: Remove arena-related new and delete.
+        (WebCore::RenderLayer::RenderLayer): No need to explicitly initialize m_clipRects,
+        since it's an OwnPtr now.
+        (WebCore::RenderLayer::~RenderLayer): No explicit clipRect teardown required.
+        (WebCore::RenderLayer::clippingRootForPainting): Renamed to make its purpose
+        more obvious.
+        (WebCore::RenderLayer::paintLayer): Use the TemporaryClipRects type when necessary.
+        (WebCore::RenderLayer::paintLayerContents): Ditto
+        (WebCore::RenderLayer::hitTestLayer): No longer need to use temporary clipRects when
+        hit testing since we cache clip rects for hit testing.
+        (WebCore::RenderLayer::updateClipRects): Take a ClipRectsType and pass it through.
+        (WebCore::RenderLayer::calculateClipRects): Ditto
+        (WebCore::RenderLayer::parentClipRects): Ditto
+        (WebCore::RenderLayer::backgroundClipRect): Ditto
+        (WebCore::RenderLayer::calculateRects): Take ClipRectsType, which obviates temporaryClipRects.
+        (WebCore::RenderLayer::childrenClipRect): Use clippingRootForPainting().
+        (WebCore::RenderLayer::selfClipRect): Ditto
+        (WebCore::RenderLayer::localClipRect): Ditto
+        (WebCore::RenderLayer::clearClipRectsIncludingDescendants): Take a type of clip rect to clear
+        (include all). Allows us to just clear painting clip rects.
+        (WebCore::RenderLayer::clearClipRects):
+
+        * rendering/RenderLayer.h:
+        (WebCore::ClipRects::create): We don't use RefCounted<> in order to use a bit in
+        the refCount for a flag. Add create() method.
+        (WebCore::ClipRects::deref): No longer arena-allocated.
+        (WebCore::ClipRectsCache::ClipRectsCache): Struct that holds a small
+        array of the 3 types of clipRects (and, in debug, the layer relative
+        to which they were computed).
+        (WebCore::RenderLayer::clipRects):
+
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateCompositedBounds): Use AbsoluteClipRects; rootLayer
+        is always the RenderView's layer here.
+        (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): Use TemporaryClipRects.
+        (WebCore::RenderLayerBacking::setRequiresOwnBackingStore): When this variable changes,
+        we need to invalidate painting clipRects, since it affects the ancestor relative to which
+        those rects are computed.
+
+        * rendering/RenderLayerBacking.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::updateBacking): When the composited state
+        of a layer changes, we have to clear all descendant clip rects, since this
+        can affect the layers relative to which clip rects are computed.
+        (WebCore::RenderLayerCompositor::addToOverlapMap): Use AbsoluteClipRects.
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements): No need
+        to call updateLayerPosition(), since that should have always happened after
+        layout. That call cleared clip rects, so removing it is very beneficial.
+        (WebCore::RenderLayerCompositor::clippedByAncestor): Use TemporaryClipRects.
+
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::writeLayers): Use TemporaryClipRects.
+
 2012-05-25  Dean Jackson  <dino@apple.com>
 
         Unreviewed, rolling out r112155.
index 20e850a..1625f07 100644 (file)
@@ -345,10 +345,6 @@ void RenderBoxModelObject::destroyLayer()
 
 void RenderBoxModelObject::willBeDestroyed()
 {
-    // This must be done before we destroy the RenderObject.
-    if (m_layer)
-        m_layer->clearClipRects();
-
     // A continuation of this RenderObject should be destroyed at subclasses.
     ASSERT(!continuation());
 
index 39afa30..1d29dec 100644 (file)
@@ -125,25 +125,6 @@ using namespace HTMLNames;
 const int MinimumWidthWhileResizing = 100;
 const int MinimumHeightWhileResizing = 40;
 
-void* ClipRects::operator new(size_t sz, RenderArena* renderArena)
-{
-    return renderArena->allocate(sz);
-}
-
-void ClipRects::operator delete(void* ptr, size_t sz)
-{
-    // Stash size where destroy can find it.
-    *(size_t *)ptr = sz;
-}
-
-void ClipRects::destroy(RenderArena* renderArena)
-{
-    delete this;
-    
-    // Recover the size left there for us by operator delete and free the memory.
-    renderArena->free(*(size_t *)this, this);
-}
-
 RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
     : m_inResizeMode(false)
     , m_scrollDimensionsDirty(true)
@@ -180,10 +161,6 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
     , m_posZOrderList(0)
     , m_negZOrderList(0)
     , m_normalFlowList(0)
-    , m_clipRects(0)
-#ifndef NDEBUG
-    , m_clipRectsRoot(0)
-#endif
     , m_marquee(0)
     , m_staticInlinePosition(0)
     , m_staticBlockPosition(0)
@@ -252,9 +229,6 @@ RenderLayer::~RenderLayer()
     clearBacking(true);
 #endif
     
-    // Make sure we have no lingering clip rects.
-    ASSERT(!m_clipRects);
-    
     if (m_scrollCorner)
         m_scrollCorner->destroy();
     if (m_resizer)
@@ -1070,7 +1044,7 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect,
 }
 #endif
     
-RenderLayer* RenderLayer::clippingRoot() const
+RenderLayer* RenderLayer::clippingRootForPainting() const
 {
 #if USE(ACCELERATED_COMPOSITING)
     if (isComposited())
@@ -2935,7 +2909,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context,
         // Make sure the parent's clip rects have been calculated.
         ClipRect clipRect = paintDirtyRect;
         if (parent()) {
-            clipRect = backgroundClipRect(rootLayer, region, paintFlags & PaintLayerTemporaryClipRects);
+            clipRect = backgroundClipRect(rootLayer, region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects);
             clipRect.intersect(paintDirtyRect);
         
             // Push the parent coordinate space's clip.
@@ -3044,7 +3018,7 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co
 #endif
     
     if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
-        calculateRects(rootLayer, region, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects);
+        calculateRects(rootLayer, region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
         paintOffset = toPoint(layerBounds.location() - renderBoxLocation());
     }
 
@@ -3452,11 +3426,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
 {
     // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
 
-    bool useTemporaryClipRects = false;
-#if USE(ACCELERATED_COMPOSITING)
-    useTemporaryClipRects = compositor()->inCompositingMode();
-#endif
-    useTemporaryClipRects |= renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars();
+    bool useTemporaryClipRects = renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars();
 
     LayoutRect hitTestArea = result.rectForPoint(hitTestPoint);
 
@@ -3464,7 +3434,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
     if (transform() && !appliedTransform) {
         // Make sure the parent's clip rects have been calculated.
         if (parent()) {
-            ClipRect clipRect = backgroundClipRect(rootLayer, result.region(), useTemporaryClipRects, IncludeOverlayScrollbarSize);
+            ClipRect clipRect = backgroundClipRect(rootLayer, result.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, IncludeOverlayScrollbarSize);
             // Go ahead and test the enclosing clip now.
             if (!clipRect.intersects(hitTestArea))
                 return 0;
@@ -3525,7 +3495,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
     ClipRect bgRect;
     ClipRect fgRect;
     ClipRect outlineRect;
-    calculateRects(rootLayer, result.region(), hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects, IncludeOverlayScrollbarSize);
+    calculateRects(rootLayer, result.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, IncludeOverlayScrollbarSize);
     
     // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
     // descendants.
@@ -3796,10 +3766,11 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
     return 0;
 }
 
-void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
+void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy)
 {
-    if (m_clipRects) {
-        ASSERT(rootLayer == m_clipRectsRoot);
+    ASSERT(clipRectsType < NumCachedClipRectsTypes);
+    if (m_clipRectsCache && m_clipRectsCache->m_clipRects[clipRectsType]) {
+        ASSERT(rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
         return; // We have the correct cached value.
     }
     
@@ -3807,29 +3778,34 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* re
     // examine the parent.  We want to cache clip rects with us as the root.
     RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
     if (parentLayer)
-        parentLayer->updateClipRects(rootLayer, region, relevancy);
+        parentLayer->updateClipRects(rootLayer, region, clipRectsType, relevancy);
 
     ClipRects clipRects;
-    calculateClipRects(rootLayer, region, clipRects, true, relevancy);
+    calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy);
 
-    if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects())
-        m_clipRects = parentLayer->clipRects();
+    if (!m_clipRectsCache)
+        m_clipRectsCache = adoptPtr(new ClipRectsCache);
+
+    if (parentLayer && parentLayer->clipRects(clipRectsType) && clipRects == *parentLayer->clipRects(clipRectsType))
+        m_clipRectsCache->m_clipRects[clipRectsType] = parentLayer->clipRects(clipRectsType);
     else
-        m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects);
-    m_clipRects->ref();
+        m_clipRectsCache->m_clipRects[clipRectsType] = ClipRects::create(clipRects);
+
+    m_clipRectsCache->m_clipRects[clipRectsType]->ref();
 #ifndef NDEBUG
-    m_clipRectsRoot = rootLayer;
+    m_clipRectsCache->m_clipRectsRoot[clipRectsType] = rootLayer;
 #endif
 }
 
-void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRects& clipRects,
-    bool useCached, OverlayScrollbarSizeRelevancy relevancy) const
+void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const
 {
     if (!parent()) {
         // The root layer's clip rect is always infinite.
         clipRects.reset(PaintInfo::infiniteRect());
         return;
     }
+    
+    bool useCached = clipRectsType != TemporaryClipRects;
 
     // For transformed layers, the root layer was shifted to be us, so there is no need to
     // examine the parent.  We want to cache clip rects with us as the root.
@@ -3837,10 +3813,10 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion*
     
     // Ensure that our parent's clip has been calculated so that we can examine the values.
     if (parentLayer) {
-        if (useCached && parentLayer->clipRects())
-            clipRects = *parentLayer->clipRects();
+        if (useCached && parentLayer->clipRects(clipRectsType))
+            clipRects = *parentLayer->clipRects(clipRectsType);
         else
-            parentLayer->calculateClipRects(rootLayer, region, clipRects);
+            parentLayer->calculateClipRects(rootLayer, region, clipRectsType, clipRects);
     } else
         clipRects.reset(PaintInfo::infiniteRect());
 
@@ -3888,16 +3864,16 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion*
     }
 }
 
-void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRects& clipRects, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
+void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const
 {
     ASSERT(parent());
-    if (temporaryClipRects) {
-        parent()->calculateClipRects(rootLayer, region, clipRects, false, relevancy);
+    if (clipRectsType == TemporaryClipRects) {
+        parent()->calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy);
         return;
     }
 
-    parent()->updateClipRects(rootLayer, region, relevancy);
-    clipRects = *parent()->clipRects();
+    parent()->updateClipRects(rootLayer, region, clipRectsType, relevancy);
+    clipRects = *parent()->clipRects(clipRectsType);
 }
 
 static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position)
@@ -3911,11 +3887,11 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect
     return parentRects.overflowClipRect();
 }
 
-ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
+ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy) const
 {
     ASSERT(parent());
     ClipRects parentRects;
-    parentClipRects(rootLayer, region, parentRects, temporaryClipRects, relevancy);
+    parentClipRects(rootLayer, region, clipRectsType, parentRects, relevancy);
     ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position());
     RenderView* view = renderer()->view();
     ASSERT(view);
@@ -3927,12 +3903,11 @@ ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderReg
     return backgroundClipRect;
 }
 
-void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
-                                 ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, bool temporaryClipRects,
-                                 OverlayScrollbarSizeRelevancy relevancy) const
+void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
+                                 ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, OverlayScrollbarSizeRelevancy relevancy) const
 {
     if (rootLayer != this && parent()) {
-        backgroundRect = backgroundClipRect(rootLayer, region, temporaryClipRects, relevancy);
+        backgroundRect = backgroundClipRect(rootLayer, region, clipRectsType, relevancy);
         backgroundRect.intersect(paintDirtyRect);
     } else
         backgroundRect = paintDirtyRect;
@@ -3985,10 +3960,10 @@ LayoutRect RenderLayer::childrenClipRect() const
     // FIXME: border-radius not accounted for.
     // FIXME: Regions not accounted for.
     RenderView* renderView = renderer()->view();
-    RenderLayer* clippingRootLayer = clippingRoot();
+    RenderLayer* clippingRootLayer = clippingRootForPainting();
     LayoutRect layerBounds;
     ClipRect backgroundRect, foregroundRect, outlineRect;
-    calculateRects(clippingRootLayer, 0, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
+    calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
     return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
 }
 
@@ -3997,10 +3972,10 @@ LayoutRect RenderLayer::selfClipRect() const
     // FIXME: border-radius not accounted for.
     // FIXME: Regions not accounted for.
     RenderView* renderView = renderer()->view();
-    RenderLayer* clippingRootLayer = clippingRoot();
+    RenderLayer* clippingRootLayer = clippingRootForPainting();
     LayoutRect layerBounds;
     ClipRect backgroundRect, foregroundRect, outlineRect;
-    calculateRects(clippingRootLayer, 0, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
+    calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
     return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox();
 }
 
@@ -4008,10 +3983,10 @@ LayoutRect RenderLayer::localClipRect() const
 {
     // FIXME: border-radius not accounted for.
     // FIXME: Regions not accounted for.
-    RenderLayer* clippingRootLayer = clippingRoot();
+    RenderLayer* clippingRootLayer = clippingRootForPainting();
     LayoutRect layerBounds;
     ClipRect backgroundRect, foregroundRect, outlineRect;
-    calculateRects(clippingRootLayer, 0, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
+    calculateRects(clippingRootLayer, 0, PaintingClipRects, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
 
     LayoutRect clipRect = backgroundRect.rect();
     if (clipRect == PaintInfo::infiniteRect())
@@ -4259,25 +4234,25 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render
     return pixelSnappedIntRect(unionBounds);
 }
 
-void RenderLayer::clearClipRectsIncludingDescendants()
+void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear)
 {
-    if (!m_clipRects)
+    // FIXME: it's not clear how this layer not having clip rects guarantees that no descendants have any.
+    if (!m_clipRectsCache)
         return;
 
-    clearClipRects();
+    clearClipRects(typeToClear);
     
     for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
-        l->clearClipRectsIncludingDescendants();
+        l->clearClipRectsIncludingDescendants(typeToClear);
 }
 
-void RenderLayer::clearClipRects()
+void RenderLayer::clearClipRects(ClipRectsType typeToClear)
 {
-    if (m_clipRects) {
-        m_clipRects->deref(renderer()->renderArena());
-        m_clipRects = 0;
-#ifndef NDEBUG
-        m_clipRectsRoot = 0;
-#endif    
+    if (typeToClear == AllClipRectTypes)
+        m_clipRectsCache = nullptr;
+    else {
+        ASSERT(typeToClear < NumCachedClipRectsTypes);
+        m_clipRectsCache->m_clipRects[typeToClear] = nullptr;
     }
 }
 
index 860a372..ad23af7 100644 (file)
@@ -129,27 +129,19 @@ inline ClipRect intersection(const ClipRect& a, const ClipRect& b)
 
 class ClipRects {
 public:
-    ClipRects()
-        : m_refCnt(0)
-        , m_fixed(false)
+    static PassRefPtr<ClipRects> create()
     {
+        return adoptRef(new ClipRects);
     }
 
-    ClipRects(const LayoutRect& r)
-        : m_overflowClipRect(r)
-        , m_fixedClipRect(r)
-        , m_posClipRect(r)
-        , m_refCnt(0)
-        , m_fixed(false)
+    static PassRefPtr<ClipRects> create(const ClipRects& other)
     {
+        return adoptRef(new ClipRects(other));
     }
 
-    ClipRects(const ClipRects& other)
-        : m_overflowClipRect(other.overflowClipRect())
-        , m_fixedClipRect(other.fixedClipRect())
-        , m_posClipRect(other.posClipRect())
-        , m_refCnt(0)
-        , m_fixed(other.fixed())
+    ClipRects()
+        : m_refCnt(0)
+        , m_fixed(false)
     {
     }
 
@@ -174,15 +166,11 @@ public:
     void setFixed(bool fixed) { m_fixed = fixed; }
 
     void ref() { m_refCnt++; }
-    void deref(RenderArena* renderArena) { if (--m_refCnt == 0) destroy(renderArena); }
-
-    void destroy(RenderArena*);
-
-    // Overloaded new operator.
-    void* operator new(size_t, RenderArena*);
-
-    // Overridden to prevent the normal delete from being called.
-    void operator delete(void*, size_t);
+    void deref()
+    {
+        if (!--m_refCnt)
+            delete this;
+    }
 
     bool operator==(const ClipRects& other) const
     {
@@ -202,10 +190,24 @@ public:
     }
 
 private:
-    // The normal operator new is disallowed on all render objects.
-    void* operator new(size_t) throw();
+    ClipRects(const LayoutRect& r)
+        : m_overflowClipRect(r)
+        , m_fixedClipRect(r)
+        , m_posClipRect(r)
+        , m_refCnt(0)
+        , m_fixed(false)
+    {
+    }
+
+    ClipRects(const ClipRects& other)
+        : m_overflowClipRect(other.overflowClipRect())
+        , m_fixedClipRect(other.fixedClipRect())
+        , m_posClipRect(other.posClipRect())
+        , m_refCnt(0)
+        , m_fixed(other.fixed())
+    {
+    }
 
-private:
     ClipRect m_overflowClipRect;
     ClipRect m_fixedClipRect;
     ClipRect m_posClipRect;
@@ -213,6 +215,30 @@ private:
     bool m_fixed : 1;
 };
 
+enum ClipRectsType {
+    PaintingClipRects, // Relative to painting ancestor. Used for painting.
+    RootRelativeClipRects, // Relative to the ancestor treated as the root (e.g. transformed layer). Used for hit testing.
+    AbsoluteClipRects, // Relative to the RenderView's layer. Used for compositing overlap testing.
+    NumCachedClipRectsTypes,
+    AllClipRectTypes,
+    TemporaryClipRects
+};
+
+struct ClipRectsCache {
+    ClipRectsCache()
+    {
+#ifndef NDEBUG
+        for (int i = 0; i < NumCachedClipRectsTypes; ++i)
+            m_clipRectsRoot[i] = 0;
+#endif
+    }
+
+    RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes];
+#ifndef NDEBUG
+    const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes];
+#endif
+};
+
 class RenderLayer : public ScrollableArea {
 public:
     friend class RenderReplica;
@@ -371,8 +397,8 @@ public:
 
     const LayoutSize& relativePositionOffset() const { return m_relativeOffset; }
 
-    void clearClipRectsIncludingDescendants();
-    void clearClipRects();
+    void clearClipRectsIncludingDescendants(ClipRectsType typeToClear = AllClipRectTypes);
+    void clearClipRects(ClipRectsType typeToClear = AllClipRectTypes);
 
     void addBlockSelectionGapsBounds(const LayoutRect&);
     void clearBlockSelectionGapsBounds();
@@ -423,7 +449,7 @@ public:
     RenderLayer* enclosingScrollableLayer() const;
 
     // The layer relative to which clipping rects for this layer are computed.
-    RenderLayer* clippingRoot() const;
+    RenderLayer* clippingRootForPainting() const;
 
 #if USE(ACCELERATED_COMPOSITING)
     // Enclosing compositing layer; if includeSelf is true, may return this.
@@ -472,16 +498,17 @@ public:
     // This method figures out our layerBounds in coordinates relative to
     // |rootLayer}.  It also computes our background and foreground clip rects
     // for painting/event handling.
-    void calculateRects(const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
+    void calculateRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
                         ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect,
-                        bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
+                        OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
 
     // Compute and cache clip rects computed with the given layer as the root
-    void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize);
+    void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize);
     // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors
     // (rather than computing them all from scratch up the parent chain).
-    void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRects&, bool useCached = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
-    ClipRects* clipRects() const { return m_clipRects; }
+    void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
+
+    ClipRects* clipRects(ClipRectsType type) const { ASSERT(type < NumCachedClipRectsTypes); return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0; }
 
     LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space.
     LayoutRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space.
@@ -767,8 +794,8 @@ private:
     void updateOrRemoveFilterEffect();
 #endif
 
-    void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRects&, bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
-    ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, bool temporaryClipRects, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
+    void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
+    ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
     LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior);
 
     RenderLayer* enclosingTransformedAncestor() const;
@@ -905,11 +932,8 @@ protected:
     // overflow layers, but that may change in the future.
     Vector<RenderLayer*>* m_normalFlowList;
 
-    ClipRects* m_clipRects;      // Cached clip rects used when painting and hit testing.
-#ifndef NDEBUG
-    const RenderLayer* m_clipRectsRoot;   // Root layer used to compute clip rects.
-#endif
-
+    OwnPtr<ClipRectsCache> m_clipRectsCache;
+    
     IntPoint m_cachedOverlayScrollbarOffset;
 
     RenderMarquee* m_marquee; // Used by layers with overflow:marquee
index ee39912..1085eab 100644 (file)
@@ -267,7 +267,7 @@ void RenderLayerBacking::updateCompositedBounds()
         LayoutRect clippingBounds = view->unscaledDocumentRect();
 
         if (m_owningLayer != rootLayer)
-            clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, 0, true).rect()); // FIXME: Incorrect for CSS regions.
+            clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions.
 
         LayoutPoint delta;
         m_owningLayer->convertToLayerCoords(rootLayer, delta);
@@ -465,7 +465,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
         // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this
         // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects
         // for a compositing layer, rootLayer is the layer itself.
-        IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, true).rect()); // FIXME: Incorrect for CSS regions.
+        IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, TemporaryClipRects).rect()); // FIXME: Incorrect for CSS regions.
         ASSERT(parentClipRect != PaintInfo::infiniteRect());
         m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation));
         m_ancestorClippingLayer->setSize(parentClipRect.size());
@@ -1112,6 +1112,17 @@ bool RenderLayerBacking::paintsIntoWindow() const
     return false;
 }
 
+void RenderLayerBacking::setRequiresOwnBackingStore(bool flag)
+{
+    if (flag == m_requiresOwnBackingStore)
+        return;
+    
+    // This affects the answer to paintsIntoCompositedAncestor(), which in turn affects
+    // cached clip rects, so when it changes we have to clear clip rects on descendants.
+    m_owningLayer->clearClipRectsIncludingDescendants(PaintingClipRects);
+    m_requiresOwnBackingStore = flag;
+}
+
 void RenderLayerBacking::setContentsNeedDisplay()
 {
     ASSERT(!paintsIntoCompositedAncestor());
index a6a03ac..d871885 100644 (file)
@@ -101,7 +101,7 @@ public:
     // paints into some ancestor layer.
     bool paintsIntoCompositedAncestor() const { return !m_requiresOwnBackingStore; }
 
-    void setRequiresOwnBackingStore(bool flag) { m_requiresOwnBackingStore = flag; }
+    void setRequiresOwnBackingStore(bool);
 
     void setContentsNeedDisplay();
     // r is in the coordinate space of the layer's render object
index c402b59..3709232 100644 (file)
@@ -537,6 +537,9 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR
         if (innerCompositor && innerCompositor->inCompositingMode())
             innerCompositor->updateRootLayerAttachment();
     }
+    
+    if (layerChanged)
+        layer->clearClipRectsIncludingDescendants(PaintingClipRects);
 
     return layerChanged;
 }
@@ -637,7 +640,7 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer*
         boundsComputed = true;
     }
 
-    IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, true).rect()); // FIXME: Incorrect for CSS regions.
+    IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions.
     clipRect.scale(pageScaleFactor());
     clipRect.intersect(layerBounds);
     overlapMap.add(layer, clipRect);
@@ -696,7 +699,6 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren
 //
 void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, OverlapMap* overlapMap, CompositingState& compositingState, bool& layersChanged)
 {
-    layer->updateLayerPosition();
     layer->updateLayerListsIfNeeded();
 
     // Clear the flag
@@ -1536,7 +1538,7 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const
     if (!computeClipRoot || computeClipRoot == layer)
         return false;
 
-    return layer->backgroundClipRect(computeClipRoot, 0, true).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions.
+    return layer->backgroundClipRect(computeClipRoot, 0, TemporaryClipRects).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions.
 }
 
 // Return true if the given layer is a stacking context and has compositing child
index 51fc417..39319ca 100644 (file)
@@ -718,7 +718,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye
     // Calculate the clip rects we should use.
     LayoutRect layerBounds;
     ClipRect damageRect, clipRectToApply, outlineRect;
-    l->calculateRects(rootLayer, 0, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, true);
+    l->calculateRects(rootLayer, 0, TemporaryClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
 
     // Ensure our lists are up-to-date.
     l->updateLayerListsIfNeeded();