[chromium] Add clipping to scissor rect to CCOcclusionTracker
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Mar 2012 07:07:54 +0000 (07:07 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 7 Mar 2012 07:07:54 +0000 (07:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=79927

Patch by Dana Jansens <danakj@chromium.org> on 2012-03-06
Reviewed by Adrienne Walker.

Source/WebCore:

Adds logic to CCOcclusionTracker to occlude anything outside of the
current screen and target surface scissor rects. When tracking
damage for partial swaps, the scissor rects are bounded by the
tracked damage rects.

Unit tests: CCOcclusionTrackerTest.cpp

* platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
(WebCore::::CCOcclusionTrackerBase):
(WebCore):
(WebCore::::markOccludedBehindLayer):
(WebCore::testContentRectOccluded):
(WebCore::::occluded):
(WebCore::computeUnoccludedContentRect):
(WebCore::::unoccludedContentRect):
(WebCore::::layerScissorRect):
* platform/graphics/chromium/cc/CCOcclusionTracker.h:
(WebCore):
(CCOcclusionTrackerDamageClientBase):
(CCOcclusionTrackerBase):

Source/WebKit/chromium:

* tests/CCOcclusionTrackerTest.cpp:
(WebCore::TestCCOcclusionTracker::TestCCOcclusionTracker):
(TestCCOcclusionTracker):
(WebCore::TestCCOcclusionTracker::setLayerScissorRect):
(WebCore::TestCCOcclusionTracker::useDefaultLayerScissorRect):
(WebCore::TestCCOcclusionTracker::layerScissorRect):
(WebCore):
(TestDamageClient):
(WebCore::TestDamageClient::damageRect):
(WebCore::TestDamageClient::TestDamageClient):
(WebCore::TestDamageClient::setDamageRect):
(WebCore::TEST):

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

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

index 593c841c5f3b66d9e17bdc051a9305feefb848b4..5b7c73666faa1746a400133ed51bcea283b391dc 100644 (file)
@@ -1,3 +1,31 @@
+2012-03-06  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Add clipping to scissor rect to CCOcclusionTracker
+        https://bugs.webkit.org/show_bug.cgi?id=79927
+
+        Reviewed by Adrienne Walker.
+
+        Adds logic to CCOcclusionTracker to occlude anything outside of the
+        current screen and target surface scissor rects. When tracking
+        damage for partial swaps, the scissor rects are bounded by the
+        tracked damage rects.
+
+        Unit tests: CCOcclusionTrackerTest.cpp
+
+        * platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
+        (WebCore::::CCOcclusionTrackerBase):
+        (WebCore):
+        (WebCore::::markOccludedBehindLayer):
+        (WebCore::testContentRectOccluded):
+        (WebCore::::occluded):
+        (WebCore::computeUnoccludedContentRect):
+        (WebCore::::unoccludedContentRect):
+        (WebCore::::layerScissorRect):
+        * platform/graphics/chromium/cc/CCOcclusionTracker.h:
+        (WebCore):
+        (CCOcclusionTrackerDamageClientBase):
+        (CCOcclusionTrackerBase):
+
 2012-03-06  Kentaro Hara  <haraken@chromium.org>
 
         Unreviewed, rolling out r110011.
index c5611ac27a6aec4a7fbd694023d343f52ba5d23c..6585454ffcb760ed8d1f5f3d3a492c377e4368c8 100644 (file)
@@ -38,6 +38,20 @@ using namespace std;
 
 namespace WebCore {
 
+template<typename LayerType, typename RenderSurfaceType>
+CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace)
+    : m_scissorRectInScreenSpace(scissorRectInScreenSpace)
+    , m_surfaceDamageClient(0)
+{
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace, const DamageClientType* surfaceDamageClient)
+    : m_scissorRectInScreenSpace(scissorRectInScreenSpace)
+    , m_surfaceDamageClient(surfaceDamageClient)
+{
+}
+
 template<typename LayerType, typename RenderSurfaceType>
 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::enterTargetRenderSurface(const RenderSurfaceType* newTarget)
 {
@@ -191,6 +205,8 @@ void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLay
 {
     ASSERT(!m_stack.isEmpty());
     ASSERT(layer->targetRenderSurface() == m_stack.last().surface);
+    if (m_stack.isEmpty())
+        return;
 
     if (layer->drawOpacity() != 1)
         return;
@@ -202,41 +218,26 @@ void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLay
     m_stack.last().occlusionInTarget.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToTargetSurface));
 }
 
-static inline bool testContentRectOccluded(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const Region& occlusion)
+static inline bool testContentRectOccluded(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion)
 {
-    FloatQuad transformedQuad = contentSpaceTransform.mapQuad(FloatQuad(contentRect));
-    return occlusion.contains(transformedQuad.enclosingBoundingBox());
+    FloatRect transformedRect = contentSpaceTransform.mapRect(FloatRect(contentRect));
+    // Take the enclosingIntRect, as we want to include partial pixels in the test.
+    IntRect targetRect = intersection(enclosingIntRect(transformedRect), scissorRect);
+    return targetRect.isEmpty() || occlusion.contains(targetRect);
 }
 
 template<typename LayerType, typename RenderSurfaceType>
 bool CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerType* layer, const IntRect& contentRect) const
 {
+    ASSERT(!m_stack.isEmpty());
     if (m_stack.isEmpty())
         return false;
 
     ASSERT(layer->targetRenderSurface() == m_stack.last().surface);
 
-    if (testContentRectOccluded(contentRect, contentToScreenSpaceTransform<LayerType>(layer), m_stack.last().occlusionInScreen))
+    if (testContentRectOccluded(contentRect, contentToScreenSpaceTransform<LayerType>(layer), m_scissorRectInScreenSpace, m_stack.last().occlusionInScreen))
         return true;
-    if (testContentRectOccluded(contentRect, contentToTargetSurfaceTransform<LayerType>(layer), m_stack.last().occlusionInTarget))
-        return true;
-    return false;
-}
-
-template<typename LayerType, typename RenderSurfaceType>
-bool CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::surfaceOccluded(const LayerType* layer, const IntRect& surfaceContentRect) const
-{
-    // A surface is not occluded by layers drawing into itself, so we need to use occlusion from one spot down on the stack.
-    if (m_stack.size() < 2)
-        return false;
-
-    ASSERT(layer->renderSurface());
-    ASSERT(layer->renderSurface() == m_stack.last().surface);
-
-    TransformationMatrix surfaceContentToScreenSpace = contentToScreenSpaceTransform<LayerType>(layer);
-
-    const StackObject& secondLast = m_stack[m_stack.size()-2];
-    if (testContentRectOccluded(surfaceContentRect, surfaceContentToScreenSpace, secondLast.occlusionInScreen))
+    if (testContentRectOccluded(contentRect, contentToTargetSurfaceTransform<LayerType>(layer), layerScissorRectInTargetSurface(layer), m_stack.last().occlusionInTarget))
         return true;
     return false;
 }
