[chromium] Cleanup scissor rect computation/use with damage
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Jun 2012 15:42:14 +0000 (15:42 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 4 Jun 2012 15:42:14 +0000 (15:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=87167

Patch by Zeev Lieber <zlieber@chromium.org> on 2012-06-04
Reviewed by Adrienne Walker.

Source/WebCore:

Performing scissorRect computation during
calculateRenderPasses. Storing scissorRect in shared quad state
instead of computing it during drawQuad. Added scissorRect fields
into layers and render surfaces.

Covered by existing layout tests. Introduced more unit tests to
test end-to-end drawing using mock graphic context, and added more
test cases to CCLayerTreeHostCommon to verify scissorRect computation.

* platform/graphics/chromium/LayerChromium.h:
(WebCore::LayerChromium::scissorRect):
(WebCore::LayerChromium::setScissorRect):
(LayerChromium):
* platform/graphics/chromium/LayerRendererChromium.cpp:
(WebCore::LayerRendererChromium::clearRenderSurface):
(WebCore::LayerRendererChromium::drawRenderPass):
(WebCore::LayerRendererChromium::drawQuad):
(WebCore::LayerRendererChromium::drawRenderSurfaceQuad):
* platform/graphics/chromium/LayerRendererChromium.h:
(LayerRendererChromium):
* platform/graphics/chromium/RenderSurfaceChromium.cpp:
(WebCore::RenderSurfaceChromium::computeRootScissorRectInCurrentSurface):
(WebCore):
* platform/graphics/chromium/RenderSurfaceChromium.h:
(WebCore::RenderSurfaceChromium::scissorRect):
(WebCore::RenderSurfaceChromium::setScissorRect):
(RenderSurfaceChromium):
* platform/graphics/chromium/cc/CCDrawQuad.h:
(WebCore::CCDrawQuad::scissorRect):
* platform/graphics/chromium/cc/CCLayerImpl.cpp:
(WebCore::CCLayerImpl::createSharedQuadState):
* platform/graphics/chromium/cc/CCLayerImpl.h:
(CCLayerImpl):
(WebCore::CCLayerImpl::scissorRect):
(WebCore::CCLayerImpl::setScissorRect):
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore::CCLayerTreeHost::updateLayers):
* platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
(WebCore):
(WebCore::calculateLayerScissorRect):
(WebCore::calculateSurfaceScissorRect):
(WebCore::calculateDrawTransformsInternal):
(WebCore::calculateVisibleAndScissorRectsInternal):
(WebCore::CCLayerTreeHostCommon::calculateDrawTransforms):
(WebCore::CCLayerTreeHostCommon::calculateVisibleAndScissorRects):
* platform/graphics/chromium/cc/CCLayerTreeHostCommon.h:
(CCLayerTreeHostCommon):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
(WebCore::CCLayerTreeHostImpl::calculateRenderSurfaceLayerList):
(WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
(WebCore::CCLayerTreeHostImpl::drawLayers):
(WebCore::CCLayerTreeHostImpl::swapBuffers):
* platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
(CCLayerTreeHostImpl):
* platform/graphics/chromium/cc/CCRenderPass.cpp:
(WebCore::CCRenderPass::appendQuadsForRenderSurfaceLayer):
* platform/graphics/chromium/cc/CCRenderPass.h:
(CCRenderPass):
* platform/graphics/chromium/cc/CCRenderSurface.cpp:
(WebCore::CCRenderSurface::createSharedQuadState):
(WebCore::CCRenderSurface::createReplicaSharedQuadState):
(WebCore):
(WebCore::CCRenderSurface::computeRootScissorRectInCurrentSurface):
(WebCore::CCRenderSurface::appendQuads):
* platform/graphics/chromium/cc/CCRenderSurface.h:
(CCRenderSurface):
(WebCore::CCRenderSurface::setScissorRect):
(WebCore::CCRenderSurface::scissorRect):
* platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.cpp:
(WebCore::CCRenderSurfaceDrawQuad::create):
(WebCore::CCRenderSurfaceDrawQuad::CCRenderSurfaceDrawQuad):
* platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.h:
(CCRenderSurfaceDrawQuad):
* platform/graphics/chromium/cc/CCRenderer.h:
(CCRenderer):
* platform/graphics/chromium/cc/CCSharedQuadState.cpp:
(WebCore::CCSharedQuadState::create):
(WebCore::CCSharedQuadState::CCSharedQuadState):
* platform/graphics/chromium/cc/CCSharedQuadState.h:
(CCSharedQuadState):
(WebCore::CCSharedQuadState::scissorRect):

Source/WebKit/chromium:

Added unit tests to CCLayerTreeHostImpl using mock graphic context
to verify end-to-end quad drawing.

Added more test cases to CCLayerTreeHostCommon to verify clip and
scissor rect computations.

* tests/CCDamageTrackerTest.cpp:
(WebKitTests::executeCalculateDrawTransformsAndVisibility):
* tests/CCLayerIteratorTest.cpp:
* tests/CCLayerTreeHostCommonTest.cpp:
* tests/CCLayerTreeHostImplTest.cpp:
* tests/CCOcclusionTrackerTest.cpp:
(WebKitTests::CCOcclusionTrackerTest::calcDrawEtc):
* tests/CCRenderSurfaceTest.cpp:

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

30 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/LayerChromium.h
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCDrawQuad.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderPass.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderPass.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.h
Source/WebCore/platform/graphics/chromium/cc/CCRenderer.h
Source/WebCore/platform/graphics/chromium/cc/CCSharedQuadState.cpp
Source/WebCore/platform/graphics/chromium/cc/CCSharedQuadState.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCDamageTrackerTest.cpp
Source/WebKit/chromium/tests/CCLayerIteratorTest.cpp
Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp
Source/WebKit/chromium/tests/CCLayerTreeHostImplTest.cpp
Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp
Source/WebKit/chromium/tests/CCRenderSurfaceTest.cpp

index 025899f..dda2b15 100644 (file)
@@ -1,3 +1,92 @@
+2012-06-04  Zeev Lieber  <zlieber@chromium.org>
+
+        [chromium] Cleanup scissor rect computation/use with damage
+        https://bugs.webkit.org/show_bug.cgi?id=87167
+
+        Reviewed by Adrienne Walker.
+
+        Performing scissorRect computation during
+        calculateRenderPasses. Storing scissorRect in shared quad state
+        instead of computing it during drawQuad. Added scissorRect fields
+        into layers and render surfaces.
+
+        Covered by existing layout tests. Introduced more unit tests to
+        test end-to-end drawing using mock graphic context, and added more
+        test cases to CCLayerTreeHostCommon to verify scissorRect computation.
+
+        * platform/graphics/chromium/LayerChromium.h:
+        (WebCore::LayerChromium::scissorRect):
+        (WebCore::LayerChromium::setScissorRect):
+        (LayerChromium):
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::clearRenderSurface):
+        (WebCore::LayerRendererChromium::drawRenderPass):
+        (WebCore::LayerRendererChromium::drawQuad):
+        (WebCore::LayerRendererChromium::drawRenderSurfaceQuad):
+        * platform/graphics/chromium/LayerRendererChromium.h:
+        (LayerRendererChromium):
+        * platform/graphics/chromium/RenderSurfaceChromium.cpp:
+        (WebCore::RenderSurfaceChromium::computeRootScissorRectInCurrentSurface):
+        (WebCore):
+        * platform/graphics/chromium/RenderSurfaceChromium.h:
+        (WebCore::RenderSurfaceChromium::scissorRect):
+        (WebCore::RenderSurfaceChromium::setScissorRect):
+        (RenderSurfaceChromium):
+        * platform/graphics/chromium/cc/CCDrawQuad.h:
+        (WebCore::CCDrawQuad::scissorRect):
+        * platform/graphics/chromium/cc/CCLayerImpl.cpp:
+        (WebCore::CCLayerImpl::createSharedQuadState):
+        * platform/graphics/chromium/cc/CCLayerImpl.h:
+        (CCLayerImpl):
+        (WebCore::CCLayerImpl::scissorRect):
+        (WebCore::CCLayerImpl::setScissorRect):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore::CCLayerTreeHost::updateLayers):
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
+        (WebCore):
+        (WebCore::calculateLayerScissorRect):
+        (WebCore::calculateSurfaceScissorRect):
+        (WebCore::calculateDrawTransformsInternal):
+        (WebCore::calculateVisibleAndScissorRectsInternal):
+        (WebCore::CCLayerTreeHostCommon::calculateDrawTransforms):
+        (WebCore::CCLayerTreeHostCommon::calculateVisibleAndScissorRects):
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.h:
+        (CCLayerTreeHostCommon):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp:
+        (WebCore::CCLayerTreeHostImpl::calculateRenderSurfaceLayerList):
+        (WebCore::CCLayerTreeHostImpl::calculateRenderPasses):
+        (WebCore::CCLayerTreeHostImpl::drawLayers):
+        (WebCore::CCLayerTreeHostImpl::swapBuffers):
+        * platform/graphics/chromium/cc/CCLayerTreeHostImpl.h:
+        (CCLayerTreeHostImpl):
+        * platform/graphics/chromium/cc/CCRenderPass.cpp:
+        (WebCore::CCRenderPass::appendQuadsForRenderSurfaceLayer):
+        * platform/graphics/chromium/cc/CCRenderPass.h:
+        (CCRenderPass):
+        * platform/graphics/chromium/cc/CCRenderSurface.cpp:
+        (WebCore::CCRenderSurface::createSharedQuadState):
+        (WebCore::CCRenderSurface::createReplicaSharedQuadState):
+        (WebCore):
+        (WebCore::CCRenderSurface::computeRootScissorRectInCurrentSurface):
+        (WebCore::CCRenderSurface::appendQuads):
+        * platform/graphics/chromium/cc/CCRenderSurface.h:
+        (CCRenderSurface):
+        (WebCore::CCRenderSurface::setScissorRect):
+        (WebCore::CCRenderSurface::scissorRect):
+        * platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.cpp:
+        (WebCore::CCRenderSurfaceDrawQuad::create):
+        (WebCore::CCRenderSurfaceDrawQuad::CCRenderSurfaceDrawQuad):
+        * platform/graphics/chromium/cc/CCRenderSurfaceDrawQuad.h:
+        (CCRenderSurfaceDrawQuad):
+        * platform/graphics/chromium/cc/CCRenderer.h:
+        (CCRenderer):
+        * platform/graphics/chromium/cc/CCSharedQuadState.cpp:
+        (WebCore::CCSharedQuadState::create):
+        (WebCore::CCSharedQuadState::CCSharedQuadState):
+        * platform/graphics/chromium/cc/CCSharedQuadState.h:
+        (CCSharedQuadState):
+        (WebCore::CCSharedQuadState::scissorRect):
+
 2012-06-04  Kentaro Hara  <haraken@chromium.org>
 
         Remove SelectorQueryCacheEntry from SelectorQuery.h
index e802c36..5d52f8b 100644 (file)
@@ -138,6 +138,9 @@ public:
     const IntRect& visibleLayerRect() const { return m_visibleLayerRect; }
     void setVisibleLayerRect(const IntRect& visibleLayerRect) { m_visibleLayerRect = visibleLayerRect; }
 
+    const IntRect& scissorRect() const { return m_scissorRect; }
+    void setScissorRect(const IntRect& scissorRect) { m_scissorRect = scissorRect; }
+
     void setScrollPosition(const IntPoint&);
     const IntPoint& scrollPosition() const { return m_scrollPosition; }
 
@@ -305,7 +308,15 @@ private:
 
     // Layer properties.
     IntSize m_bounds;
+
+    // Uses layer's content space.
     IntRect m_visibleLayerRect;
