[chromium] Replicas should be included in the computed occlusion
authordanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Apr 2012 01:58:23 +0000 (01:58 +0000)
committerdanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 14 Apr 2012 01:58:23 +0000 (01:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=82262

Reviewed by Adrienne Walker.

Source/WebCore:

When merging a surface's occlusion up to its target, make a copy of it
where the replica will be as well, and make sure that occlusion from a
RenderSurface does not leave its clipRect.

Unit test: CCOcclusionTrackerTestReplicaDoesOcclude
           CCOcclusionTrackerTestReplicaWithClipping
           CCOcclusionTrackerTestSurfaceChildOfSurface

* platform/graphics/chromium/RenderSurfaceChromium.cpp:
(WebCore::RenderSurfaceChromium::hasReplica):
(WebCore):
* platform/graphics/chromium/RenderSurfaceChromium.h:
(RenderSurfaceChromium):
* platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
(WebCore::transformSurfaceOpaqueRegion):
(WebCore::::leaveToTargetRenderSurface):

Source/WebKit/chromium:

* tests/CCOcclusionTrackerTest.cpp:
(CCOcclusionTrackerTestReplicaDoesOcclude):
(WebKitTests::CCOcclusionTrackerTestReplicaDoesOcclude::runMyTest):
(WebKitTests):
(CCOcclusionTrackerTestReplicaWithClipping):
(WebKitTests::CCOcclusionTrackerTestReplicaWithClipping::runMyTest):
(CCOcclusionTrackerTestSurfaceChildOfSurface):
(WebKitTests::CCOcclusionTrackerTestSurfaceChildOfSurface::runMyTest):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp

index 739b6ac..7dc1a48 100644 (file)
@@ -1,3 +1,27 @@
+2012-04-13  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Replicas should be included in the computed occlusion
+        https://bugs.webkit.org/show_bug.cgi?id=82262
+
+        Reviewed by Adrienne Walker.
+
+        When merging a surface's occlusion up to its target, make a copy of it
+        where the replica will be as well, and make sure that occlusion from a
+        RenderSurface does not leave its clipRect.
+
+        Unit test: CCOcclusionTrackerTestReplicaDoesOcclude
+                   CCOcclusionTrackerTestReplicaWithClipping
+                   CCOcclusionTrackerTestSurfaceChildOfSurface
+
+        * platform/graphics/chromium/RenderSurfaceChromium.cpp:
+        (WebCore::RenderSurfaceChromium::hasReplica):
+        (WebCore):
+        * platform/graphics/chromium/RenderSurfaceChromium.h:
+        (RenderSurfaceChromium):
+        * platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
+        (WebCore::transformSurfaceOpaqueRegion):
+        (WebCore::::leaveToTargetRenderSurface):
+
 2012-04-13  Raymond Liu  <raymond.liu@intel.com>
 
         AudioContext createChannelMerger() method should have optional argument for number of inputs.
index fbef7a7..4e5528e 100644 (file)
@@ -64,5 +64,10 @@ FloatRect RenderSurfaceChromium::drawableContentRect() const
     return drawableContentRect;
 }
 
+bool RenderSurfaceChromium::hasReplica() const
+{
+    return m_owningLayer->replicaLayer();
+}
+
 }
 #endif // USE(ACCELERATED_COMPOSITING)
index 9a84ebb..c895215 100644 (file)
@@ -107,6 +107,8 @@ public:
     void setNearestAncestorThatMovesPixels(RenderSurfaceChromium* surface) { m_nearestAncestorThatMovesPixels = surface; }
     const RenderSurfaceChromium* nearestAncestorThatMovesPixels() const { return m_nearestAncestorThatMovesPixels; }
 
+    bool hasReplica() const;
+
 private:
     LayerChromium* m_owningLayer;
     LayerChromium* m_maskLayer;
index dfd36d0..bd175a6 100644 (file)
@@ -125,8 +125,12 @@ static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surfa
 
     Vector<IntRect> rects = region.rects();
     // Clipping has been verified above, so mapRect will give correct results.
-    for (size_t i = 0; i < rects.size(); ++i)
-        transformedRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(rects[i]))));
+    for (size_t i = 0; i < rects.size(); ++i) {
+        IntRect transformedRect = enclosedIntRect(transform.mapRect(FloatRect(rects[i])));
+        if (!surface->clipRect().isEmpty())
+            transformedRect.intersect(surface->clipRect());
+        transformedRegion.unite(transformedRect);
+    }
     return transformedRegion;
 }
 