@@ -256,22 +257,20 @@ static inline IntRect rectSubtractRegion(const IntRect& rect, const Region& regi
     return boundsRect;
 }
 
-static IntRect computeUnoccludedContentRect(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const Region& occlusion)
+static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion)
 {
-    FloatQuad transformedQuad = contentSpaceTransform.mapQuad(FloatQuad(contentRect));
-    if (!transformedQuad.isRectilinear())
-        return contentRect;
-    // Take the enclosingIntRect at each step here, as we want to contain any unoccluded partial pixels in the resulting IntRect.
-    IntRect shrunkRect = rectSubtractRegion(enclosingIntRect(transformedQuad.boundingBox()), occlusion);
+    FloatRect transformedRect = contentSpaceTransform.mapRect(FloatRect(contentRect));
+    // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect.
+    IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), scissorRect), occlusion);
     IntRect unoccludedRect = enclosingIntRect(contentSpaceTransform.inverse().mapRect(FloatRect(shrunkRect)));
-    // The use of enclosingIntRect, with floating point rounding, can give us a result that is not a sub-rect of contentRect, but our
-    // return value should be a sub-rect.
+    // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
     return intersection(unoccludedRect, contentRect);
 }
 
 template<typename LayerType, typename RenderSurfaceType>
 IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentRect(const LayerType* layer, const IntRect& contentRect) const
 {
+    ASSERT(!m_stack.isEmpty());
     if (m_stack.isEmpty())
         return contentRect;
 
@@ -281,31 +280,24 @@ IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR
     TransformationMatrix contentToScreenSpace = contentToScreenSpaceTransform<LayerType>(layer);
     TransformationMatrix contentToTargetSurface = contentToTargetSurfaceTransform<LayerType>(layer);
 
-    IntRect unoccludedInScreen = computeUnoccludedContentRect(contentRect, contentToScreenSpace, m_stack.last().occlusionInScreen);
-    IntRect unoccludedInTarget = computeUnoccludedContentRect(contentRect, contentToTargetSurface, m_stack.last().occlusionInTarget);
+    IntRect unoccludedInScreen = computeUnoccludedContentRect(contentRect, contentToScreenSpace, m_scissorRectInScreenSpace, m_stack.last().occlusionInScreen);
+    if (unoccludedInScreen.isEmpty())
+        return IntRect();
+    IntRect unoccludedInTarget = computeUnoccludedContentRect(contentRect, contentToTargetSurface, layerScissorRectInTargetSurface(layer), m_stack.last().occlusionInTarget);
 
     return intersection(unoccludedInScreen, unoccludedInTarget);
 }
 
 template<typename LayerType, typename RenderSurfaceType>
-IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::surfaceUnoccludedContentRect(const LayerType* layer, const IntRect& surfaceContentRect) const
+IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::layerScissorRectInTargetSurface(const LayerType* layer) const
 {
-    // A surface is not occluded by layers drawing into itself, so we need to use occlusion from one spot down on the stack.
-    if (m_stack.size() < 2)
-        return surfaceContentRect;
-
-    ASSERT(layer->renderSurface());
-    ASSERT(layer->renderSurface() == m_stack.last().surface);
-
-    // We want to return a rect that contains all the visible parts of |contentRect| in both screen space and in the target surface.
-    // So we find the visible parts of |contentRect| in each space, and take the intersection.
-
-    TransformationMatrix contentToScreenSpace = contentToScreenSpaceTransform<LayerType>(layer);
-
-    const StackObject& secondLast = m_stack[m_stack.size()-2];
-    IntRect unoccludedInScreen = computeUnoccludedContentRect(surfaceContentRect, contentToScreenSpace, secondLast.occlusionInScreen);
-
-    return unoccludedInScreen;
+    const RenderSurfaceType* targetSurface = m_stack.last().surface;
+    FloatRect totalScissor = targetSurface->contentRect();
+    if (m_surfaceDamageClient)
+        totalScissor.intersect(m_surfaceDamageClient->damageRect(targetSurface));
+    if (!layer->clipRect().isEmpty())
+        totalScissor.intersect(layer->clipRect());
+    return enclosingIntRect(totalScissor);
 }
 
 template<typename LayerType, typename RenderSurfaceType>
@@ -324,27 +316,29 @@ const Region& CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::currentOcclu
 
 
 // Declare the possible functions here for the linker.
+template CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace);
+template CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace, const CCOcclusionTrackerDamageClient* surfaceDamageClient);
 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::enterTargetRenderSurface(const RenderSurfaceChromium* newTarget);
 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::finishedTargetRenderSurface(const LayerChromium* owningLayer, const RenderSurfaceChromium* finishedTarget);
 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::leaveToTargetRenderSurface(const RenderSurfaceChromium* newTarget);
 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::markOccludedBehindLayer(const LayerChromium*);
 template bool CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::occluded(const LayerChromium*, const IntRect& contentRect) const;
-template bool CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::surfaceOccluded(const LayerChromium*, const IntRect& surfaceContentRect) const;
 template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::unoccludedContentRect(const LayerChromium*, const IntRect& contentRect) const;
-template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::surfaceUnoccludedContentRect(const LayerChromium*, const IntRect& surfaceContentRect) const;
 template const Region& CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::currentOcclusionInScreenSpace() const;
 template const Region& CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::currentOcclusionInTargetSurface() const;
+template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::layerScissorRectInTargetSurface(const LayerChromium*) const;
 
+template CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace);
+template CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace, const CCOcclusionTrackerDamageClientImpl* surfaceDamageClient);
 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::enterTargetRenderSurface(const CCRenderSurface* newTarget);
 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::finishedTargetRenderSurface(const CCLayerImpl* owningLayer, const CCRenderSurface* finishedTarget);
 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::leaveToTargetRenderSurface(const CCRenderSurface* newTarget);
 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::markOccludedBehindLayer(const CCLayerImpl*);
 template bool CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::occluded(const CCLayerImpl*, const IntRect& contentRect) const;
-template bool CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::surfaceOccluded(const CCLayerImpl*, const IntRect& surfaceContentRect) const;
 template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::unoccludedContentRect(const CCLayerImpl*, const IntRect& contentRect) const;
-template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::surfaceUnoccludedContentRect(const CCLayerImpl*, const IntRect& surfaceContentRect) const;
 template const Region& CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::currentOcclusionInScreenSpace() const;
 template const Region& CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::currentOcclusionInTargetSurface() const;
+template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::layerScissorRectInTargetSurface(const CCLayerImpl*) const;
 
 
 } // namespace WebCore
index d1c833e1a9ba4eede9abdf43021e7ed7b4c4ff16..b7c0e3b28fc07313ae6e120dd93ad376fbdc0d87 100644 (file)
@@ -36,6 +36,15 @@ class CCRenderSurface;
 class LayerChromium;
 class RenderSurfaceChromium;
 
+template<typename RenderSurfaceType>
+class CCOcclusionTrackerDamageClientBase {
+public:
+    virtual FloatRect damageRect(const RenderSurfaceType*) const = 0;
+};
+
+typedef CCOcclusionTrackerDamageClientBase<RenderSurfaceChromium> CCOcclusionTrackerDamageClient;
+typedef CCOcclusionTrackerDamageClientBase<CCRenderSurface> CCOcclusionTrackerDamageClientImpl;
+
 // This class is used to track occlusion of layers while traversing them in a front-to-back order. As each layer is visited, one of the
 // methods in this class is called to notify it about the current target surface.
 // Then, occlusion in the content space of the current layer may be queried, via methods such as occluded() and unoccludedContentRect().
@@ -43,8 +52,11 @@ class RenderSurfaceChromium;
 // Finally, once finished with the layer, occlusion behind the layer should be marked by calling markOccludedBehindLayer().
 template<typename LayerType, typename RenderSurfaceType>
 class CCOcclusionTrackerBase {
+    WTF_MAKE_NONCOPYABLE(CCOcclusionTrackerBase);
+    typedef CCOcclusionTrackerDamageClientBase<RenderSurfaceType> DamageClientType;
 public:
-    CCOcclusionTrackerBase() { }
+    CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace);
+    CCOcclusionTrackerBase(IntRect scissorRectInScreenSpace, const DamageClientType*);
 
     // Called when visiting a layer representing itself. If the target was not already current, then this indicates we have entered a new surface subtree.
     void enterTargetRenderSurface(const RenderSurfaceType* newTarget);