+
+    // During drawing, identifies the region outside of which nothing should be drawn.
+    // Currently this is set to layer's clipRect if usesLayerClipping is true, otherwise
+    // it's targetRenderSurface's contentRect.
+    // Uses target surface's space.
+    IntRect m_scissorRect;
     IntPoint m_scrollPosition;
     bool m_scrollable;
     bool m_shouldScrollOnMainThread;
@@ -343,12 +354,16 @@ private:
     OwnPtr<RenderSurfaceChromium> m_renderSurface;
     float m_drawOpacity;
     bool m_drawOpacityIsAnimating;
+
+    // Uses target surface space.
     IntRect m_clipRect;
     RenderSurfaceChromium* m_targetRenderSurface;
     WebKit::WebTransformationMatrix m_drawTransform;
     WebKit::WebTransformationMatrix m_screenSpaceTransform;
     bool m_drawTransformIsAnimating;
     bool m_screenSpaceTransformIsAnimating;
+
+    // Uses target surface space.
     IntRect m_drawableContentRect;
     float m_contentsScale;
 
index 4d90ce5..92e03a3 100644 (file)
@@ -386,7 +386,7 @@ void LayerRendererChromium::viewportChanged()
     m_currentRenderSurface = 0;
 }
 
-void LayerRendererChromium::clearRenderSurface(CCRenderSurface* renderSurface, CCRenderSurface* rootRenderSurface, const FloatRect& surfaceDamageRect)
+void LayerRendererChromium::clearRenderSurface(CCRenderSurface* renderSurface, CCRenderSurface* rootRenderSurface, const FloatRect& rootScissorRectInCurrentSurface)
 {
     // Non-root layers should clear their entire contents to transparent. On DEBUG builds, the root layer
     // is cleared to blue to easily see regions that were not drawn on the screen. If we
@@ -400,7 +400,7 @@ void LayerRendererChromium::clearRenderSurface(CCRenderSurface* renderSurface, C
         GLC(m_context, m_context->clearColor(0, 0, 1, 1));
 
     if (m_capabilities.usingPartialSwap)
-        setScissorToRect(enclosingIntRect(surfaceDamageRect));
+        setScissorToRect(enclosingIntRect(rootScissorRectInCurrentSurface));
     else
         GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
 
@@ -454,36 +454,28 @@ void LayerRendererChromium::doNoOp()
     GLC(m_context, m_context->flush());
 }
 
-void LayerRendererChromium::drawRenderPass(const CCRenderPass* renderPass)
+void LayerRendererChromium::drawRenderPass(const CCRenderPass* renderPass, const FloatRect& rootScissorRectInCurrentSurface)
 {
     CCRenderSurface* renderSurface = renderPass->targetSurface();
     if (!useRenderSurface(renderSurface))
         return;
 
-    clearRenderSurface(renderSurface, m_defaultRenderSurface, renderPass->surfaceDamageRect());
+    clearRenderSurface(renderSurface, m_defaultRenderSurface, rootScissorRectInCurrentSurface);
 
     const CCQuadList& quadList = renderPass->quadList();
     for (CCQuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it)
-        drawQuad(it->get(), renderPass->surfaceDamageRect());
+        drawQuad(it->get());
 }
 
-void LayerRendererChromium::drawQuad(const CCDrawQuad* quad, const FloatRect& surfaceDamageRect)
+void LayerRendererChromium::drawQuad(const CCDrawQuad* quad)
 {
-    IntRect scissorRect;
-    if (m_capabilities.usingPartialSwap) {
-        FloatRect clipAndDamageRect = surfaceDamageRect;
-        if (!quad->clipRect().isEmpty())
-            clipAndDamageRect.intersect(quad->clipRect());
-        scissorRect = enclosingIntRect(clipAndDamageRect);
-        if (scissorRect.isEmpty())
-            return;
-    } else
-        scissorRect = quad->clipRect();
+    IntRect scissorRect = quad->scissorRect();
 
+    ASSERT(!scissorRect.isEmpty());
     if (scissorRect.isEmpty())
-        GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
-    else
-        setScissorToRect(scissorRect);
+        return;
+
+    setScissorToRect(scissorRect);
 
     if (quad->needsBlending())
         GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
@@ -676,9 +668,6 @@ void LayerRendererChromium::drawRenderSurfaceQuad(const CCRenderSurfaceDrawQuad*
 
     drawBackgroundFilters(quad, contentsDeviceTransform);
 
-    // FIXME: Remove this call when the quad's scissorRect() is set correctly.
-    drawingSurface->setScissorRect(this, quad->surfaceDamageRect());
-
     // FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
     // Apply filters to the contents texture.
     SkBitmap filterBitmap = applyFilters(this, quad->filters(), drawingSurface->contentsTexture());
index 2efbdb2..20e8119 100644 (file)
@@ -76,7 +76,7 @@ public:
     const FloatQuad& sharedGeometryQuad() const { return m_sharedGeometryQuad; }
 
     virtual void beginDrawingFrame(CCRenderSurface* defaultRenderSurface) OVERRIDE;
-    virtual void drawRenderPass(const CCRenderPass*) OVERRIDE;
+    virtual void drawRenderPass(const CCRenderPass*, const FloatRect& rootScissorRectInCurrentSurface) OVERRIDE;
     virtual void finishDrawingFrame() OVERRIDE;
 
     virtual void drawHeadsUpDisplay(ManagedTexture*, const IntSize& hudSize) OVERRIDE;
@@ -125,7 +125,7 @@ protected:
 private:
     static void toGLMatrix(float*, const WebKit::WebTransformationMatrix&);
 
-    void drawQuad(const CCDrawQuad*, const FloatRect& surfaceDamageRect);
+    void drawQuad(const CCDrawQuad*);
     void drawCheckerboardQuad(const CCCheckerboardDrawQuad*);
     void drawDebugBorderQuad(const CCDebugBorderDrawQuad*);
     void drawBackgroundFilters(const CCRenderSurfaceDrawQuad*, const WebKit::WebTransformationMatrix& deviceTransform);
@@ -153,7 +153,7 @@ private:
 
     bool bindFramebufferToTexture(ManagedTexture*, const IntRect& viewportRect);
 
-    void clearRenderSurface(CCRenderSurface*, CCRenderSurface* rootRenderSurface, const FloatRect& surfaceDamageRect);
+    void clearRenderSurface(CCRenderSurface*, CCRenderSurface* rootRenderSurface, const FloatRect& rootScissorRectInCurrentSurface);
 
     void releaseRenderSurfaceTextures();
 
index 7ab9ba0..b7fee87 100644 (file)
 #include "FilterOperations.h"
 #include "LayerChromium.h"
 #include "LayerRendererChromium.h"
+#include "cc/CCMathUtil.h"
+#include <public/WebTransformationMatrix.h>
 #include <wtf/text/CString.h>
 
+using WebKit::WebTransformationMatrix;
+
 namespace WebCore {
 
 RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer)
@@ -86,5 +90,11 @@ bool RenderSurfaceChromium::replicaHasMask() const
     return hasReplica() && (m_maskLayer || m_owningLayer->replicaLayer()->maskLayer());
 }
 
+FloatRect RenderSurfaceChromium::computeRootScissorRectInCurrentSurface(const FloatRect& rootScissorRect) const
+{
+    WebTransformationMatrix inverseScreenSpaceTransform = m_screenSpaceTransform.inverse();
+    return CCMathUtil::projectClippedRect(inverseScreenSpaceTransform, rootScissorRect);
+}
+
 }
 #endif // USE(ACCELERATED_COMPOSITING)
index e6711ef..e6e6800 100644 (file)
@@ -91,6 +91,9 @@ public:
     const IntRect& clipRect() const { return m_clipRect; }
     void setClipRect(const IntRect& clipRect) { m_clipRect = clipRect; }
 
+    const IntRect& scissorRect() const { return m_scissorRect; }
+    void setScissorRect(const IntRect& scissorRect) { m_scissorRect = scissorRect; }
+
     void setFilters(const WebKit::WebFilterOperations& filters) { m_filters = filters; }
     const WebKit::WebFilterOperations& filters() const { return m_filters; }
 
@@ -115,10 +118,12 @@ public:
     bool hasMask() const;
     bool replicaHasMask() const;
 
+    FloatRect computeRootScissorRectInCurrentSurface(const FloatRect& rootScissorRect) const;
 private:
     LayerChromium* m_owningLayer;
     LayerChromium* m_maskLayer;
 
+    // Uses this surface's space.
     IntRect m_contentRect;
     bool m_skipsDraw;
 
@@ -134,7 +139,16 @@ private:
     bool m_screenSpaceTransformsAreAnimating;
     WebKit::WebFilterOperations m_filters;
     WebKit::WebFilterOperations m_backgroundFilters;
+
+    // Uses the space of the surface's target surface.
     IntRect m_clipRect;
+
+    // During drawing, identifies the region outside of which nothing should be drawn.
+    // Currently this is set to layer's clipRect if usesLayerClipping is true, otherwise
+    // it's targetRenderSurface's contentRect.
+    // Uses the space of the surface's target surface.
+    IntRect m_scissorRect;
+
     Vector<RefPtr<LayerChromium> > m_layerList;
 
     // The nearest ancestor target surface that will contain the contents of this surface, and that is going
index 381cbae..f2d89f2 100644 (file)
@@ -50,7 +50,7 @@ public:
     const WebKit::WebTransformationMatrix& quadTransform() const { return m_sharedQuadState->quadTransform(); }
     const WebKit::WebTransformationMatrix& layerTransform() const { return m_sharedQuadState->layerTransform(); }
     const IntRect& layerRect() const { return m_sharedQuadState->layerRect(); }
-    const IntRect& clipRect() const { return m_sharedQuadState->clipRect(); }
+    const IntRect& scissorRect() const { return m_sharedQuadState->scissorRect(); }
     float opacity() const { return m_sharedQuadState->opacity(); }
     // For the purposes of blending, what part of the contents of this quad are opaque?
     IntRect opaqueRect() const;
index 93ab178..4a032ae 100644 (file)
@@ -138,10 +138,7 @@ bool CCLayerImpl::descendantDrawsContent()
 
 PassOwnPtr<CCSharedQuadState> CCLayerImpl::createSharedQuadState() const
 {
-    IntRect layerClipRect;
-    if (usesLayerClipping())
-        layerClipRect = clipRect();
-    return CCSharedQuadState::create(quadTransform(), drawTransform(), visibleLayerRect(), layerClipRect, drawOpacity(), opaque());
+    return CCSharedQuadState::create(quadTransform(), drawTransform(), visibleLayerRect(), m_scissorRect, drawOpacity(), opaque());
 }
 
 void CCLayerImpl::willDraw(CCRenderer*, CCGraphicsContext*)
index cdb8c7d..0456269 100644 (file)
@@ -164,6 +164,10 @@ public:
     // Usage: if this->usesLayerClipping() is false, then this clipRect should not be used.
     const IntRect& clipRect() const { return m_clipRect; }
     void setClipRect(const IntRect& rect) { m_clipRect = rect; }
+
+    const IntRect& scissorRect() const { return m_scissorRect; }
+    void setScissorRect(const IntRect& rect) { m_scissorRect = rect; }
+
     CCRenderSurface* targetRenderSurface() const { return m_targetRenderSurface; }
     void setTargetRenderSurface(CCRenderSurface* surface) { m_targetRenderSurface = surface; }
 
@@ -298,6 +302,7 @@ private:
     // Tracks if drawing-related properties have changed since last redraw.
     bool m_layerPropertyChanged;
 
+    // Uses layer's content space.
     IntRect m_visibleLayerRect;
     bool m_masksToBounds;
     bool m_opaque;
@@ -352,17 +357,24 @@ private:
     // The rect that contributes to the scissor when this layer is drawn.
     // Inherited by the parent layer and further restricted if this layer masks
     // to bounds.
+    // Uses target surface's space.
     IntRect m_clipRect;
 
+    // During drawing, identifies the region outside of which nothing should be drawn.
+    // Uses target surface's space.
+    IntRect m_scissorRect;
+
     // Render surface associated with this layer. The layer and its descendants
     // will render to this surface.
     OwnPtr<CCRenderSurface> m_renderSurface;
 
     // Hierarchical bounding rect containing the layer and its descendants.
+    // Uses target surface's space.
     IntRect m_drawableContentRect;
 
     // Rect indicating what was repainted/updated during update.
     // Note that plugin layers bypass this and leave it empty.
+    // Uses layer's content space.
     FloatRect m_updateRect;
 
     // Manages animations for this layer.
index 1659ec5..12510e2 100644 (file)
@@ -518,7 +518,10 @@ void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer, CCTextureUpdater& u
         WebTransformationMatrix identityMatrix;
         WebTransformationMatrix deviceScaleTransform;
         deviceScaleTransform.scale(m_settings.deviceScaleFactor);
-        CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, deviceScaleTransform, identityMatrix, updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize);
+        CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, deviceScaleTransform, identityMatrix, updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize);
+
+        FloatRect rootScissorRect(FloatPoint(0, 0), viewportSize());
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(updateList, rootScissorRect);
     }
 
     // Reset partial texture update requests.