@@ -141,7 +145,8 @@ void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToTargetRenderSu
 
     const RenderSurfaceType* oldTarget = m_stack[lastIndex].surface;
     Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(oldTarget, m_stack[lastIndex].occlusionInTarget, oldTarget->originTransform());
-    // FIXME: The replica can occlude things too.
+    if (oldTarget->hasReplica())
+        oldTargetOcclusionInNewTarget.unite(transformSurfaceOpaqueRegion<RenderSurfaceType>(oldTarget, m_stack[lastIndex].occlusionInTarget, oldTarget->replicaOriginTransform()));
 
     if (surfaceWillBeAtTopAfterPop) {
         // Merge the top of the stack down.
index 6ccbbe2..b50f2b0 100644 (file)
@@ -1,3 +1,19 @@
+2012-04-13  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Replicas should be included in the computed occlusion
+        https://bugs.webkit.org/show_bug.cgi?id=82262
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCOcclusionTrackerTest.cpp:
+        (CCOcclusionTrackerTestReplicaDoesOcclude):
+        (WebKitTests::CCOcclusionTrackerTestReplicaDoesOcclude::runMyTest):
+        (WebKitTests):
+        (CCOcclusionTrackerTestReplicaWithClipping):
+        (WebKitTests::CCOcclusionTrackerTestReplicaWithClipping::runMyTest):
+        (CCOcclusionTrackerTestSurfaceChildOfSurface):
+        (WebKitTests::CCOcclusionTrackerTestSurfaceChildOfSurface::runMyTest):
+
 2012-04-13  Bernhard Bauer  <bauerb@google.com>
 
         [chromium] Remove fallback code for "Missing plug-in" string.
index fd3f14f..b3e3c36 100644 (file)
@@ -1219,6 +1219,70 @@ protected:
 ALL_CCOCCLUSIONTRACKER_TEST(CCOcclusionTrackerTestFilters);
 
 template<class Types, bool opaqueLayers>
+class CCOcclusionTrackerTestReplicaDoesOcclude : public CCOcclusionTrackerTest<Types, opaqueLayers> {
+protected:
+    void runMyTest()
+    {
+        typename Types::ContentLayerType* parent = this->createRoot(this->identityMatrix, FloatPoint(0, 0), IntSize(100, 200));
+        typename Types::LayerType* surface = this->createDrawingSurface(parent, this->identityMatrix, FloatPoint(0, 100), IntSize(50, 50), true);
+        this->createReplicaLayer(surface, this->identityMatrix, FloatPoint(50, 50), IntSize());
+        this->calcDrawEtc(parent);
+
+        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(0, 0, 1000, 1000));
+        occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
+        occlusion.enterTargetRenderSurface(surface->renderSurface());
+        occlusion.markOccludedBehindLayer(surface);
+
+        EXPECT_EQ_RECT(IntRect(0, 100, 50, 50), occlusion.occlusionInScreenSpace().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(0, 0, 50, 50), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
+
+        occlusion.finishedTargetRenderSurface(surface, surface->renderSurface());
+        occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+        // The surface and replica should both be occluding the parent.
+        EXPECT_EQ_RECT(IntRect(0, 100, 100, 100), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(2u, occlusion.occlusionInTargetSurface().rects().size());
+    }
+};
+
+ALL_CCOCCLUSIONTRACKER_TEST(CCOcclusionTrackerTestReplicaDoesOcclude);
+
+template<class Types, bool opaqueLayers>
+class CCOcclusionTrackerTestReplicaWithClipping : public CCOcclusionTrackerTest<Types, opaqueLayers> {
+protected:
+    void runMyTest()
+    {
+        typename Types::ContentLayerType* parent = this->createRoot(this->identityMatrix, FloatPoint(0, 0), IntSize(100, 170));
+        typename Types::LayerType* surface = this->createDrawingSurface(parent, this->identityMatrix, FloatPoint(0, 100), IntSize(50, 50), true);
+        this->createReplicaLayer(surface, this->identityMatrix, FloatPoint(50, 50), IntSize());
+        this->calcDrawEtc(parent);
+
+        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(0, 0, 1000, 1000));
+        occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
+        occlusion.enterTargetRenderSurface(surface->renderSurface());
+        occlusion.markOccludedBehindLayer(surface);
+
+        EXPECT_EQ_RECT(IntRect(0, 100, 50, 50), occlusion.occlusionInScreenSpace().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(0, 0, 50, 50), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
+
+        occlusion.finishedTargetRenderSurface(surface, surface->renderSurface());
+        occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+        // The surface and replica should both be occluding the parent.
+        EXPECT_EQ_RECT(IntRect(0, 100, 100, 70), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(2u, occlusion.occlusionInTargetSurface().rects().size());
+    }
+};
+
+ALL_CCOCCLUSIONTRACKER_TEST(CCOcclusionTrackerTestReplicaWithClipping);
+
+template<class Types, bool opaqueLayers>
 class CCOcclusionTrackerTestLayerScissorRectOutsideChild : public CCOcclusionTrackerTest<Types, opaqueLayers> {
 protected:
     void runMyTest()
@@ -2195,12 +2259,11 @@ protected:
 
         typename Types::ContentLayerType* parent = this->createRoot(this->identityMatrix, FloatPoint(0, 0), IntSize(100, 200));
         typename Types::LayerType* surface = this->createDrawingSurface(parent, this->identityMatrix, FloatPoint(0, 0), IntSize(100, 100), true);
-        typename Types::LayerType* surfaceChild = this->createDrawingSurface(surface, this->identityMatrix, FloatPoint(0, 0), IntSize(100, 100), false);
+        typename Types::LayerType* surfaceChild = this->createDrawingSurface(surface, this->identityMatrix, FloatPoint(0, 10), IntSize(100, 50), true);
         typename Types::LayerType* topmost = this->createDrawingLayer(parent, this->identityMatrix, FloatPoint(0, 0), IntSize(100, 50), true);
         this->calcDrawEtc(parent);
 
-        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(0, 0, 1000, 1000));
-        occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(-100, -100, 1000, 1000));
 
         // This occludes everything partially so we know occlusion is happening at all.
         occlusion.enterTargetRenderSurface(parent->renderSurface());
@@ -2212,23 +2275,32 @@ protected:
         EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
 
         occlusion.enterTargetRenderSurface(surfaceChild->renderSurface());
-        // surfaceChild is not opaque and does not occlude, so we have a non-empty unoccluded area on surface.
+
         occlusion.markOccludedBehindLayer(surfaceChild);
 
-        EXPECT_EQ_RECT(IntRect(0, 0, 100, 50), occlusion.occlusionInScreenSpace().bounds());
+        // surfaceChild increases the occlusion in the screen by a narrow sliver.
+        EXPECT_EQ_RECT(IntRect(0, 0, 100, 60), occlusion.occlusionInScreenSpace().bounds());
         EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size());
-        EXPECT_EQ_RECT(IntRect(0, 0, 0, 0), occlusion.occlusionInTargetSurface().bounds());
-        EXPECT_EQ(0u, occlusion.occlusionInTargetSurface().rects().size());
+        // In its own surface, surfaceChild is at 0,0 as is its occlusion.
+        EXPECT_EQ_RECT(IntRect(0, 0, 100, 50), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
 
         // The root layer always has a clipRect. So the parent of |surface| has a clipRect. However, the owning layer for |surface| does not
         // mask to bounds, so it doesn't have a clipRect of its own. Thus the parent of |surfaceChild| exercises different code paths
         // as its parent does not have a clipRect.
 
         occlusion.finishedTargetRenderSurface(surfaceChild, surfaceChild->renderSurface());
-        // The surfaceChild's parent does not have a clipRect as it owns a render surface.
-        EXPECT_EQ_RECT(IntRect(0, 50, 100, 50), occlusion.unoccludedContributingSurfaceContentRect(surfaceChild, false, IntRect(0, 0, 100, 100)));
+        // The surfaceChild's parent does not have a clipRect as it owns a render surface. Make sure the unoccluded rect
+        // does not get clipped away inappropriately.
+        EXPECT_EQ_RECT(IntRect(0, 40, 100, 10), occlusion.unoccludedContributingSurfaceContentRect(surfaceChild, false, IntRect(0, 0, 100, 50)));
 
+        // When the surfaceChild's occlusion is transformed up to its parent, make sure it is not clipped away inappropriately also.
         occlusion.leaveToTargetRenderSurface(surface->renderSurface());
+        EXPECT_EQ_RECT(IntRect(0, 0, 100, 60), occlusion.occlusionInScreenSpace().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(0, 10, 100, 50), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
+
         occlusion.markOccludedBehindLayer(surface);
 
         occlusion.finishedTargetRenderSurface(surface, surface->renderSurface());