@@ -65,11 +77,6 @@ public:
     // Gives an unoccluded sub-rect of |contentRect| in the content space of the layer. Used when considering occlusion for a layer that paints/draws something.
     IntRect unoccludedContentRect(const LayerType*, const IntRect& contentRect) const;
 
-    // Returns true if the given rect in content space for the RenderSurface owned by the layer is fully occluded in either screen space or the layer's target surface.
-    bool surfaceOccluded(const LayerType*, const IntRect& contentRect) const;
-    // Gives an unoccluded sub-rect of |contentRect| in the content space of the RenderSurface owned by the layer. Used when considering occlusion for a target surface.
-    IntRect surfaceUnoccludedContentRect(const LayerType*, const IntRect& contentRect) const;
-
     // FIXME: Remove these in future, they are to make CLs for transitioning to this easier.
     const Region& currentOcclusionInScreenSpace() const;
     const Region& currentOcclusionInTargetSurface() const;
@@ -90,8 +97,12 @@ protected:
     // We merge the occlusion at the top of the stack with the new current subtree. This new target is pushed onto the stack if not already there.
     Vector<StackObject, 1> m_stack;
 
+    // Allow tests to override this.
+    virtual IntRect layerScissorRectInTargetSurface(const LayerType*) const;
+
 private:
-    WTF_MAKE_NONCOPYABLE(CCOcclusionTrackerBase);
+    IntRect m_scissorRectInScreenSpace;
+    const DamageClientType* m_surfaceDamageClient;
 };
 
 typedef CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium> CCOcclusionTracker;
index a69cc2b4066fc4a345aafb654bca34331f388e8e..632fdf9ea2d71ca996505b807330b65f11d2c1d6 100644 (file)
@@ -1,3 +1,23 @@
+2012-03-06  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Add clipping to scissor rect to CCOcclusionTracker
+        https://bugs.webkit.org/show_bug.cgi?id=79927
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCOcclusionTrackerTest.cpp:
+        (WebCore::TestCCOcclusionTracker::TestCCOcclusionTracker):
+        (TestCCOcclusionTracker):
+        (WebCore::TestCCOcclusionTracker::setLayerScissorRect):
+        (WebCore::TestCCOcclusionTracker::useDefaultLayerScissorRect):
+        (WebCore::TestCCOcclusionTracker::layerScissorRect):
+        (WebCore):
+        (TestDamageClient):
+        (WebCore::TestDamageClient::damageRect):
+        (WebCore::TestDamageClient::TestDamageClient):
+        (WebCore::TestDamageClient::setDamageRect):
+        (WebCore::TEST):
+
 2012-03-06  Kenichi Ishibashi  <bashi@chromium.org>
 
         [WebSocket] Introduce ThreadableWebSocketChannel::SendResult
index 678ec96452b0baed687aef66662df3d8d5105da8..765b491ac569bed170378016227962ee73a3ffbc 100644 (file)
@@ -68,17 +68,51 @@ public:
 // A subclass to expose the total current occlusion.
 class TestCCOcclusionTracker : public CCOcclusionTracker {
 public:
+    TestCCOcclusionTracker(IntRect screenScissorRect)
+        : CCOcclusionTracker(screenScissorRect)
+        , m_overrideLayerScissorRect(false)
+    {
+    }
+
+    TestCCOcclusionTracker(IntRect screenScissorRect, const CCOcclusionTrackerDamageClient* damageClient)
+        : CCOcclusionTracker(screenScissorRect, damageClient)
+        , m_overrideLayerScissorRect(false)
+    {
+    }
+
     Region occlusionInScreenSpace() const { return CCOcclusionTracker::m_stack.last().occlusionInScreen; }
     Region occlusionInTargetSurface() const { return CCOcclusionTracker::m_stack.last().occlusionInTarget; }
 
     void setOcclusionInScreenSpace(const Region& region) { CCOcclusionTracker::m_stack.last().occlusionInScreen = region; }
     void setOcclusionInTargetSurface(const Region& region) { CCOcclusionTracker::m_stack.last().occlusionInTarget = region; }
+
+    void setLayerScissorRect(const IntRect& rect) { m_overrideLayerScissorRect = true; m_layerScissorRect = rect;}
+    void useDefaultLayerScissorRect() { m_overrideLayerScissorRect = false; }
+
+protected:
+    virtual IntRect layerScissorRectInTargetSurface(const LayerChromium* layer) const { return m_overrideLayerScissorRect ? m_layerScissorRect : CCOcclusionTracker::layerScissorRectInTargetSurface(layer); }
+
+private:
+    bool m_overrideLayerScissorRect;
+    IntRect m_layerScissorRect;
+};
+
+class TestDamageClient : public CCOcclusionTrackerDamageClient {
+public:
+    // The interface
+    virtual FloatRect damageRect(const RenderSurfaceChromium*) const { return m_damageRect; }
+
+    // Testing stuff
+    TestDamageClient(const FloatRect& damageRect) : m_damageRect(damageRect) { }
+    void setDamageRect(const FloatRect& damageRect) { m_damageRect = damageRect; }
+
+private:
+    FloatRect m_damageRect;
 };
 
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegion)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
@@ -98,6 +132,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegion)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(parent->renderSurface());
     occlusion.markOccludedBehindLayer(layer.get());
     EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds());