index b5bcabb..9cd0316 100644 (file)
@@ -67,6 +67,43 @@ IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurface
     return layerRect;
 }
 
+template<typename LayerType, typename RenderSurfaceType>
+static IntRect calculateLayerScissorRect(LayerType* layer, const FloatRect& rootScissorRect)
+{
+    RenderSurfaceType* targetSurface = layer->targetRenderSurface();
+
+    FloatRect rootScissorRectInTargetSurface = targetSurface->computeRootScissorRectInCurrentSurface(rootScissorRect);
+    FloatRect clipAndDamage;
+    if (layer->usesLayerClipping())
+        clipAndDamage = intersection(rootScissorRectInTargetSurface, layer->clipRect());
+    else
+        clipAndDamage = intersection(rootScissorRectInTargetSurface, targetSurface->contentRect());
+
+    return enclosingIntRect(clipAndDamage);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+static IntRect calculateSurfaceScissorRect(LayerType* layer, const FloatRect& rootScissorRect)
+{
+    LayerType* parentLayer = layer->parent();
+    RenderSurfaceType* targetSurface = parentLayer->targetRenderSurface();
+    ASSERT(targetSurface);
+
+    RenderSurfaceType* currentSurface = layer->renderSurface();
+    ASSERT(currentSurface);
+
+    FloatRect clipRect = currentSurface->clipRect();
+
+    // For surfaces, empty clipRect means the same as CCLayerImpl::usesLayerClipping being false
+    if (clipRect.isEmpty())
+        clipRect = intersection(targetSurface->contentRect(), currentSurface->drawableContentRect());
+
+    FloatRect rootScissorRectInTargetSurface = targetSurface->computeRootScissorRectInCurrentSurface(rootScissorRect);
+
+    FloatRect clipAndDamage = intersection(rootScissorRectInTargetSurface, clipRect);
+    return enclosingIntRect(clipAndDamage);
+}
+
 template<typename LayerType>
 static inline bool layerIsInExisting3DRenderingContext(LayerType* layer)
 {
@@ -284,7 +321,7 @@ static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlig
 // Recursively walks the layer tree starting at the given node and computes all the
 // necessary transformations, clipRects, render surfaces, etc.
 template<typename LayerType, typename LayerList, typename RenderSurfaceType, typename LayerSorter>
-static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, LayerType* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, RenderSurfaceType* nearestAncestorThatMovesPixels, LayerList& renderSurfaceLayerList, LayerList& layerList, LayerSorter* layerSorter, int maxTextureSize)
+static bool calculateDrawTransformsInternal(LayerType* layer, LayerType* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, RenderSurfaceType* nearestAncestorThatMovesPixels, LayerList& renderSurfaceLayerList, LayerList& layerList, LayerSorter* layerSorter, int maxTextureSize)
 {
     // This function computes the new matrix transformations recursively for this
     // layer and all its descendants. It also computes the appropriate render surfaces.
@@ -572,7 +609,7 @@ static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, Layer
 
     for (size_t i = 0; i < layer->children().size(); ++i) {
         LayerType* child = layer->children()[i].get();
-        bool drawsContent = calculateDrawTransformsAndVisibilityInternal<LayerType, LayerList, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, nearestAncestorThatMovesPixels, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
+        bool drawsContent = calculateDrawTransformsInternal<LayerType, LayerList, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, nearestAncestorThatMovesPixels, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
 
         if (drawsContent) {
             if (child->renderSurface()) {
@@ -693,9 +730,9 @@ static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, Layer
 
 // FIXME: Instead of using the following function to set visibility rects on a second
 // tree pass, revise calculateVisibleLayerRect() so that this can be done in a single
-// pass inside calculateDrawTransformsAndVisibilityInternal<>().
+// pass inside calculateDrawTransformsInternal<>().
 template<typename LayerType, typename LayerList, typename RenderSurfaceType>
-static void walkLayersAndCalculateVisibleLayerRects(const LayerList& renderSurfaceLayerList)
+static void calculateVisibleAndScissorRectsInternal(const LayerList& renderSurfaceLayerList, const FloatRect& rootScissorRect)
 {
     // Use BackToFront since it's cheap and this isn't order-dependent.
     typedef CCLayerIterator<LayerType, LayerList, RenderSurfaceType, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
@@ -706,19 +743,34 @@ static void walkLayersAndCalculateVisibleLayerRects(const LayerList& renderSurfa
             IntRect visibleLayerRect = calculateVisibleLayerRect(*it);
             it->setVisibleLayerRect(visibleLayerRect);
         }
+        if (it.representsItself()) {
+            IntRect scissorRect = calculateLayerScissorRect<LayerType, RenderSurfaceType>(*it, rootScissorRect);
+            it->setScissorRect(scissorRect);
+        } else if (it.representsContributingRenderSurface()) {
+            IntRect scissorRect = calculateSurfaceScissorRect<LayerType, RenderSurfaceType>(*it, rootScissorRect);
+            it->renderSurface()->setScissorRect(scissorRect);
+        }
     }
 }
 
-void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(LayerChromium* layer, LayerChromium* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize)
+void CCLayerTreeHostCommon::calculateDrawTransforms(LayerChromium* layer, LayerChromium* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize)
+{
+    WebCore::calculateDrawTransformsInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, void>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, 0, maxTextureSize);
+}
+
+void CCLayerTreeHostCommon::calculateDrawTransforms(CCLayerImpl* layer, CCLayerImpl* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter* layerSorter, int maxTextureSize)
+{
+    WebCore::calculateDrawTransformsInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
+}
+
+void CCLayerTreeHostCommon::calculateVisibleAndScissorRects(Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, const FloatRect& rootScissorRect)
 {
-    WebCore::calculateDrawTransformsAndVisibilityInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, void>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, 0, maxTextureSize);
-    walkLayersAndCalculateVisibleLayerRects<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium>(renderSurfaceLayerList);
+    calculateVisibleAndScissorRectsInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium>(renderSurfaceLayerList, rootScissorRect);
 }
 
-void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(CCLayerImpl* layer, CCLayerImpl* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter* layerSorter, int maxTextureSize)
+void CCLayerTreeHostCommon::calculateVisibleAndScissorRects(Vector<CCLayerImpl*>& renderSurfaceLayerList, const FloatRect& rootScissorRect)
 {
-    calculateDrawTransformsAndVisibilityInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
-    walkLayersAndCalculateVisibleLayerRects<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface>(renderSurfaceLayerList);
+    calculateVisibleAndScissorRectsInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface>(renderSurfaceLayerList, rootScissorRect);
 }
 
 } // namespace WebCore
index 0585aff..f804516 100644 (file)
@@ -41,8 +41,11 @@ class CCLayerTreeHostCommon {
 public:
     static IntRect calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const WebKit::WebTransformationMatrix&);
 
-    static void calculateDrawTransformsAndVisibility(LayerChromium*, LayerChromium* rootLayer, const WebKit::WebTransformationMatrix& parentMatrix, const WebKit::WebTransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize);
-    static void calculateDrawTransformsAndVisibility(CCLayerImpl*, CCLayerImpl* rootLayer, const WebKit::WebTransformationMatrix& parentMatrix, const WebKit::WebTransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter*, int maxTextureSize);
+    static void calculateDrawTransforms(LayerChromium*, LayerChromium* rootLayer, const WebKit::WebTransformationMatrix& parentMatrix, const WebKit::WebTransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize);
+    static void calculateDrawTransforms(CCLayerImpl*, CCLayerImpl* rootLayer, const WebKit::WebTransformationMatrix& parentMatrix, const WebKit::WebTransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter*, int maxTextureSize);
+
+    static void calculateVisibleAndScissorRects(Vector<CCLayerImpl*>& renderSurfaceLayerList, const FloatRect& rootScissorRect);
+    static void calculateVisibleAndScissorRects(Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, const FloatRect& rootScissorRect);
 
     template<typename LayerType> static bool renderSurfaceContributesToTarget(LayerType*, int targetSurfaceLayerID);
 
index 7d83d20..2ccbf22 100644 (file)
@@ -40,6 +40,7 @@
 #include "cc/CCLayerIterator.h"
 #include "cc/CCLayerTreeHost.h"
 #include "cc/CCLayerTreeHostCommon.h"
+#include "cc/CCMathUtil.h"
 #include "cc/CCPageScaleAnimation.h"
 #include "cc/CCRenderSurfaceDrawQuad.h"
 #include "cc/CCSingleThreadProxy.h"
@@ -230,26 +231,6 @@ void CCLayerTreeHostImpl::trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer,
     }
 }
 
-static FloatRect damageInSurfaceSpace(CCLayerImpl* renderSurfaceLayer, const FloatRect& rootDamageRect)
-{
-    FloatRect surfaceDamageRect;
-    // For now, we conservatively use the root damage as the damage for
-    // all surfaces, except perspective transforms.
-    const WebTransformationMatrix& screenSpaceTransform = renderSurfaceLayer->renderSurface()->screenSpaceTransform();
-    if (screenSpaceTransform.hasPerspective()) {
-        // Perspective projections do not play nice with mapRect of
-        // inverse transforms. In this uncommon case, its simpler to
-        // just redraw the entire surface.
-        // FIXME: use calculateVisibleRect to handle projections.
-        CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface();
-        surfaceDamageRect = renderSurface->contentRect();
-    } else {
-        WebTransformationMatrix inverseScreenSpaceTransform = screenSpaceTransform.inverse();
-        surfaceDamageRect = inverseScreenSpaceTransform.mapRect(rootDamageRect);
-    }
-    return surfaceDamageRect;
-}
-
 void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSurfaceLayerList)
 {
     ASSERT(renderSurfaceLayerList.isEmpty());
@@ -268,7 +249,16 @@ void CCLayerTreeHostImpl::calculateRenderSurfaceLayerList(CCLayerList& renderSur
         WebTransformationMatrix identityMatrix;
         WebTransformationMatrix deviceScaleTransform;
         deviceScaleTransform.scale(m_settings.deviceScaleFactor);
-        CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(m_rootLayerImpl.get(), m_rootLayerImpl.get(), deviceScaleTransform, identityMatrix, renderSurfaceLayerList, m_rootLayerImpl->renderSurface()->layerList(), &m_layerSorter, layerRendererCapabilities().maxTextureSize);
+        CCLayerTreeHostCommon::calculateDrawTransforms(m_rootLayerImpl.get(), m_rootLayerImpl.get(), deviceScaleTransform, identityMatrix, renderSurfaceLayerList, m_rootLayerImpl->renderSurface()->layerList(), &m_layerSorter, layerRendererCapabilities().maxTextureSize);
+
+        if (layerRendererCapabilities().usingPartialSwap || settings().showSurfaceDamageRects)
+            trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList);
+        m_rootScissorRect = m_rootLayerImpl->renderSurface()->damageTracker()->currentDamageRect();
+
+        if (!layerRendererCapabilities().usingPartialSwap)
+            m_rootScissorRect = FloatRect(FloatPoint(0, 0), deviceViewportSize());
+    
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, m_rootScissorRect);
     }
 }
 
@@ -280,9 +270,7 @@ bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
 
     TRACE_EVENT1("webkit", "CCLayerTreeHostImpl::calculateRenderPasses", "renderSurfaceLayerList.size()", static_cast<long long unsigned>(renderSurfaceLayerList.size()));
 
-    if (layerRendererCapabilities().usingPartialSwap || settings().showSurfaceDamageRects)
-        trackDamageForAllSurfaces(m_rootLayerImpl.get(), renderSurfaceLayerList);
-    m_rootDamageRect = m_rootLayerImpl->renderSurface()->damageTracker()->currentDamageRect();
+    m_rootLayerImpl->setScissorRect(enclosingIntRect(m_rootScissorRect));
 
     // Create the render passes in dependency order.
     HashMap<CCRenderSurface*, CCRenderPass*> surfacePassMap;
@@ -291,24 +279,12 @@ bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
         CCRenderSurface* renderSurface = renderSurfaceLayer->renderSurface();
 
         OwnPtr<CCRenderPass> pass = CCRenderPass::create(renderSurface);
-
-        FloatRect surfaceDamageRect;
-        if (layerRendererCapabilities().usingPartialSwap)
-            surfaceDamageRect = damageInSurfaceSpace(renderSurfaceLayer, m_rootDamageRect);
-        pass->setSurfaceDamageRect(surfaceDamageRect);
-
         surfacePassMap.add(renderSurface, pass.get());
         passes.append(pass.release());
     }
 
-    IntRect scissorRect;
-    if (layerRendererCapabilities().usingPartialSwap)
-        scissorRect = enclosingIntRect(m_rootDamageRect);
-    else
-        scissorRect = IntRect(IntPoint(), deviceViewportSize());
-
     bool recordMetricsForFrame = true; // FIXME: In the future, disable this when about:tracing is off.
-    CCOcclusionTrackerImpl occlusionTracker(scissorRect, recordMetricsForFrame);
+    CCOcclusionTrackerImpl occlusionTracker(enclosingIntRect(m_rootScissorRect), recordMetricsForFrame);
     occlusionTracker.setMinimumTrackingSize(CCOcclusionTrackerImpl::preferredMinimumTrackingSize());
 
     // Add quads to the Render passes in FrontToBack order to allow for testing occlusion and performing culling during the tree walk.
@@ -327,9 +303,9 @@ bool CCLayerTreeHostImpl::calculateRenderPasses(CCRenderPassList& passes, CCLaye
 
         occlusionTracker.enterLayer(it);
 
-        if (it.representsContributingRenderSurface())
+        if (it.representsContributingRenderSurface() && !it->renderSurface()->scissorRect().isEmpty())
             pass->appendQuadsForRenderSurfaceLayer(*it, &occlusionTracker);
-        else if (it.representsItself() && !it->visibleLayerRect().isEmpty()) {
+        else if (it.representsItself() && !it->visibleLayerRect().isEmpty() &&  !it->scissorRect().isEmpty()) {
             it->willDraw(m_layerRenderer.get(), context());
             pass->appendQuadsForLayer(*it, &occlusionTracker, hadMissingTiles);
         }
@@ -431,8 +407,12 @@ void CCLayerTreeHostImpl::drawLayers(const FrameData& frame)
     m_fpsCounter->markBeginningOfFrame(currentTime());
     m_layerRenderer->beginDrawingFrame(m_rootLayerImpl->renderSurface());
 
-    for (size_t i = 0; i < frame.renderPasses.size(); ++i)
-        m_layerRenderer->drawRenderPass(frame.renderPasses[i].get());
+    for (size_t i = 0; i < frame.renderPasses.size(); ++i) {
+        CCRenderPass* renderPass = frame.renderPasses[i].get();
+
+        FloatRect rootScissorRectInCurrentSurface = renderPass->targetSurface()->computeRootScissorRectInCurrentSurface(m_rootScissorRect);
+        m_layerRenderer->drawRenderPass(renderPass, rootScissorRectInCurrentSurface);
+    }
 
     if (m_debugRectHistory->enabled(settings()))
         m_debugRectHistory->saveDebugRectsForCurrentFrame(m_rootLayerImpl.get(), frame.renderSurfaceLayerList, settings());
@@ -485,7 +465,7 @@ bool CCLayerTreeHostImpl::swapBuffers()
     ASSERT(m_layerRenderer);
 
     m_fpsCounter->markEndOfFrame();
-    return m_layerRenderer->swapBuffers(enclosingIntRect(m_rootDamageRect));
+    return m_layerRenderer->swapBuffers(enclosingIntRect(m_rootScissorRect));
 }
 
 void CCLayerTreeHostImpl::didLoseContext()
index 90aa0fb..c740a66 100644 (file)
@@ -241,7 +241,7 @@ private:
 
     CCLayerSorter m_layerSorter;
 
-    FloatRect m_rootDamageRect;
+    FloatRect m_rootScissorRect;
 
     OwnPtr<CCFrameRateCounter> m_fpsCounter;
     OwnPtr<CCDebugRectHistory> m_debugRectHistory;
index fd89990..5d34735 100644 (file)
@@ -68,7 +68,7 @@ void CCRenderPass::appendQuadsForRenderSurfaceLayer(CCLayerImpl* layer, CCOcclus
 
     OwnPtr<CCSharedQuadState> sharedQuadState = surface->createSharedQuadState();
     bool isReplica = false;
-    surface->appendQuads(quadCuller, sharedQuadState.get(), isReplica, surfaceDamageRect());
+    surface->appendQuads(quadCuller, sharedQuadState.get(), isReplica);
     m_sharedQuadStateList.append(sharedQuadState.release());
 
     if (!surface->hasReplica())
@@ -77,7 +77,7 @@ void CCRenderPass::appendQuadsForRenderSurfaceLayer(CCLayerImpl* layer, CCOcclus
     // Add replica after the surface so that it appears below the surface.
     OwnPtr<CCSharedQuadState> replicaSharedQuadState = surface->createReplicaSharedQuadState();
     isReplica = true;
-    surface->appendQuads(quadCuller, replicaSharedQuadState.get(), isReplica, surfaceDamageRect());
+    surface->appendQuads(quadCuller, replicaSharedQuadState.get(), isReplica);
     m_sharedQuadStateList.append(replicaSharedQuadState.release());
 }
 
index 452a861..0358eec 100644 (file)
@@ -62,16 +62,12 @@ public:
     const CCQuadList& quadList() const { return m_quadList; }
     CCRenderSurface* targetSurface() const { return m_targetSurface; }
 
-    void setSurfaceDamageRect(const FloatRect& surfaceDamageRect) { m_surfaceDamageRect = surfaceDamageRect; }
-    const FloatRect& surfaceDamageRect() const { return m_surfaceDamageRect; }
-
 private:
     explicit CCRenderPass(CCRenderSurface*);
 
     CCRenderSurface* m_targetSurface;
     CCQuadList m_quadList;
     Vector<OwnPtr<CCSharedQuadState> > m_sharedQuadStateList;
-    FloatRect m_surfaceDamageRect;
 };
 
 typedef Vector<OwnPtr<CCRenderPass> > CCRenderPassList;
index 943c53f..d62f5f9 100644 (file)
 #include "cc/CCDamageTracker.h"
 #include "cc/CCDebugBorderDrawQuad.h"
 #include "cc/CCLayerImpl.h"
+#include "cc/CCMathUtil.h"
 #include "cc/CCQuadCuller.h"
 #include "cc/CCRenderSurfaceDrawQuad.h"
 #include "cc/CCSharedQuadState.h"
+#include <public/WebTransformationMatrix.h>
 #include <wtf/text/CString.h>
 
+using WebKit::WebTransformationMatrix;
+
 namespace WebCore {
 
 static const int debugSurfaceBorderWidth = 2;
@@ -138,20 +142,6 @@ bool CCRenderSurface::hasValidBackgroundTexture() const
     return m_backgroundTexture && m_backgroundTexture->isReserved() && m_backgroundTexture->isValid(m_contentRect.size(), GraphicsContext3D::RGBA);
 }
 
-void CCRenderSurface::setScissorRect(LayerRendererChromium* layerRenderer, const FloatRect& surfaceDamageRect) const
-{
-    if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping() && layerRenderer->capabilities().usingPartialSwap) {
-        FloatRect clipAndDamageRect = m_clipRect;
-        clipAndDamageRect.intersect(surfaceDamageRect);
-        layerRenderer->setScissorToRect(enclosingIntRect(clipAndDamageRect));
-    } else if (layerRenderer->capabilities().usingPartialSwap)
-        layerRenderer->setScissorToRect(enclosingIntRect(surfaceDamageRect));
-    else if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping())
-        layerRenderer->setScissorToRect(m_clipRect);
-    else
-        GLC(layerRenderer->context(), layerRenderer->context()->disable(GraphicsContext3D::SCISSOR_TEST));
-}
-
 String CCRenderSurface::name() const
 {
     return String::format("RenderSurface(id=%i,owner=%s)", m_owningLayer->id(), m_owningLayer->debugName().utf8().data());
@@ -251,16 +241,22 @@ bool CCRenderSurface::surfacePropertyChangedOnlyFromDescendant() const
 PassOwnPtr<CCSharedQuadState> CCRenderSurface::createSharedQuadState() const
 {
     bool isOpaque = false;
-    return CCSharedQuadState::create(originTransform(), drawTransform(), contentRect(), clipRect(), drawOpacity(), isOpaque);
+    return CCSharedQuadState::create(originTransform(), drawTransform(), contentRect(), m_scissorRect, drawOpacity(), isOpaque);
 }
 
 PassOwnPtr<CCSharedQuadState> CCRenderSurface::createReplicaSharedQuadState() const
 {
     bool isOpaque = false;
-    return CCSharedQuadState::create(replicaOriginTransform(), replicaDrawTransform(), contentRect(), clipRect(), drawOpacity(), isOpaque);
+    return CCSharedQuadState::create(replicaOriginTransform(), replicaDrawTransform(), contentRect(), m_scissorRect, drawOpacity(), isOpaque);
+}
+
+FloatRect CCRenderSurface::computeRootScissorRectInCurrentSurface(const FloatRect& rootScissorRect) const
+{
+    WebTransformationMatrix inverseScreenSpaceTransform = m_screenSpaceTransform.inverse();
+    return CCMathUtil::projectClippedRect(inverseScreenSpaceTransform, rootScissorRect);
 }
 
-void CCRenderSurface::appendQuads(CCQuadCuller& quadList, CCSharedQuadState* sharedQuadState, bool forReplica, const FloatRect& surfaceDamageRect)
+void CCRenderSurface::appendQuads(CCQuadCuller& quadList, CCSharedQuadState* sharedQuadState, bool forReplica)
 {
     ASSERT(!forReplica || hasReplica());
 
@@ -290,7 +286,7 @@ void CCRenderSurface::appendQuads(CCQuadCuller& quadList, CCSharedQuadState* sha
 
     int maskTextureId = maskLayer ? maskLayer->contentsTextureId() : 0;
 
-    quadList.appendSurface(CCRenderSurfaceDrawQuad::create(sharedQuadState, contentRect(), m_owningLayer, surfaceDamageRect, forReplica, filters(), backgroundFilters(), maskTextureId));
+    quadList.appendSurface(CCRenderSurfaceDrawQuad::create(sharedQuadState, contentRect(), m_owningLayer, forReplica, filters(), backgroundFilters(), maskTextureId));
 }
 
 }
index 855fcce..c4bb999 100644 (file)
@@ -60,8 +60,6 @@ public:
     void releaseBackgroundTexture();
     bool hasValidBackgroundTexture() const;
 
-    void setScissorRect(LayerRendererChromium*, const FloatRect& surfaceDamageRect) const;
-
     String name() const;
     void dumpSurface(TextStream&, int indent) const;
 
@@ -112,6 +110,9 @@ public:
     void setClipRect(const IntRect&);
     const IntRect& clipRect() const { return m_clipRect; }
 
+    void setScissorRect(const IntRect& scissorRect) { m_scissorRect = scissorRect; }
+    const IntRect& scissorRect() const { return m_scissorRect; }
+
     void setContentRect(const IntRect&);
     const IntRect& contentRect() const { return m_contentRect; }
 
@@ -138,12 +139,13 @@ public:
     PassOwnPtr<CCSharedQuadState> createSharedQuadState() const;
     PassOwnPtr<CCSharedQuadState> createReplicaSharedQuadState() const;
 
-    // FIXME: Remove the surfaceDamageRect parameter when the value is removed from CCRenderSurfaceDrawQuad.
-    void appendQuads(CCQuadCuller&, CCSharedQuadState*, bool forReplica, const FloatRect& surfaceDamageRect);
+    void appendQuads(CCQuadCuller&, CCSharedQuadState*, bool forReplica);
+    FloatRect computeRootScissorRectInCurrentSurface(const FloatRect& rootScissorRect) const;
 
 private:
     CCLayerImpl* m_owningLayer;
 
+    // Uses this surface's space.
     IntRect m_contentRect;
     bool m_surfacePropertyChanged;
 
@@ -162,7 +164,14 @@ private:
     bool m_screenSpaceTransformsAreAnimating;
     WebKit::WebFilterOperations m_filters;
     WebKit::WebFilterOperations m_backgroundFilters;
+
+    // Uses the space of the surface's target surface.
     IntRect m_clipRect;
+
+    // During drawing, identifies the region outside of which nothing should be drawn.
+    // Uses the space of the surface's target surface.
+    IntRect m_scissorRect;
+
     Vector<CCLayerImpl*> m_layerList;
 
     // The nearest ancestor target surface that will contain the contents of this surface, and that is going
@@ -171,9 +180,6 @@ private:
 
     OwnPtr<CCDamageTracker> m_damageTracker;
 
-    // Stored in the "surface space" where this damage can be used for scissoring.
-    FloatRect m_damageRect;
-
     // For CCLayerIteratorActions
     int m_targetRenderSurfaceLayerIndexHistory;
     int m_currentLayerIndexHistory;
index df00c0e..5742382 100644 (file)
 
 namespace WebCore {
 
-PassOwnPtr<CCRenderSurfaceDrawQuad> CCRenderSurfaceDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer, const FloatRect& surfaceDamageRect, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId)
+PassOwnPtr<CCRenderSurfaceDrawQuad> CCRenderSurfaceDrawQuad::create(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId)
 {
-    return adoptPtr(new CCRenderSurfaceDrawQuad(sharedQuadState, quadRect, layer, surfaceDamageRect, isReplica, filters, backgroundFilters, maskTextureId));
+    return adoptPtr(new CCRenderSurfaceDrawQuad(sharedQuadState, quadRect, layer, isReplica, filters, backgroundFilters, maskTextureId));
 }
 
-CCRenderSurfaceDrawQuad::CCRenderSurfaceDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer, const FloatRect& surfaceDamageRect, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId)
+CCRenderSurfaceDrawQuad::CCRenderSurfaceDrawQuad(const CCSharedQuadState* sharedQuadState, const IntRect& quadRect, CCLayerImpl* layer, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId)
     : CCDrawQuad(sharedQuadState, CCDrawQuad::RenderSurface, quadRect)
     , m_layer(layer)