@@ -111,6 +148,14 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegion)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70)));
 
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 70, 70)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 70, 70)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 70, 70)).isEmpty());
     EXPECT_EQ_RECT(IntRect(29, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 30, 70, 70)));
     EXPECT_EQ_RECT(IntRect(29, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 29, 70, 70)));
@@ -125,7 +170,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegion)
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotation)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
@@ -150,6 +194,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotation)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(parent->renderSurface());
     occlusion.markOccludedBehindLayer(layer.get());
     EXPECT_EQ_RECT(IntRect(30, 30, 70, 70), occlusion.occlusionInScreenSpace().bounds());
@@ -163,6 +210,14 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotation)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70)));
 
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 30, 70, 70)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 30, 70, 70)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 29, 70, 70)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(31, 30, 70, 70)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 31, 70, 70)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(30, 30, 70, 70)).isEmpty());
     EXPECT_EQ_RECT(IntRect(29, 30, 1, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 30, 70, 70)));
     EXPECT_EQ_RECT(IntRect(29, 29, 70, 70), occlusion.unoccludedContentRect(parent.get(), IntRect(29, 29, 70, 70)));
@@ -177,7 +232,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotation)
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithTranslation)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
@@ -200,6 +254,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithTranslation)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(parent->renderSurface());
     occlusion.markOccludedBehindLayer(layer.get());
     EXPECT_EQ_RECT(IntRect(50, 50, 50, 50), occlusion.occlusionInScreenSpace().bounds());
@@ -213,6 +270,14 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithTranslation)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(51, 50, 50, 50)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(50, 51, 50, 50)));
 
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(50, 50, 50, 50)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(49, 50, 50, 50)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(50, 49, 50, 50)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(51, 50, 50, 50)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(50, 51, 50, 50)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(50, 50, 50, 50)).isEmpty());
     EXPECT_EQ_RECT(IntRect(49, 50, 1, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 50, 50, 50)));
     EXPECT_EQ_RECT(IntRect(49, 49, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 49, 50, 50)));
@@ -222,12 +287,23 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithTranslation)
     EXPECT_EQ_RECT(IntRect(51, 51, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(51, 51, 50, 50)));
     EXPECT_EQ_RECT(IntRect(50, 100, 50, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(50, 51, 50, 50)));
     EXPECT_EQ_RECT(IntRect(49, 51, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 51, 50, 50)));
+
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(50, 50, 50, 50)).isEmpty());
+    EXPECT_EQ_RECT(IntRect(49, 50, 1, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 50, 50, 50)));
+    EXPECT_EQ_RECT(IntRect(49, 49, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 49, 50, 50)));
+    EXPECT_EQ_RECT(IntRect(50, 49, 50, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(50, 49, 50, 50)));
+    EXPECT_EQ_RECT(IntRect(51, 49, 49, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(51, 49, 50, 50)));
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(51, 50, 50, 50)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(51, 51, 50, 50)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(50, 51, 50, 50)).isEmpty());
+    EXPECT_EQ_RECT(IntRect(49, 51, 1, 49), occlusion.unoccludedContentRect(parent.get(), IntRect(49, 51, 50, 50)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
 }
 
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child = LayerChromium::create();
@@ -257,6 +333,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(child->renderSurface());
     occlusion.markOccludedBehindLayer(layer.get());
 
@@ -271,6 +350,14 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface)
     EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 430, 61, 70)));
     EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 71)));
 
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(9, 430, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 429, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 61, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 71)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.markOccludedBehindLayer(child.get());
     occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -283,6 +370,16 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface)
     EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 40, 70, 60)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 40, 70, 60)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 39, 70, 60)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(31, 40, 70, 60)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 41, 70, 60)));