-    , m_surfaceDamageRect(surfaceDamageRect)
     , m_isReplica(isReplica)
     , m_filters(filters)
     , m_backgroundFilters(backgroundFilters)
index 0a01281..edaee24 100644 (file)
@@ -37,24 +37,19 @@ class CCLayerImpl;
 class CCRenderSurfaceDrawQuad : public CCDrawQuad {
     WTF_MAKE_NONCOPYABLE(CCRenderSurfaceDrawQuad);
 public:
-    static PassOwnPtr<CCRenderSurfaceDrawQuad> create(const CCSharedQuadState*, const IntRect&, CCLayerImpl*, const FloatRect& surfaceDamageRect, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId);
+    static PassOwnPtr<CCRenderSurfaceDrawQuad> create(const CCSharedQuadState*, const IntRect&, CCLayerImpl*, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId);
 
     CCLayerImpl* layer() const { return m_layer; }
     bool isReplica() const { return m_isReplica; }
     unsigned maskTextureId() const { return m_maskTextureId; }
 
-    // The surface damage rect for the target surface this quad draws into.
-    // FIXME: This can be removed once render surfaces get their own layer type.
-    const FloatRect& surfaceDamageRect() const { return m_surfaceDamageRect; }
-
     const WebKit::WebFilterOperations& filters() const { return m_filters; }
     const WebKit::WebFilterOperations& backgroundFilters() const { return m_backgroundFilters; }
 
 private:
-    CCRenderSurfaceDrawQuad(const CCSharedQuadState*, const IntRect&, CCLayerImpl*, const FloatRect& surfaceDamageRect, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId);
+    CCRenderSurfaceDrawQuad(const CCSharedQuadState*, const IntRect&, CCLayerImpl*, bool isReplica, const WebKit::WebFilterOperations& filters, const WebKit::WebFilterOperations& backgroundFilters, unsigned maskTextureId);
 
     CCLayerImpl* m_layer;
-    FloatRect m_surfaceDamageRect;
     bool m_isReplica;
     WebKit::WebFilterOperations m_filters;
     WebKit::WebFilterOperations m_backgroundFilters;
index 3a45515..a1aa33f 100644 (file)
@@ -69,7 +69,7 @@ public:
     const WebKit::WebTransformationMatrix& windowMatrix() const { return m_windowMatrix; }
 
     virtual void beginDrawingFrame(CCRenderSurface* defaultRenderSurface) = 0;
-    virtual void drawRenderPass(const CCRenderPass*) = 0;
+    virtual void drawRenderPass(const CCRenderPass*, const FloatRect& rootScissorRectInCurrentSurface) = 0;
     virtual void finishDrawingFrame() = 0;
 
     virtual void drawHeadsUpDisplay(ManagedTexture*, const IntSize& hudSize) = 0;
index 3f2837e..536b398 100644 (file)
@@ -31,16 +31,16 @@ using WebKit::WebTransformationMatrix;
 
 namespace WebCore {
 
-PassOwnPtr<CCSharedQuadState> CCSharedQuadState::create(const WebTransformationMatrix& quadTransform, const WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& clipRect, float opacity, bool opaque)
+PassOwnPtr<CCSharedQuadState> CCSharedQuadState::create(const WebTransformationMatrix& quadTransform, const WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& scissorRect, float opacity, bool opaque)
 {
-    return adoptPtr(new CCSharedQuadState(quadTransform, layerTransform, layerRect, clipRect, opacity, opaque));
+    return adoptPtr(new CCSharedQuadState(quadTransform, layerTransform, layerRect, scissorRect, opacity, opaque));
 }
 
-CCSharedQuadState::CCSharedQuadState(const WebTransformationMatrix& quadTransform, const WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& clipRect, float opacity, bool opaque)
+CCSharedQuadState::CCSharedQuadState(const WebTransformationMatrix& quadTransform, const WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& scissorRect, float opacity, bool opaque)
     : m_quadTransform(quadTransform)
     , m_layerTransform(layerTransform)
     , m_layerRect(layerRect)
-    , m_clipRect(clipRect)
+    , m_scissorRect(scissorRect)
     , m_opacity(opacity)
     , m_opaque(opaque)
 {
index a14b17d..4540a06 100644 (file)
@@ -36,27 +36,26 @@ namespace WebCore {
 class CCSharedQuadState {
     WTF_MAKE_NONCOPYABLE(CCSharedQuadState);
 public:
-    static PassOwnPtr<CCSharedQuadState> create(const WebKit::WebTransformationMatrix& quadTransform, const WebKit::WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& clipRect, float opacity, bool opaque);
+    static PassOwnPtr<CCSharedQuadState> create(const WebKit::WebTransformationMatrix& quadTransform, const WebKit::WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& scissorRect, float opacity, bool opaque);
 
     // The transform that quads in a CCDrawQuad should be transformed with.
     const WebKit::WebTransformationMatrix& quadTransform() const { return m_quadTransform; }
     // The transform that layerRect() should be transformed with.
     const WebKit::WebTransformationMatrix& layerTransform() const { return m_layerTransform; }
     const IntRect& layerRect() const { return m_layerRect; }
-    // Usage: if clipRect is empty, this clipRect should not be used.
-    const IntRect& clipRect() const { return m_clipRect; }
+    const IntRect& scissorRect() const { return m_scissorRect; }
 
     float opacity() const { return m_opacity; }
     bool isOpaque() const { return m_opaque; }
     bool isLayerAxisAlignedIntRect() const;
 
 private:
-    CCSharedQuadState(const WebKit::WebTransformationMatrix& quadTransform, const WebKit::WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& clipRect, float opacity, bool opaque);
+    CCSharedQuadState(const WebKit::WebTransformationMatrix& quadTransform, const WebKit::WebTransformationMatrix& layerTransform, const IntRect& layerRect, const IntRect& scissorRect, float opacity, bool opaque);
 
     WebKit::WebTransformationMatrix m_quadTransform;
     WebKit::WebTransformationMatrix m_layerTransform;
     IntRect m_layerRect;
-    IntRect m_clipRect;
+    IntRect m_scissorRect;
     float m_opacity;
     bool m_opaque;
 };
index 19447ca..6db5cd9 100644 (file)
@@ -1,3 +1,25 @@
+2012-06-04  Zeev Lieber  <zlieber@chromium.org>
+
+        [chromium] Cleanup scissor rect computation/use with damage
+        https://bugs.webkit.org/show_bug.cgi?id=87167
+
+        Reviewed by Adrienne Walker.
+
+        Added unit tests to CCLayerTreeHostImpl using mock graphic context
+        to verify end-to-end quad drawing.
+
+        Added more test cases to CCLayerTreeHostCommon to verify clip and
+        scissor rect computations.
+
+        * tests/CCDamageTrackerTest.cpp:
+        (WebKitTests::executeCalculateDrawTransformsAndVisibility):
+        * tests/CCLayerIteratorTest.cpp:
+        * tests/CCLayerTreeHostCommonTest.cpp:
+        * tests/CCLayerTreeHostImplTest.cpp:
+        * tests/CCOcclusionTrackerTest.cpp:
+        (WebKitTests::CCOcclusionTrackerTest::calcDrawEtc):
+        * tests/CCRenderSurfaceTest.cpp:
+
 2012-06-03  Ryosuke Niwa  <rniwa@webkit.org>
 
         Roll Chromium DEPS from r140222 to r140260.
index 56d85fa..08ea035 100644 (file)
@@ -58,7 +58,8 @@ void executeCalculateDrawTransformsAndVisibility(CCLayerImpl* root, Vector<CCLay
 
     root->renderSurface()->clearLayerList();
     renderSurfaceLayerList.append(root);
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, &layerSorter, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, &layerSorter, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, root->renderSurface()->contentRect());
 }
 
 void emulateDrawingOneFrame(CCLayerImpl* root)
index 105c718..5fc625f 100644 (file)
@@ -140,10 +140,11 @@ TEST(CCLayerIteratorTest, simpleTree)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > layerList;
     renderSurfaceLayerList.append(rootLayer.get());
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
-                                                                WebTransformationMatrix(), WebTransformationMatrix(),
-                                                                renderSurfaceLayerList, layerList,
-                                                                256);
+    CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+                                                   WebTransformationMatrix(), WebTransformationMatrix(),
+                                                   renderSurfaceLayerList, layerList,
+                                                   256);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
 
     iterateBackToFront(&renderSurfaceLayerList);
     EXPECT_COUNT(rootLayer, 0, -1, 1);
@@ -187,10 +188,11 @@ TEST(CCLayerIteratorTest, complexTree)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > layerList;
     renderSurfaceLayerList.append(rootLayer.get());
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
-                                                                WebTransformationMatrix(), WebTransformationMatrix(),
-                                                                renderSurfaceLayerList, layerList,
-                                                                256);
+    CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+                                                   WebTransformationMatrix(), WebTransformationMatrix(),
+                                                   renderSurfaceLayerList, layerList,
+                                                   256);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
 
     iterateBackToFront(&renderSurfaceLayerList);
     EXPECT_COUNT(rootLayer, 0, -1, 1);
@@ -246,10 +248,11 @@ TEST(CCLayerIteratorTest, complexTreeMultiSurface)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > layerList;
     renderSurfaceLayerList.append(rootLayer.get());
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer.get(), rootLayer.get(),
-                                                                WebTransformationMatrix(), WebTransformationMatrix(),
-                                                                renderSurfaceLayerList, layerList,
-                                                                256);
+    CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer.get(), rootLayer.get(),
+                                                   WebTransformationMatrix(), WebTransformationMatrix(),
+                                                   renderSurfaceLayerList, layerList,
+                                                   256);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
 
     iterateBackToFront(&renderSurfaceLayerList);
     EXPECT_COUNT(rootLayer, 0, -1, 1);
index fce9046..1d069a5 100644 (file)
 #include "LayerChromium.h"
 #include "TranslateTransformOperation.h"
 #include "cc/CCLayerAnimationController.h"
+#include "cc/CCLayerImpl.h"
+#include "cc/CCLayerSorter.h"
 #include "cc/CCMathUtil.h"
+#include "cc/CCProxy.h"
+#include "cc/CCSingleThreadProxy.h"
+#include "cc/CCThread.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -59,7 +64,8 @@ void executeCalculateDrawTransformsAndVisibility(LayerChromium* rootLayer)
     Vector<RefPtr<LayerChromium> > dummyRenderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > dummyLayerList;
     int dummyMaxTextureSize = 512;
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(rootLayer, rootLayer, identityMatrix, identityMatrix, dummyRenderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, identityMatrix, identityMatrix, dummyRenderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(dummyRenderSurfaceLayerList, rootLayer->renderSurface()->contentRect());
 }
 
 WebTransformationMatrix remove3DComponentOfMatrix(const WebTransformationMatrix& mat)
@@ -175,7 +181,7 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleLayer)
     EXPECT_TRANSFORMATION_MATRIX_EQ(expectedResult, layer->screenSpaceTransform());
 
     // Case 7: Verify that position pre-multiplies the layer transform.
-    //         The current implementation of calculateDrawTransformsAndVisibility does this implicitly, but it is
+    //         The current implementation of calculateDrawTransforms does this implicitly, but it is
     //         still worth testing to detect accidental regressions.
     expectedResult = positionTransform * translationToAnchor * layerTransform * translationToAnchor.inverse();
     setLayerPropertiesForTesting(layer.get(), layerTransform, identityMatrix, FloatPoint(0.5f, 0.0f), FloatPoint(5.0f, 1.2f), IntSize(10, 12), false);
@@ -318,6 +324,558 @@ TEST(CCLayerTreeHostCommonTest, verifyTransformsForSingleRenderSurface)
     EXPECT_TRANSFORMATION_MATRIX_EQ(parentCompositeTransform, child->targetRenderSurface()->screenSpaceTransform());
 }
 