+
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 40, 70, 60)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(29, 40, 70, 60)));
+    EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(30, 39, 70, 60)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(31, 40, 70, 60)));
+    EXPECT_TRUE(occlusion.occluded(parent.get(), IntRect(30, 41, 70, 60)));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
 
 
     /* Justification for the above occlusion from |layer|:
@@ -314,7 +411,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedSurface)
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child = LayerChromium::create();
@@ -350,6 +446,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(-10, -10, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(parent->renderSurface());
     occlusion.markOccludedBehindLayer(child2.get());
 
@@ -372,6 +471,14 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack
     EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(11, 430, 60, 70)));
     EXPECT_FALSE(occlusion.occluded(child.get(), IntRect(10, 431, 60, 70)));
 
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 430, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(9, 430, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 429, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(11, 430, 60, 70)));
+    EXPECT_TRUE(occlusion.occluded(child.get(), IntRect(10, 431, 60, 70)));
+    occlusion.setLayerScissorRect(IntRect(-10, -10, 1000, 1000));
+
     EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)).isEmpty());
     // This is the little piece not occluded by child2
     EXPECT_EQ_RECT(IntRect(9, 430, 1, 10), occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 70)));
@@ -387,8 +494,16 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack
     EXPECT_EQ_RECT(IntRect(70, 430, 1, 70), occlusion.unoccludedContentRect(child.get(), IntRect(11, 430, 60, 70)));
     EXPECT_EQ_RECT(IntRect(10, 500, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 431, 60, 70)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)));
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 70)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(9, 430, 60, 80)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(-10, 430, 60, 70)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(-10, 430, 60, 80)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 429, 60, 70)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(11, 430, 60, 70)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(child.get(), IntRect(10, 431, 60, 70)).isEmpty());
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
 
     occlusion.markOccludedBehindLayer(child.get());
     // |child2| should get merged with the surface we are leaving now
@@ -433,10 +548,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack
     EXPECT_EQ_RECT(IntRect(100, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 40, 70, 60)));
     EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 41, 70, 60)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60)));
-
-
     /* Justification for the above occlusion from |layer|:
                100
       +---------------------+                                      +---------------------+
@@ -465,7 +576,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithSurfaceAlreadyOnStack
 
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedOffAxisSurface)
 {
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child = LayerChromium::create();
@@ -501,6 +611,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedOffAxisSurface
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     IntRect clippedLayerInChild = layerTransform.mapRect(layer->visibleLayerRect());
 
     occlusion.enterTargetRenderSurface(child->renderSurface());
@@ -530,9 +643,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedOffAxisSurface
     EXPECT_FALSE(occlusion.unoccludedContentRect(parent.get(), clippedLayerInChild).isEmpty());
     clippedLayerInChild.move(0, -1);
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(0, 0, 500, 500), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(0, 0, 500, 500)));
-
     occlusion.markOccludedBehindLayer(child.get());
     occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -544,15 +654,11 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithRotatedOffAxisSurface
 
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(75, 55, 1, 1)));
     EXPECT_EQ_RECT(IntRect(75, 55, 1, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(75, 55, 1, 1)));
-
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(0, 0, 100, 100), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(0, 0, 100, 100)));
 }
 
 TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers)
 {
     // This is similar to the previous test but now we make a few opaque layers inside of |child| so that the occluded parts of child are not a simple rect.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child = LayerChromium::create();
@@ -585,6 +691,9 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(child->renderSurface());
     occlusion.markOccludedBehindLayer(layer2.get());
     occlusion.markOccludedBehindLayer(layer1.get());
@@ -606,9 +715,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers)
     EXPECT_EQ_RECT(IntRect(70, 430, 1, 70), occlusion.unoccludedContentRect(child.get(), IntRect(11, 430, 60, 70)));
     EXPECT_EQ_RECT(IntRect(10, 500, 60, 1), occlusion.unoccludedContentRect(child.get(), IntRect(10, 431, 60, 70)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(10, 430, 60, 70), occlusion.surfaceUnoccludedContentRect(child.get(), IntRect(10, 430, 60, 70)));
-
     occlusion.markOccludedBehindLayer(child.get());
     occlusion.finishedTargetRenderSurface(child.get(), child->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -628,10 +734,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers)
     EXPECT_EQ_RECT(IntRect(100, 40, 1, 60), occlusion.unoccludedContentRect(parent.get(), IntRect(31, 40, 70, 60)));
     EXPECT_EQ_RECT(IntRect(30, 100, 70, 1), occlusion.unoccludedContentRect(parent.get(), IntRect(30, 41, 70, 60)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(30, 40, 70, 60)));
-
-
     /* Justification for the above occlusion from |layer1| and |layer2|:
 
        +---------------------+
@@ -661,7 +763,6 @@ TEST(CCOcclusionTrackerTest, layerAddedToOccludedRegionWithMultipleOpaqueLayers)
 TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child1 = LayerChromium::create();
@@ -698,6 +799,9 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(-10, -10, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(child2->renderSurface());
     occlusion.markOccludedBehindLayer(layer2.get());
 
@@ -712,9 +816,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(0, 420, 61, 80)));
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(0, 420, 60, 81)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(0, 420, 60, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(0, 420, 60, 80)));
-
     occlusion.markOccludedBehindLayer(child2.get());
     occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -732,9 +833,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(0, 430, 71, 70)));
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(0, 430, 70, 71)));
 
-    // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface.
-    EXPECT_EQ_RECT(IntRect(0, 430, 10, 70), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(0, 430, 70, 70)));
-
     occlusion.markOccludedBehindLayer(child1.get());
     occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -754,10 +852,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(19, 40, 80, 60)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 39, 80, 60)));
 
-    // |child1| and |child2| both draw into parent so they should not occlude it.
-    EXPECT_EQ_RECT(IntRect(20, 30, 80, 70), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(20, 30, 80, 70)));
-
-
     /* Justification for the above occlusion:
                100
       +---------------------+
@@ -787,7 +881,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionWithOverlappingSiblingSurfaces)
 TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child1 = LayerChromium::create();
@@ -831,6 +924,9 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(-20, -20, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(child2->renderSurface());
     occlusion.markOccludedBehindLayer(layer2.get());
 
@@ -845,9 +941,13 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 71, 80)));
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 81)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(-10, 420, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child2.get(), IntRect(30, 250, 1, 1)));
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 80)));
+    EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-11, 420, 70, 80)));
+    EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 419, 70, 80)));
+    EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 420, 71, 80)));
+    EXPECT_TRUE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 81)));
+    occlusion.setLayerScissorRect(IntRect(-20, -20, 1000, 1000));
 
     occlusion.markOccludedBehindLayer(child2.get());
     occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface());
@@ -866,14 +966,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-10, 430, 81, 70)));
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(-10, 430, 80, 71)));
 
-    // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface.
-    EXPECT_EQ_RECT(IntRect(-10, 430, 10, 80), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(-10, 430, 70, 80)));
-    EXPECT_TRUE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 430, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(-1, 430, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 429, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(1, 430, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(0, 431, 70, 80)));
-
     occlusion.markOccludedBehindLayer(child1.get());
     occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -893,11 +985,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(19, 30, 80, 70)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(20, 29, 80, 70)));
 
-    // |child1| and |child2| both draw into parent so they should not occlude it.
-    EXPECT_EQ_RECT(IntRect(20, 20, 80, 80), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(20, 20, 80, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(50, 50, 1, 1)));
-
-
     /* Justification for the above occlusion:
                100
       +---------------------+
@@ -926,7 +1013,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpace)
 TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromium> child1 = LayerChromium::create();
@@ -975,6 +1061,9 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(-30, -30, 1000, 1000));
+
     occlusion.enterTargetRenderSurface(child2->renderSurface());
     occlusion.markOccludedBehindLayer(layer2.get());
 
@@ -989,10 +1078,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 71, 80)));
     EXPECT_FALSE(occlusion.occluded(child2.get(), IntRect(-10, 420, 70, 81)));
 
-    // Surface is not occluded by things that draw into itself.
-    EXPECT_EQ_RECT(IntRect(-10, 420, 70, 80), occlusion.surfaceUnoccludedContentRect(child2.get(), IntRect(-10, 420, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child2.get(), IntRect(30, 250, 1, 1)));
-
     occlusion.markOccludedBehindLayer(child2.get());
     occlusion.finishedTargetRenderSurface(child2.get(), child2->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -1010,16 +1095,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(420, -19, 80, 90)));
     EXPECT_FALSE(occlusion.occluded(child1.get(), IntRect(421, -20, 80, 90)));
 
-    // Surface is not occluded by things that draw into itself, but the |child1| surface should be occluded by the |child2| surface.
-    EXPECT_EQ_RECT(IntRect(420, -20, 80, 90), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -20, 80, 90)));
-    EXPECT_EQ_RECT(IntRect(490, -10, 10, 80), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -10, 80, 80)));
-    EXPECT_EQ_RECT(IntRect(420, -20, 70, 10), occlusion.surfaceUnoccludedContentRect(child1.get(), IntRect(420, -20, 70, 90)));
-    EXPECT_TRUE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -10, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(419, -10, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -11, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(421, -10, 70, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(child1.get(), IntRect(420, -9, 70, 80)));
-
     occlusion.markOccludedBehindLayer(child1.get());
     occlusion.finishedTargetRenderSurface(child1.get(), child1->renderSurface());
     occlusion.leaveToTargetRenderSurface(parent->renderSurface());
@@ -1035,14 +1110,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(11, 20, 90, 80)));
     EXPECT_FALSE(occlusion.occluded(parent.get(), IntRect(10, 21, 90, 80)));
 
-    // |child1| and |child2| both draw into parent so they should not occlude it.
-    EXPECT_EQ_RECT(IntRect(10, 20, 90, 80), occlusion.surfaceUnoccludedContentRect(parent.get(), IntRect(10, 20, 90, 80)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(10, 20, 1, 1)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(99, 20, 1, 1)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(10, 9, 1, 1)));
-    EXPECT_FALSE(occlusion.surfaceOccluded(parent.get(), IntRect(99, 99, 1, 1)));
-
-
     /* Justification for the above occlusion:
                100
       +---------------------+
@@ -1071,7 +1138,6 @@ TEST(CCOcclusionTrackerTest, surfaceOcclusionInScreenSpaceDifferentTransforms)
 TEST(CCOcclusionTrackerTest, occlusionInteractionWithFilters)
 {
     // This tests that the right transforms are being used.
-    TestCCOcclusionTracker occlusion;
     const TransformationMatrix identityMatrix;
     RefPtr<LayerChromium> parent = LayerChromium::create();
     RefPtr<LayerChromiumWithForcedDrawsContent> blurLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
@@ -1121,6 +1187,9 @@ TEST(CCOcclusionTrackerTest, occlusionInteractionWithFilters)
 
     CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+
     // Opacity layer won't contribute to occlusion.
     occlusion.enterTargetRenderSurface(opacityLayer->renderSurface());
     occlusion.markOccludedBehindLayer(opacityLayer.get());
@@ -1170,4 +1239,778 @@ TEST(CCOcclusionTrackerTest, occlusionInteractionWithFilters)
     EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
 }
 
+TEST(CCOcclusionTrackerTest, layerScissorRectOverTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(200, 100, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(200, 100, 100, 100)));
+
+    occlusion.useDefaultLayerScissorRect();
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(200, 100, 100, 100)));
+    occlusion.setLayerScissorRect(IntRect(200, 100, 100, 100));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(200, 100, 100, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+}
+
+TEST(CCOcclusionTrackerTest, screenScissorRectOverTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(200, 100, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    // Occluded since its outside the surface bounds.
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(200, 100, 100, 100)));
+
+    // Test without any scissors.
+    occlusion.setLayerScissorRect(IntRect(0, 0, 1000, 1000));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(200, 100, 100, 100)));
+    occlusion.useDefaultLayerScissorRect();
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(200, 100, 100, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+}
+
+TEST(CCOcclusionTrackerTest, layerScissorRectOverCulledTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(100, 100, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+}
+
+TEST(CCOcclusionTrackerTest, screenScissorRectOverCulledTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(100, 100, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+}
+
+TEST(CCOcclusionTrackerTest, layerScissorRectOverPartialTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(50, 50, 200, 200));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(50, 50, 200, 200), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+    EXPECT_EQ_RECT(IntRect(200, 50, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_EQ_RECT(IntRect(100, 200, 100, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)));
+}
+
+TEST(CCOcclusionTrackerTest, screenScissorRectOverPartialTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(50, 50, 200, 200));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(50, 50, 200, 200), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+    EXPECT_EQ_RECT(IntRect(200, 50, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_EQ_RECT(IntRect(100, 200, 100, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)));
+}
+
+TEST(CCOcclusionTrackerTest, layerScissorRectOverNoTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+    occlusion.setLayerScissorRect(IntRect(500, 500, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)).isEmpty());
+}
+
+TEST(CCOcclusionTrackerTest, screenScissorRectOverNoTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(500, 500, 100, 100));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)).isEmpty());
+}
+
+TEST(CCOcclusionTrackerTest, layerScissorRectForLayerOffOrigin)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(100, 100), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000));
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    // This layer is translated when drawn into its target. So if the scissor rect given from the target surface
+    // is not in that target space, then after translating these query rects into the target, they will fall outside
+    // the scissor and be considered occluded.
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+}
+
+TEST(CCOcclusionTrackerTest, damageRectOverTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestDamageClient damage(FloatRect(200, 100, 100, 100));
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000), &damage);
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    // Outside the layer's clip rect.
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(200, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(200, 100, 100, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+}
+
+TEST(CCOcclusionTrackerTest, damageRectOverCulledTile)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestDamageClient damage(FloatRect(100, 100, 100, 100));
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000), &damage);
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+}
+
+TEST(CCOcclusionTrackerTest, damageRectOverPartialTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestDamageClient damage(FloatRect(50, 50, 200, 200));
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000), &damage);
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_FALSE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_EQ_RECT(IntRect(50, 50, 200, 200), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)));
+    EXPECT_EQ_RECT(IntRect(200, 50, 50, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)));
+    EXPECT_EQ_RECT(IntRect(200, 100, 50, 100), occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_EQ_RECT(IntRect(100, 200, 100, 50), occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)));
+}
+
+TEST(CCOcclusionTrackerTest, damageRectOverNoTiles)
+{
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> parentLayer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> layer = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    parent->createRenderSurface();
+    parent->addChild(parentLayer);
+    parent->addChild(layer);
+
+    FilterOperations filters;
+    filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::GRAYSCALE));
+    parentLayer->setFilters(filters);
+    layer->setFilters(filters);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(parentLayer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(300, 300), false);
+    setLayerPropertiesForTesting(layer.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(200, 200), true);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint::zero(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent);
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    TestDamageClient damage(FloatRect(500, 500, 100, 100));
+    TestCCOcclusionTracker occlusion(IntRect(0, 0, 1000, 1000), &damage);
+
+    occlusion.enterTargetRenderSurface(layer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(layer.get(), IntRect(100, 100, 100, 100)));
+
+    occlusion.markOccludedBehindLayer(layer.get());
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+    occlusion.enterTargetRenderSurface(parentLayer->renderSurface());
+
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 100, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 0, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(0, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(100, 200, 100, 100)));
+    EXPECT_TRUE(occlusion.occluded(parentLayer.get(), IntRect(200, 200, 100, 100)));
+
+    occlusion.leaveToTargetRenderSurface(parent->renderSurface());
+
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 300)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 0, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(0, 100, 300, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(200, 100, 100, 100)).isEmpty());
+    EXPECT_TRUE(occlusion.unoccludedContentRect(parent.get(), IntRect(100, 200, 100, 100)).isEmpty());
+}
+
 } // namespace