+TEST(CCLayerTreeHostCommonTest, scissorRectNoClip)
+{
+    DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+    /*
+      Layers are created as follows:
+
+         +--------------------+
+         |                  1 |
+         |  +-----------+     |
+         |  |         2 |     |
+         |  | +-------------------+
+         |  | |   3               |
+         |  | +-------------------+
+         |  |           |     |
+         |  +-----------+     |
+         |                    |
+         |                    |
+         +--------------------+
+
+         Layers 1, 2 have render surfaces
+     */
+    OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+    OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+    OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+
+    IntRect rootRect(0, 0, 100, 100);
+    IntRect childRect(10, 10, 50, 50);
+    IntRect grandChildRect(5, 5, 150, 150);
+
+    root->createRenderSurface();
+    root->setAnchorPoint(FloatPoint(0, 0));
+    root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+    root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+    root->setDrawsContent(true);
+    root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+    child->setAnchorPoint(FloatPoint(0, 0));
+    child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+    child->setOpacity(0.5f);
+    child->setBounds(IntSize(childRect.width(), childRect.height()));
+    child->setDrawsContent(true);
+
+    grandChild->setAnchorPoint(FloatPoint(0, 0));
+    grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+    grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+    grandChild->setDrawsContent(true);
+
+    CCLayerImpl* childPtr = child.get();
+    CCLayerImpl* grandChildPtr = grandChild.get();
+
+    child->addChild(grandChild.release());
+    root->addChild(child.release());
+
+    Vector<CCLayerImpl*> renderSurfaceLayerList;
+    {
+        WebTransformationMatrix identityMatrix;
+        Vector<CCLayerImpl*> layerList;
+        int dummyMaxTextureSize = 512;
+        CCLayerSorter layerSorter;
+
+        renderSurfaceLayerList.append(root.get());
+
+        CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+        FloatRect dummyDamageRect;
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+    }
+    
+    ASSERT_TRUE(childPtr->renderSurface());
+    ASSERT_TRUE(root->renderSurface());
+    ASSERT_FALSE(grandChildPtr->renderSurface());
+    
+    EXPECT_EQ(renderSurfaceLayerList.size(), 2U);
+    
+    ASSERT_EQ(root->clipRect(), IntRect(0, 0, 0, 0));
+
+    // Layer's clipRect is a union of all its children's bounds
+    ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+    ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, 0, 0));
+
+    ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+    ASSERT_EQ(childPtr->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+    
+    ASSERT_FALSE(root->usesLayerClipping());
+    ASSERT_FALSE(childPtr->usesLayerClipping());
+    ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+    
+    // Damage the entire screen
+    IntRect rootDamage(rootRect);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // child surface doesn't have a clip rect, therefore it will be computed as intersection
+    // between root surface's contentrect and child surface's drawable content rect.
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(childRect.x(), childRect.y(), rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+    EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+    // The damage is the entire rootRect, but child layer starts at an offset.
+    // Even though it has bounds, it is not clipping to bounds so its children
+    // (which extend beyond the bounds) extend the scissor rect
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+    // Grand child will have the same scissor rect as it doesn't have a surface
+    // of its own
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+    
+    // Empty damage
+    rootDamage = IntRect(0, 0, 0, 0);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Empty damage == empty scissor
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    // Partial damage within child
+    rootDamage = IntRect(10, 10, 20, 20);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child does not have its own surface, so its scissor rect is identical to child's
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Partial damage beyond child
+    rootDamage = IntRect(10, 10, 80, 80);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child does not have its own surface, so its scissor rect is identical to child's
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Partial damage beyond root
+    rootDamage = IntRect(10, 10, 110, 110);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+    
+    // Root does not use layer clipping, so its content rect will be used to intersect with damage
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+    // Children's content rects are bigger than the root's so they don't clip the damage rect, but change its offset.
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+}
+
+TEST(CCLayerTreeHostCommonTest, scissorRectWithClip)
+{
+    DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+    /*
+      Layers are created as follows:
+
+         +--------------------+
+         |                  1 |
+         |  +-----------+     |
+         |  |         2 |     |
+         |  | +-------------------+
+         |  | |   3               |
+         |  | +-------------------+
+         |  |           |     |
+         |  +-----------+     |
+         |                    |
+         |                    |
+         +--------------------+
+
+         Layers 1, 2 have render surfaces
+     */
+    OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+    OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+    OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+
+    IntRect rootRect(0, 0, 100, 100);
+    IntRect childRect(10, 10, 50, 50);
+    IntRect grandChildRect(5, 5, 150, 150);
+
+    root->createRenderSurface();
+    root->setAnchorPoint(FloatPoint(0, 0));
+    root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+    root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+    root->setDrawsContent(true);
+    root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+    child->setAnchorPoint(FloatPoint(0, 0));
+    child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+    child->setOpacity(0.5f);
+    child->setBounds(IntSize(childRect.width(), childRect.height()));
+    child->setDrawsContent(true);
+
+    grandChild->setAnchorPoint(FloatPoint(0, 0));
+    grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+    grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+    grandChild->setDrawsContent(true);
+
+    CCLayerImpl* childPtr = child.get();
+    CCLayerImpl* grandChildPtr = grandChild.get();
+
+    child->addChild(grandChild.release());
+    root->addChild(child.release());
+
+    root->setMasksToBounds(true);
+
+    Vector<CCLayerImpl*> renderSurfaceLayerList;
+    {
+        WebTransformationMatrix identityMatrix;
+        Vector<CCLayerImpl*> layerList;
+        int dummyMaxTextureSize = 512;
+        CCLayerSorter layerSorter;
+
+        renderSurfaceLayerList.append(root.get());
+
+        CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+        FloatRect dummyDamageRect;
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+    }
+    
+    ASSERT_TRUE(childPtr->renderSurface());
+    ASSERT_TRUE(root->renderSurface());
+    ASSERT_FALSE(grandChildPtr->renderSurface());
+    
+    EXPECT_EQ(renderSurfaceLayerList.size(), 2U);
+    
+    // Now root is clipping to its bounds
+    ASSERT_EQ(root->clipRect(), rootRect);
+
+    // Layer's clipRect is a union of all its children's bounds
+    ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+    ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, 0, 0));
+
+    ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+
+    // Child surface's clipping rect is now set to root's
+    ASSERT_EQ(childPtr->renderSurface()->clipRect(), rootRect);
+    
+    ASSERT_TRUE(root->usesLayerClipping());
+    ASSERT_FALSE(childPtr->usesLayerClipping());
+    ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+    
+    // Damage the entire screen
+    IntRect rootDamage(rootRect);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootRect));
+    
+    EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+    // The damage is the entire rootRect, but child layer starts at an offset.
+    // Even though it has bounds, it is not clipping to bounds so its children
+    // (which extend beyond the bounds) extend the scissor rect
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+    // Grand child will have the same scissor rect as it doesn't have a surface
+    // of its own
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+    
+    // Empty damage
+    rootDamage = IntRect(0, 0, 0, 0);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Empty damage == empty scissor
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    // Partial damage within child
+    rootDamage = IntRect(10, 10, 20, 20);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child does not have its own surface, so its scissor rect is identical to child's
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Partial damage beyond child
+    rootDamage = IntRect(10, 10, 80, 80);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child does not have its own surface, so its scissor rect is identical to child's
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Partial damage beyond root
+    rootDamage = IntRect(10, 10, 110, 110);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+    
+    // Root does not use layer clipping, so its content rect will be used to intersect with damage
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+    // Now the scissor rects are clipped by surfaces contentRect
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+}
+
+TEST(CCLayerTreeHostCommonTest, scissorRectWithClipAndSpaceTransform)
+{
+    DebugScopedSetImplThread thisScopeIsOnImplThread;
+
+    /*
+      Layers are created as follows:
+
+         +--------------------+
+         |                  1 |
+         |  +-----------+     |
+         |  |         2 |     |
+         |  | +-------------------+
+         |  | |   3,4             |
+         |  | +-------------------+
+         |  |           |     |
+         |  +-----------+     |
+         |                    |
+         |                    |
+         +--------------------+
+
+         Layers 1, 2 and 3 have render surfaces
+     */
+    OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+    OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+    OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
+    OwnPtr<CCLayerImpl> grandChild2 = CCLayerImpl::create(4);
+
+    IntRect rootRect(0, 0, 100, 100);
+    IntRect childRect(10, 10, 50, 50);
+    IntRect grandChildRect(5, 5, 150, 150);
+
+    root->createRenderSurface();
+    root->setAnchorPoint(FloatPoint(0, 0));
+    root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+    root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+    root->setDrawsContent(true);
+    root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+    child->setAnchorPoint(FloatPoint(0, 0));
+    child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+    child->setOpacity(0.5f);
+    child->setBounds(IntSize(childRect.width(), childRect.height()));
+    child->setDrawsContent(true);
+
+    grandChild->setAnchorPoint(FloatPoint(0, 0));
+    grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+    grandChild->setOpacity(0.5f);
+    grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+    grandChild->setDrawsContent(true);
+
+    grandChild2->setAnchorPoint(FloatPoint(0, 0));
+    grandChild2->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+    grandChild2->setOpacity(0.5f);
+    grandChild2->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+    grandChild2->setDrawsContent(true);
+
+    CCLayerImpl* childPtr = child.get();
+    CCLayerImpl* grandChildPtr = grandChild.get();
+
+    grandChild->addChild(grandChild2.release());
+    child->addChild(grandChild.release());
+    root->addChild(child.release());
+
+    root->setMasksToBounds(true);
+
+    Vector<CCLayerImpl*> renderSurfaceLayerList;
+    {
+        WebTransformationMatrix identityMatrix;
+        Vector<CCLayerImpl*> layerList;
+        int dummyMaxTextureSize = 512;
+        CCLayerSorter layerSorter;
+
+        renderSurfaceLayerList.append(root.get());
+
+        CCLayerTreeHostCommon::calculateDrawTransforms(root.get(), root.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, layerList, &layerSorter, dummyMaxTextureSize);
+
+        FloatRect dummyDamageRect;
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, dummyDamageRect);
+    }
+    
+    ASSERT_TRUE(childPtr->renderSurface());
+    ASSERT_TRUE(root->renderSurface());
+    ASSERT_TRUE(grandChildPtr->renderSurface());
+    
+    EXPECT_EQ(renderSurfaceLayerList.size(), 3U);
+    
+    // Now root is clipping to its bounds
+    ASSERT_EQ(root->clipRect(), rootRect);
+
+    ASSERT_EQ(childPtr->clipRect(), IntRect(0, 0, childRect.x() + grandChildRect.width() , childRect.y() + grandChildRect.height()));
+
+    // Grandchild now clips
+    ASSERT_EQ(grandChildPtr->clipRect(), IntRect(0, 0, grandChildRect.x() + grandChildRect.width(), grandChildRect.y() + grandChildRect.height()));
+
+    ASSERT_EQ(root->renderSurface()->clipRect(), IntRect(0, 0, 0, 0));
+
+    // Child surface's clipping rect is now set to root's
+    ASSERT_EQ(childPtr->renderSurface()->clipRect(), rootRect);
+    
+    ASSERT_TRUE(root->usesLayerClipping());
+    ASSERT_FALSE(childPtr->usesLayerClipping());
+    ASSERT_FALSE(grandChildPtr->usesLayerClipping());
+    
+    // Damage the entire screen
+    IntRect rootDamage(rootRect);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootRect));
+    
+    EXPECT_EQ(root->scissorRect(), IntRect(rootRect));
+
+    // The damage is the entire rootRect, but child layer starts at an offset.
+    // Even though it has bounds, it is not clipping to bounds so its children
+    // (which extend beyond the bounds) extend the scissor rect
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x(), rootRect.height() - childRect.y()));
+
+    // Grand child is now scissored by the render surface
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, rootRect.width() - childRect.x() - grandChildRect.x(), rootRect.height() - childRect.y() - grandChildRect.y()));
+    
+    // Empty damage
+    rootDamage = IntRect(0, 0, 0, 0);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Empty damage == empty scissor
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    EXPECT_EQ(root->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(0, 0, 0, 0));
+    
+    // Partial damage within child
+    rootDamage = IntRect(10, 10, 20, 20);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child now gets scissored by its target surface as well as root
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+
+    // Partial damage beyond child
+    rootDamage = IntRect(10, 10, 80, 80);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Entire damage rect is within the root surface
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), rootDamage);
+    
+    // Entire damage rect is within the layer
+    EXPECT_EQ(root->scissorRect(), rootDamage);
+
+    // Entire damage rect is within the layer, but with different offset
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width(), rootDamage.height()));
+
+    // Grand child now gets scissored by its target surface as well as root
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+
+    // Partial damage beyond root
+    rootDamage = IntRect(10, 10, 110, 110);
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, rootDamage);
+    
+    // Scissors are not computed for root
+    EXPECT_EQ(root->targetRenderSurface()->scissorRect(), IntRect(0, 0, 0, 0));
+
+    // Root surface does not have a clipRect, so its contentRect will be used to intersect with damage.
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(childPtr->targetRenderSurface()->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+    
+    // Root does not use layer clipping, so its content rect will be used to intersect with damage
+    // Result is that root damage rect is clipped at root layer boundary
+    EXPECT_EQ(root->scissorRect(), IntRect(rootDamage.x(), rootDamage.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+    // Now the scissor rects are clipped by surfaces contentRect
+    EXPECT_EQ(childPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootRect.width() - rootDamage.x(), rootRect.height() - rootDamage.y()));
+
+    // Grandchild's scissor rect is clipped by its target surface
+    EXPECT_EQ(grandChildPtr->scissorRect(), IntRect(rootDamage.x() - childRect.x(), rootDamage.y() - childRect.y(), rootDamage.width() - grandChildRect.x(), rootDamage.height() - grandChildRect.y()));
+}
+
 TEST(CCLayerTreeHostCommonTest, verifyTransformsForReplica)
 {
     RefPtr<LayerChromium> parent = LayerChromium::create();
@@ -545,7 +1103,10 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForClipLayer)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > dummyLayerList;
     int dummyMaxTextureSize = 512;
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    FloatRect dummyDamageRect;
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
 
     // The child layer's content is entirely outside the parent's clip rect, so the intermediate
     // render surface should have been removed. Render surfaces without children or visible
@@ -573,7 +1134,9 @@ TEST(CCLayerTreeHostCommonTest, verifyRenderSurfaceListForTransparentChild)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > dummyLayerList;
     int dummyMaxTextureSize = 512;
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
 
     // Since the layer is transparent, renderSurface1->renderSurface() should not have gotten added anywhere.
     // Also, the drawable content rect should not have been extended by the children.
@@ -601,14 +1164,14 @@ TEST(CCLayerTreeHostCommonTest, verifyForceRenderSurface)
     Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
     Vector<RefPtr<LayerChromium> > dummyLayerList;
     int dummyMaxTextureSize = 512;
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     EXPECT_TRUE(renderSurface1->renderSurface());
     EXPECT_EQ(renderSurfaceLayerList.size(), 1U);
 
     renderSurfaceLayerList.clear();
     renderSurface1->setForceRenderSurface(false);
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
     EXPECT_FALSE(renderSurface1->renderSurface());
     EXPECT_EQ(renderSurfaceLayerList.size(), 0U);
 }
@@ -666,7 +1229,11 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfaces)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    FloatRect dummyDamageRect;
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
+
 
     ASSERT_EQ(2U, renderSurfaceLayerList.size());
     EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id());
@@ -725,7 +1292,9 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsRenderSurfacesCrashRepro)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
 
     ASSERT_EQ(2U, renderSurfaceLayerList.size());
     EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id());
@@ -776,7 +1345,7 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsSurfaceWithoutVisibleContent)
     parent->createRenderSurface();
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     // Without an animation, we should cull child and grandChild from the renderSurfaceLayerList.
     ASSERT_EQ(1U, renderSurfaceLayerList.size());
@@ -795,7 +1364,7 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectCullsSurfaceWithoutVisibleContent)
     parent->createRenderSurface();
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     // With an animating transform, we should keep child and grandChild in the renderSurfaceLayerList.
     ASSERT_EQ(3U, renderSurfaceLayerList.size());
@@ -855,7 +1424,10 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectIsPropagatedCorrectlyToLayers)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
+
 
     EXPECT_INT_RECT_EQ(IntRect(IntPoint::zero(), IntSize(20, 20)), grandChild1->clipRect());
     EXPECT_INT_RECT_EQ(IntRect(IntPoint::zero(), IntSize(20, 20)), grandChild2->clipRect());
@@ -927,7 +1499,9 @@ TEST(CCLayerTreeHostCommonTest, verifyClipRectIsPropagatedCorrectlyToSurfaces)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
 
     ASSERT_TRUE(grandChild1->renderSurface());
     ASSERT_TRUE(grandChild2->renderSurface());
@@ -1408,7 +1982,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithoutPreserves3d)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     // Verify which renderSurfaces were created.
     EXPECT_FALSE(frontFacingChild->renderSurface());
@@ -1513,7 +2087,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3d)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     // Verify which renderSurfaces were created.
     EXPECT_FALSE(frontFacingChild->renderSurface());
@@ -1598,7 +2172,9 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithAnimatingTransforms)
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    CCLayerTreeHostCommon::calculateVisibleAndScissorRects(renderSurfaceLayerList, parent->renderSurface()->contentRect());
 
     EXPECT_FALSE(child->renderSurface());
     EXPECT_TRUE(animatingSurface->renderSurface());
@@ -1670,7 +2246,7 @@ TEST(CCLayerTreeHostCommonTest, verifyBackFaceCullingWithPreserves3dForFlattenin
     parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
     renderSurfaceLayerList.append(parent.get());
 
-    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+    CCLayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
 
     // Verify which renderSurfaces were created.
     EXPECT_TRUE(frontFacingSurface->renderSurface());
index c7df191..7faa43d 100644 (file)
 #include "cc/CCQuadCuller.h"
 #include "cc/CCScrollbarLayerImpl.h"
 #include "cc/CCSingleThreadProxy.h"
+#include "cc/CCSolidColorDrawQuad.h"
 #include "cc/CCTextureLayerImpl.h"
 #include "cc/CCTileDrawQuad.h"
 #include "cc/CCTiledLayerImpl.h"
 #include "cc/CCVideoLayerImpl.h"
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <public/WebVideoFrame.h>
 #include <public/WebVideoFrameProvider.h>
@@ -49,6 +51,12 @@ using namespace WebCore;
 using namespace WebKit;
 using namespace WebKitTests;
 
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::AnyNumber;
+using ::testing::AtLeast;
+using ::testing::_;
+
 namespace {
 
 class CCLayerTreeHostImplTest : public testing::Test, public CCLayerTreeHostImplClient {
@@ -70,6 +78,28 @@ public:
     virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { }
     virtual void postSetContentsMemoryAllocationLimitBytesToMainThreadOnImplThread(size_t) OVERRIDE { }
 
+    PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, PassRefPtr<CCGraphicsContext> graphicsContext, PassOwnPtr<CCLayerImpl> rootPtr)
+    {
+        CCSettings settings;
+
+        settings.partialSwapEnabled = partialSwap;
+
+        OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
+
+        myHostImpl->initializeLayerRenderer(graphicsContext, UnthrottledUploader);
+        myHostImpl->setViewportSize(IntSize(10, 10));
+
+        OwnPtr<CCLayerImpl> root = rootPtr;
+
+        root->setAnchorPoint(FloatPoint(0, 0));
+        root->setPosition(FloatPoint(0, 0));
+        root->setBounds(IntSize(10, 10));
+        root->setVisibleLayerRect(IntRect(0, 0, 10, 10));
+        root->setDrawsContent(true);
+        myHostImpl->setRootLayer(root.release());
+        return myHostImpl.release();
+    }
+
     static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
     {
         ASSERT_EQ(layer->scrollDelta(), IntSize());
@@ -1101,6 +1131,288 @@ TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
 }
 
+class FakeLayerWithQuads : public CCLayerImpl {
+public:
+    static PassOwnPtr<FakeLayerWithQuads> create(int id) { return adoptPtr(new FakeLayerWithQuads(id)); }
+
+    virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
+    {
+        const Color gray(100, 100, 100);
+        IntRect quadRect(0, 0, 5, 5);
+        OwnPtr<CCDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray);
+        quadList.append(myQuad.release());
+    }
+
+private:
+    FakeLayerWithQuads(int id)
+        : CCLayerImpl(id)
+    {
+    }
+};
+
+class MockContext : public FakeWebGraphicsContext3D {
+public:
+    MOCK_METHOD1(useProgram, void(WebGLId program));
+    MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
+    MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value));
+    MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
+    MOCK_METHOD1(getString, WebString(WGC3Denum name));
+    MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
+    MOCK_METHOD1(enable, void(WGC3Denum cap));
+    MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height));
+};
+
+class MockContextHarness {
+private:
+    MockContext* m_context;
+public:
+    MockContextHarness(MockContext* context)
+        : m_context(context)
+    {
+        // Catch "uninteresting" calls
+        EXPECT_CALL(*m_context, useProgram(_))
+            .Times(0);
+
+        EXPECT_CALL(*m_context, drawElements(_, _, _, _))
+            .Times(0);
+
+        // These are not asserted
+        EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
+            .WillRepeatedly(Return());
+
+        EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
+            .WillRepeatedly(Return());
+
+        // Any other strings are empty
+        EXPECT_CALL(*m_context, getString(_))
+            .WillRepeatedly(Return(WebString()));
+
+        // Support for partial swap, if needed
+        EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
+            .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
+
+        EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
+            .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
+
+        // Any un-sanctioned calls to enable() are OK
+        EXPECT_CALL(*m_context, enable(_))
+            .WillRepeatedly(Return());
+    }
+
+    void mustDrawSolidQuad()
+    {
+        EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0))
+            .WillOnce(Return())
+            .RetiresOnSaturation();
+
+        // 1 is hardcoded return value of fake createProgram()
+        EXPECT_CALL(*m_context, useProgram(1))
+            .WillOnce(Return())
+            .RetiresOnSaturation();
+
+    }
+
+    void mustSetScissor(int x, int y, int width, int height)
+    {
+        EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
+            .WillRepeatedly(Return());
+
+        EXPECT_CALL(*m_context, scissor(x, y, width, height))
+            .Times(AtLeast(1))
+            .WillRepeatedly(Return());
+    }
+
+};
+
+TEST_F(CCLayerTreeHostImplTest, noPartialSwap)
+{
+    MockContext* mockContext = new MockContext();
+    RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+    MockContextHarness harness(mockContext);
+
+    harness.mustDrawSolidQuad();
+    harness.mustSetScissor(0, 0, 10, 10);
+
+    // Run test case
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context, FakeLayerWithQuads::create(1));
+
+    CCLayerTreeHostImpl::FrameData frame;
+    EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+    myHostImpl->drawLayers(frame);
+    myHostImpl->didDrawAllLayers(frame);
+    Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+TEST_F(CCLayerTreeHostImplTest, partialSwap)
+{
+    MockContext* mockContext = new MockContext();
+    RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+    MockContextHarness harness(mockContext);
+
+    harness.mustDrawSolidQuad();
+    harness.mustSetScissor(0, 0, 10, 10);
+
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
+
+    CCLayerTreeHostImpl::FrameData frame;
+    EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+    myHostImpl->drawLayers(frame);
+    myHostImpl->didDrawAllLayers(frame);
+    Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+TEST_F(CCLayerTreeHostImplTest, partialSwapNoUpdate)
+{
+    MockContext* mockContext = new MockContext();
+    RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
+    MockContextHarness harness(mockContext);
+
+    harness.mustDrawSolidQuad();
+    harness.mustSetScissor(0, 8, 2, 2);
+    harness.mustDrawSolidQuad();
+    harness.mustSetScissor(0, 0, 10, 10);
+
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
+    
+    // Draw once to make sure layer is not new
+    CCLayerTreeHostImpl::FrameData frame;
+    EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+    myHostImpl->drawLayers(frame);
+    myHostImpl->didDrawAllLayers(frame);
+
+    // Generate update in layer
+    CCLayerImpl* root = myHostImpl->rootLayer();
+    root->setUpdateRect(FloatRect(0, 0, 2, 2));
+
+    // This draw should generate no new udpates
+    EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+    myHostImpl->drawLayers(frame);
+    myHostImpl->didDrawAllLayers(frame);
+
+    Mock::VerifyAndClearExpectations(&mockContext);
+}
+
+class PartialSwapContext: public FakeWebGraphicsContext3D {
+public:
+    WebString getString(WGC3Denum name)
+    {
+        if (name == GraphicsContext3D::EXTENSIONS)
+            return WebString("GL_CHROMIUM_post_sub_buffer");
+        return WebString();
+    }
+    
+    WebString getRequestableExtensionsCHROMIUM()
+    {
+        return WebString("GL_CHROMIUM_post_sub_buffer");
+    }
+};
+
+static PassOwnPtr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client)
+{
+    CCSettings settings;
+    settings.partialSwapEnabled = partialSwap;
+
+    RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client);
+    myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
+    myHostImpl->setViewportSize(IntSize(100, 100));
+
+    /*
+      Layers are created as follows:
+
+         +--------------------+
+         |                  1 |
+         |  +-----------+     |
+         |  |         2 |     |
+         |  | +-------------------+
+         |  | |   3               |
+         |  | +-------------------+
+         |  |           |     |
+         |  +-----------+     |
+         |                    |
+         |                    |
+         +--------------------+
+
+         Layers 1, 2 have render surfaces
+     */
+    OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
+    OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
+    OwnPtr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
+
+    IntRect rootRect(0, 0, 100, 100);
+    IntRect childRect(10, 10, 50, 50);
+    IntRect grandChildRect(5, 5, 150, 150);
+
+    root->createRenderSurface();
+    root->setAnchorPoint(FloatPoint(0, 0));
+    root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
+    root->setBounds(IntSize(rootRect.width(), rootRect.height()));
+    root->setVisibleLayerRect(rootRect);
+    root->setDrawsContent(false);
+    root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
+
+    child->setAnchorPoint(FloatPoint(0, 0));
+    child->setPosition(FloatPoint(childRect.x(), childRect.y()));
+    child->setOpacity(0.5f);
+    child->setBounds(IntSize(childRect.width(), childRect.height()));
+    child->setVisibleLayerRect(childRect);
+    child->setDrawsContent(false);
+
+    grandChild->setAnchorPoint(FloatPoint(0, 0));
+    grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
+    grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
+    grandChild->setVisibleLayerRect(grandChildRect);
+    grandChild->setDrawsContent(true);
+
+    child->addChild(grandChild.release());
+    root->addChild(child.release());
+
+    myHostImpl->setRootLayer(root.release());
+    return myHostImpl.release();
+}
+
+TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
+{
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this);
+
+    {
+        CCLayerTreeHostImpl::FrameData frame;
+        EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+        // Just for consistency, the most interesting stuff already happened
+        myHostImpl->drawLayers(frame);
+        myHostImpl->didDrawAllLayers(frame);
+
+        // Verify all quads have been computed
+        ASSERT_EQ(2U, frame.renderPasses.size());
+        ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
+        ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
+        EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
+        EXPECT_EQ(CCDrawQuad::RenderSurface, frame.renderPasses[1]->quadList()[0]->material());
+    }
+}
+
+TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
+{
+    OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this);
+
+    {
+        CCLayerTreeHostImpl::FrameData frame;
+        EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
+
+        // Just for consistency, the most interesting stuff already happened
+        myHostImpl->drawLayers(frame);
+        myHostImpl->didDrawAllLayers(frame);
+
+        // Verify all quads have been computed
+        ASSERT_EQ(2U, frame.renderPasses.size());
+        ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
+        ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
+        EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
+        EXPECT_EQ(CCDrawQuad::RenderSurface, frame.renderPasses[1]->quadList()[0]->material());
+    }
+}
+
 // Make sure that context lost notifications are propagated through the tree.
 class ContextLostNotificationCheckLayer : public CCLayerImpl {
 public:
index 80317a0..a64965f 100644 (file)
@@ -261,7 +261,10 @@ protected:
         root->setClipRect(IntRect(IntPoint::zero(), root->bounds()));
         m_renderSurfaceLayerListImpl.append(m_root.get());
 
-        CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListImpl, dummyLayerList, 0, dummyMaxTextureSize);
+        CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListImpl, dummyLayerList, 0, dummyMaxTextureSize);
+
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(m_renderSurfaceLayerListImpl, root->renderSurface()->contentRect());
+
         m_layerIterator = m_layerIteratorBegin = Types::LayerIterator::begin(&m_renderSurfaceLayerListImpl);
     }
 
@@ -277,7 +280,10 @@ protected:
         root->setClipRect(IntRect(IntPoint::zero(), root->bounds()));
         m_renderSurfaceLayerListChromium.append(m_root);
 
-        CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListChromium, dummyLayerList, dummyMaxTextureSize);
+        CCLayerTreeHostCommon::calculateDrawTransforms(root, root, identityMatrix, identityMatrix, m_renderSurfaceLayerListChromium, dummyLayerList, dummyMaxTextureSize);
+
+        CCLayerTreeHostCommon::calculateVisibleAndScissorRects(m_renderSurfaceLayerListChromium, root->renderSurface()->contentRect());
+
         m_layerIterator = m_layerIteratorBegin = Types::LayerIterator::begin(&m_renderSurfaceLayerListChromium);
     }
 
index 5cbe7fc..c8b0eda 100644 (file)
@@ -111,6 +111,7 @@ TEST(CCRenderSurfaceTest, sanityCheckSurfaceCreatesCorrectSharedQuadState)
     renderSurface->setOriginTransform(origin);
     renderSurface->setContentRect(contentRect);
     renderSurface->setClipRect(clipRect);
+    renderSurface->setScissorRect(clipRect);
     renderSurface->setDrawOpacity(1);
 
     OwnPtr<CCSharedQuadState> sharedQuadState = renderSurface->createSharedQuadState();
@@ -119,7 +120,7 @@ TEST(CCRenderSurfaceTest, sanityCheckSurfaceCreatesCorrectSharedQuadState)
     EXPECT_EQ(30, sharedQuadState->layerTransform().m41());
     EXPECT_EQ(40, sharedQuadState->layerTransform().m42());
     EXPECT_EQ(contentRect, sharedQuadState->layerRect());
-    EXPECT_EQ(clipRect, sharedQuadState->clipRect());
+    EXPECT_EQ(clipRect, sharedQuadState->scissorRect());
     EXPECT_EQ(1, sharedQuadState->opacity());
     EXPECT_FALSE(sharedQuadState->isOpaque());
 }