[Chromium] Occlusion tracking with CSS filters
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Feb 2012 02:27:57 +0000 (02:27 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Feb 2012 02:27:57 +0000 (02:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=77498

Patch by Dana Jansens <danakj@chromium.org> on 2012-02-16
Reviewed by James Robinson.

Source/WebCore:

The new CSS filter support within the compositor changes how
occlusion tracking needs to function. A filter can change the
alpha value of pixels, making an otherwise opaque pixel no
longer so. Secondly, a filter may move color values around
on a surface, which can cause otherwise occluded areas to
become visible and require painting.

New unit tests: CCLayerTreeHostTest.cpp

Tests: compositing/culling/filter-occlusion-alpha-large.html
       compositing/culling/filter-occlusion-alpha.html
       compositing/culling/filter-occlusion-blur-large.html
       compositing/culling/filter-occlusion-blur.html

* platform/graphics/chromium/RenderSurfaceChromium.cpp:
(WebCore::RenderSurfaceChromium::RenderSurfaceChromium):
* platform/graphics/chromium/RenderSurfaceChromium.h:
(WebCore::RenderSurfaceChromium::setFilters):
(WebCore::RenderSurfaceChromium::filters):
(WebCore::RenderSurfaceChromium::setNearestAncestorThatMovesPixels):
(WebCore::RenderSurfaceChromium::nearestAncestorThatMovesPixels):
(RenderSurfaceChromium):
* platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
(WebCore::enterTargetRenderSurface):
(WebCore::CCLayerTreeHost::paintLayerContents):
* platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
(WebCore::subtreeShouldRenderToSeparateSurface):
(WebCore::calculateDrawTransformsAndVisibilityInternal):
(WebCore::CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility):
* platform/graphics/chromium/cc/CCRenderSurface.cpp:
(WebCore::CCRenderSurface::CCRenderSurface):
* platform/graphics/chromium/cc/CCRenderSurface.h:
(WebCore::CCRenderSurface::setNearestAncestorThatMovesPixels):
(WebCore::CCRenderSurface::nearestAncestorThatMovesPixels):
(CCRenderSurface):
* platform/graphics/filters/FilterOperation.h:
(FilterOperation):
(WebCore::FilterOperation::affectsOpacity):
(WebCore::FilterOperation::movesPixels):
(WebCore::ReferenceFilterOperation::affectsOpacity):
(WebCore::ReferenceFilterOperation::movesPixels):
(ReferenceFilterOperation):
(WebCore::BasicComponentTransferFilterOperation::affectsOpacity):
(BasicComponentTransferFilterOperation):
(WebCore::BlurFilterOperation::affectsOpacity):
(WebCore::BlurFilterOperation::movesPixels):
(BlurFilterOperation):
(WebCore::DropShadowFilterOperation::affectsOpacity):
(DropShadowFilterOperation):
* platform/graphics/filters/FilterOperations.cpp:
(WebCore::FilterOperations::hasFilterThatAffectsOpacity):
(WebCore):
(WebCore::FilterOperations::hasFilterThatMovesPixels):
* platform/graphics/filters/FilterOperations.h:
(WebCore::FilterOperations::isEmpty):
(FilterOperations):

Source/WebKit/chromium:

* tests/CCLayerTreeHostTest.cpp:
(CCLayerTreeHostTestLayerOcclusionWithFilters):
(WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::CCLayerTreeHostTestLayerOcclusionWithFilters):
(WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::beginTest):
(WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::afterTest):
(WTF):

LayoutTests:

* compositing/culling/filter-occlusion-alpha-expected.png: Added.
* compositing/culling/filter-occlusion-alpha-expected.txt: Added.
* compositing/culling/filter-occlusion-alpha-large-expected.png: Added.
* compositing/culling/filter-occlusion-alpha-large-expected.txt: Added.
* compositing/culling/filter-occlusion-alpha-large.html: Added.
* compositing/culling/filter-occlusion-alpha.html: Added.
* compositing/culling/filter-occlusion-blur-expected.txt: Added.
* compositing/culling/filter-occlusion-blur-large-expected.txt: Added.
* compositing/culling/filter-occlusion-blur-large.html: Added.
* compositing/culling/filter-occlusion-blur.html: Added.
* platform/chromium/compositing/culling/filter-occlusion-blur-expected.png: Added.
* platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png: Added.
* platform/chromium/test_expectations.txt:

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

26 files changed:
LayoutTests/ChangeLog
LayoutTests/compositing/culling/filter-occlusion-alpha-expected.png [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-alpha-expected.txt [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.png [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.txt [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-alpha-large.html [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-alpha.html [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-blur-expected.txt [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-blur-large-expected.txt [new file with mode: 0644]
LayoutTests/compositing/culling/filter-occlusion-blur-large.html [new file with mode: 0755]
LayoutTests/compositing/culling/filter-occlusion-blur.html [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/test_expectations.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHost.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.h
Source/WebCore/platform/graphics/filters/FilterOperation.h
Source/WebCore/platform/graphics/filters/FilterOperations.cpp
Source/WebCore/platform/graphics/filters/FilterOperations.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp

index 932aa5a..49aa982 100644 (file)
@@ -1,3 +1,24 @@
+2012-02-16  Dana Jansens  <danakj@chromium.org>
+
+        [Chromium] Occlusion tracking with CSS filters
+        https://bugs.webkit.org/show_bug.cgi?id=77498
+
+        Reviewed by James Robinson.
+
+        * compositing/culling/filter-occlusion-alpha-expected.png: Added.
+        * compositing/culling/filter-occlusion-alpha-expected.txt: Added.
+        * compositing/culling/filter-occlusion-alpha-large-expected.png: Added.
+        * compositing/culling/filter-occlusion-alpha-large-expected.txt: Added.
+        * compositing/culling/filter-occlusion-alpha-large.html: Added.
+        * compositing/culling/filter-occlusion-alpha.html: Added.
+        * compositing/culling/filter-occlusion-blur-expected.txt: Added.
+        * compositing/culling/filter-occlusion-blur-large-expected.txt: Added.
+        * compositing/culling/filter-occlusion-blur-large.html: Added.
+        * compositing/culling/filter-occlusion-blur.html: Added.
+        * platform/chromium/compositing/culling/filter-occlusion-blur-expected.png: Added.
+        * platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png: Added.
+        * platform/chromium/test_expectations.txt:
+
 2012-02-16  Noel Gordon  <noel.gordon@gmail.com>
 
         [chromium] Rebaseline JPEG image results after r107389
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha-expected.png b/LayoutTests/compositing/culling/filter-occlusion-alpha-expected.png
new file mode 100644 (file)
index 0000000..ce2c952
Binary files /dev/null and b/LayoutTests/compositing/culling/filter-occlusion-alpha-expected.png differ
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha-expected.txt b/LayoutTests/compositing/culling/filter-occlusion-alpha-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.png b/LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.png
new file mode 100644 (file)
index 0000000..7eb2f1d
Binary files /dev/null and b/LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.png differ
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.txt b/LayoutTests/compositing/culling/filter-occlusion-alpha-large-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha-large.html b/LayoutTests/compositing/culling/filter-occlusion-alpha-large.html
new file mode 100644 (file)
index 0000000..9202577
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html><head>
+<title>CSS filter blur occlusion test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .green-parent {
+    width: 800px;
+    height:  800px;
+  }
+  .centered {
+    width: 400px;
+    height: 400px;
+    position: absolute;
+    left: 200px;
+    top: 200px;
+  }
+  .alpha {
+    -webkit-filter: opacity(0%);
+  }
+</style>
+<script type="text/javascript">
+  if (window.layoutTestController) {
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+<body>
+<!--
+   This test guards against culling behind filters that change opacity. The red box is given
+   an opacity of 0% with a CSS filter, so only the green box behind it should be visible.
+   This version of the test causes part of the boxes to be out of view, testing the interaction
+   between their visible region with culling.
+  -->
+<div class="green-parent composted" style="position:absolute; left:0; top:0">
+  <div class="centered composited" style="background-color: green;">
+  </div>
+</div>
+<div class="composited centered alpha" style="background-color: red;">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/culling/filter-occlusion-alpha.html b/LayoutTests/compositing/culling/filter-occlusion-alpha.html
new file mode 100644 (file)
index 0000000..00dc4b7
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html><head>
+<title>CSS filter blur occlusion test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .green-parent {
+    width: 600px;
+    height:  600px;
+  }
+  .centered {
+    width: 200px;
+    height: 200px;
+    position: absolute;
+    left: 100px;
+    top: 100px;
+  }
+  .alpha {
+    -webkit-filter: opacity(0%);
+  }
+</style>
+<script type="text/javascript">
+  if (window.layoutTestController) {
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+<body>
+<!--
+   This test guards against culling behind filters that change opacity. The red box is given
+   an opacity of 0% with a CSS filter, so only the green box behind it should be visible.
+  -->
+<div class="green-parent composted" style="position:absolute; left:0; top:0">
+  <div class="centered composited" style="background-color: green;">
+  </div>
+</div>
+<div class="composited centered alpha" style="background-color: red;">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/culling/filter-occlusion-blur-expected.txt b/LayoutTests/compositing/culling/filter-occlusion-blur-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/compositing/culling/filter-occlusion-blur-large-expected.txt b/LayoutTests/compositing/culling/filter-occlusion-blur-large-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/compositing/culling/filter-occlusion-blur-large.html b/LayoutTests/compositing/culling/filter-occlusion-blur-large.html
new file mode 100755 (executable)
index 0000000..fb4ed74
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html><head>
+<title>CSS filter blur occlusion test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .yellow-parent {
+    width: 800px;
+    height:  800px;
+    -webkit-filter: blur(10px);
+  }
+  .centered {
+    width: 400px;
+    height: 400px;
+    position: absolute;
+    left: 200px;
+    top: 200px;
+  }
+</style>
+<script type="text/javascript">
+  if (window.layoutTestController) {
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+<body>
+<!--
+   This test guards against over-culling of the "hidden" yellow box. Since the yellow box is blurred,
+   it becomes visible around the outside of the green box. This test causes part of the green and
+   yellow boxes to be out of view, testing the interaction of their visible region with the culling.
+  -->
+<div class="yellow-parent composted" style="position:absolute; left:0; top:0">
+  <div class="centered composited" style="background-color: yellow;">
+  </div>
+</div>
+<div class="composited centered" style="background-color: green;">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/culling/filter-occlusion-blur.html b/LayoutTests/compositing/culling/filter-occlusion-blur.html
new file mode 100644 (file)
index 0000000..960c790
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html><head>
+<title>CSS filter blur occlusion test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .yellow-parent {
+    width: 600px;
+    height:  600px;
+    -webkit-filter: blur(10px);
+  }
+  .centered {
+    width: 200px;
+    height: 200px;
+    position: absolute;
+    left: 100px;
+    top: 100px;
+  }
+</style>
+<script type="text/javascript">
+  if (window.layoutTestController) {
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+<body>
+<!--
+   This test guards against over-culling of the "hidden" yellow box. Since the yellow box is blurred,
+   it becomes visible around the outside of the green box.
+  -->
+<div class="yellow-parent composted" style="position:absolute; left:0; top:0">
+  <div class="centered composited" style="background-color: yellow;">
+  </div>
+</div>
+<div class="composited centered" style="background-color: green;">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-expected.png b/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-expected.png
new file mode 100644 (file)
index 0000000..0e6c779
Binary files /dev/null and b/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-expected.png differ
diff --git a/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png b/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png
new file mode 100644 (file)
index 0000000..43036f9
Binary files /dev/null and b/LayoutTests/platform/chromium/compositing/culling/filter-occlusion-blur-large-expected.png differ
index 50babef..518441a 100644 (file)
@@ -4196,6 +4196,12 @@ BUGWK78219 : svg/dynamic-updates/SVGTextElement-svgdom-y-prop.html = IMAGE
 BUGWK78219 : svg/dynamic-updates/SVGUseElement-dom-requiredFeatures.html = IMAGE
 BUGWK78219 : svg/dynamic-updates/SVGUseElement-svgdom-requiredFeatures.html = IMAGE
 
+// May need platform specific baselines
+BUGWK77498 : compositing/culling/filter-occlusion-alpha.html = PASS IMAGE
+BUGWK77498 : compositing/culling/filter-occlusion-alpha-large.html = PASS IMAGE
+BUGWK77498 : compositing/culling/filter-occlusion-blur.html = PASS IMAGE
+BUGWK77498 : compositing/culling/filter-occlusion-blur-large.html = PASS IMAGE
+
 // Needs new baselines.
 BUGWK65072 : svg/text/exs-display-none.svg = IMAGE IMAGE+TEXT
 BUGWK65072 : svg/text/ems-display-none.svg = IMAGE IMAGE+TEXT
index c14ac71..a8e9121 100644 (file)
@@ -1,3 +1,67 @@
+2012-02-16  Dana Jansens  <danakj@chromium.org>
+
+        [Chromium] Occlusion tracking with CSS filters
+        https://bugs.webkit.org/show_bug.cgi?id=77498
+
+        Reviewed by James Robinson.
+
+        The new CSS filter support within the compositor changes how
+        occlusion tracking needs to function. A filter can change the
+        alpha value of pixels, making an otherwise opaque pixel no
+        longer so. Secondly, a filter may move color values around
+        on a surface, which can cause otherwise occluded areas to
+        become visible and require painting.
+
+        New unit tests: CCLayerTreeHostTest.cpp
+
+        Tests: compositing/culling/filter-occlusion-alpha-large.html
+               compositing/culling/filter-occlusion-alpha.html
+               compositing/culling/filter-occlusion-blur-large.html
+               compositing/culling/filter-occlusion-blur.html
+
+        * platform/graphics/chromium/RenderSurfaceChromium.cpp:
+        (WebCore::RenderSurfaceChromium::RenderSurfaceChromium):
+        * platform/graphics/chromium/RenderSurfaceChromium.h:
+        (WebCore::RenderSurfaceChromium::setFilters):
+        (WebCore::RenderSurfaceChromium::filters):
+        (WebCore::RenderSurfaceChromium::setNearestAncestorThatMovesPixels):
+        (WebCore::RenderSurfaceChromium::nearestAncestorThatMovesPixels):
+        (RenderSurfaceChromium):
+        * platform/graphics/chromium/cc/CCLayerTreeHost.cpp:
+        (WebCore::enterTargetRenderSurface):
+        (WebCore::CCLayerTreeHost::paintLayerContents):
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
+        (WebCore::subtreeShouldRenderToSeparateSurface):
+        (WebCore::calculateDrawTransformsAndVisibilityInternal):
+        (WebCore::CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility):
+        * platform/graphics/chromium/cc/CCRenderSurface.cpp:
+        (WebCore::CCRenderSurface::CCRenderSurface):
+        * platform/graphics/chromium/cc/CCRenderSurface.h:
+        (WebCore::CCRenderSurface::setNearestAncestorThatMovesPixels):
+        (WebCore::CCRenderSurface::nearestAncestorThatMovesPixels):
+        (CCRenderSurface):
+        * platform/graphics/filters/FilterOperation.h:
+        (FilterOperation):
+        (WebCore::FilterOperation::affectsOpacity):
+        (WebCore::FilterOperation::movesPixels):
+        (WebCore::ReferenceFilterOperation::affectsOpacity):
+        (WebCore::ReferenceFilterOperation::movesPixels):
+        (ReferenceFilterOperation):
+        (WebCore::BasicComponentTransferFilterOperation::affectsOpacity):
+        (BasicComponentTransferFilterOperation):
+        (WebCore::BlurFilterOperation::affectsOpacity):
+        (WebCore::BlurFilterOperation::movesPixels):
+        (BlurFilterOperation):
+        (WebCore::DropShadowFilterOperation::affectsOpacity):
+        (DropShadowFilterOperation):
+        * platform/graphics/filters/FilterOperations.cpp:
+        (WebCore::FilterOperations::hasFilterThatAffectsOpacity):
+        (WebCore):
+        (WebCore::FilterOperations::hasFilterThatMovesPixels):
+        * platform/graphics/filters/FilterOperations.h:
+        (WebCore::FilterOperations::isEmpty):
+        (FilterOperations):
+
 2012-02-16  Leo Yang  <leo.yang@torchmobile.com.cn>
 
         [BlackBerry] Adapt to the removal of WebStringIml.h
index 73f3ab2..69ce952 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "RenderSurfaceChromium.h"
 
+#include "FilterOperations.h"
 #include "GraphicsContext3D.h"
 #include "LayerChromium.h"
 #include "LayerRendererChromium.h"
@@ -41,6 +42,7 @@ RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer)
     , m_maskLayer(0)
     , m_skipsDraw(false)
     , m_drawOpacity(1)
+    , m_nearestAncestorThatMovesPixels(0)
 {
 }
 
index 65cb64b..9045425 100644 (file)
@@ -77,10 +77,8 @@ public:
     const IntRect& clipRect() const { return m_clipRect; }
     void setClipRect(const IntRect& clipRect) { m_clipRect = clipRect; }
 
-    // We don't care about filters here, but we need to satisfy 
-    // calculateDrawTransformsAndVisibilityInternal when templated on this
-    // class.
-    void setFilters(const FilterOperations&) { }
+    void setFilters(const FilterOperations& filters) { m_filters = filters; }
+    const FilterOperations& filters() const { return m_filters; }
 
     bool skipsDraw() const { return m_skipsDraw; }
     void setSkipsDraw(bool skipsDraw) { m_skipsDraw = skipsDraw; }
@@ -90,6 +88,9 @@ public:
 
     void setMaskLayer(LayerChromium* maskLayer) { m_maskLayer = maskLayer; }
 
+    void setNearestAncestorThatMovesPixels(RenderSurfaceChromium* surface) { m_nearestAncestorThatMovesPixels = surface; }
+    const RenderSurfaceChromium* nearestAncestorThatMovesPixels() const { return m_nearestAncestorThatMovesPixels; }
+
 private:
     LayerChromium* m_owningLayer;
     LayerChromium* m_maskLayer;
@@ -101,9 +102,14 @@ private:
     TransformationMatrix m_drawTransform;
     TransformationMatrix m_replicaDrawTransform;
     TransformationMatrix m_originTransform;
+    FilterOperations m_filters;
     IntRect m_clipRect;
     Vector<RefPtr<LayerChromium> > m_layerList;
 
+    // The nearest ancestor target surface that will contain the contents of this surface, and that is going
+    // to move pixels within the surface (such as with a blur). This can point to itself.
+    RenderSurfaceChromium* m_nearestAncestorThatMovesPixels;
+
     // For CCLayerIteratorActions
     int m_targetRenderSurfaceLayerIndexHistory;
     int m_currentLayerIndexHistory;
index f8144e1..9ce6f20 100644 (file)
@@ -505,10 +505,18 @@ static void enterTargetRenderSurface(Vector<RenderSurfaceRegion>& stack, RenderS
         stack.append(RenderSurfaceRegion());
         stack.last().surface = newTarget;
     } else if (stack.last().surface != newTarget) {
+        // If we are entering a subtree that is going to move pixels around, then the occlusion we've computed
+        // so far won't apply to the pixels we're drawing here in the same way. We discard the occlusion thus
+        // far to be safe, and ensure we don't cull any pixels that are moved such that they become visible.
+        const RenderSurfaceChromium* oldAncestorThatMovesPixels = stack.last().surface->nearestAncestorThatMovesPixels();
+        const RenderSurfaceChromium* newAncestorThatMovesPixels = newTarget->nearestAncestorThatMovesPixels();
+        bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAncestorThatMovesPixels != oldAncestorThatMovesPixels;
+
         stack.append(RenderSurfaceRegion());
         stack.last().surface = newTarget;
         int lastIndex = stack.size() - 1;
-        stack[lastIndex].occludedInScreen = stack[lastIndex - 1].occludedInScreen;
+        if (!enteringSubtreeThatMovesPixels)
+            stack[lastIndex].occludedInScreen = stack[lastIndex - 1].occludedInScreen;
     }
 }
 
@@ -551,7 +559,7 @@ void CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList
             paintMaskAndReplicaForRenderSurface(*it, paintType);
             // FIXME: add the replica layer to the current occlusion
 
-            if (it->maskLayer() || it->renderSurface()->drawOpacity() < 1)
+            if (it->maskLayer() || it->renderSurface()->drawOpacity() < 1 || it->renderSurface()->filters().hasFilterThatAffectsOpacity())
                 targetSurfaceStack.last().occludedInScreen = Region();
         } else if (it.representsItself()) {
             ASSERT(!it->bounds().isEmpty());
index 4dbca92..9b250d0 100644 (file)
@@ -128,7 +128,7 @@ static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlig
         return true;
 
     // If the layer uses a CSS filter.
-    if (layer->filters().size() > 0)
+    if (!layer->filters().isEmpty())
         return true;
 
     // If the layer flattens its subtree (i.e. the layer doesn't preserve-3d), but it is
@@ -150,7 +150,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 RenderSurfaceType, typename LayerSorter>
-static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, LayerType* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerType> >& renderSurfaceLayerList, Vector<RefPtr<LayerType> >& layerList, LayerSorter* layerSorter, int maxTextureSize)
+static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, LayerType* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, RenderSurfaceType* nearestAncestorThatMovesPixels, Vector<RefPtr<LayerType> >& renderSurfaceLayerList, Vector<RefPtr<LayerType> >& layerList, LayerSorter* layerSorter, int maxTextureSize)
 {
     typedef Vector<RefPtr<LayerType> > LayerList;
 
@@ -312,6 +312,9 @@ static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, Layer
             layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface);
 
         renderSurface->setFilters(layer->filters());
+        if (renderSurface->filters().hasFilterThatMovesPixels())
+            nearestAncestorThatMovesPixels = renderSurface;
+        renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
 
         renderSurfaceLayerList.append(layer);
     } else {
@@ -393,7 +396,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, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
+        bool drawsContent = calculateDrawTransformsAndVisibilityInternal<LayerType, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, nearestAncestorThatMovesPixels, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
 
         if (drawsContent) {
             if (child->renderSurface()) {
@@ -515,13 +518,13 @@ static void walkLayersAndCalculateVisibleLayerRects(const Vector<RefPtr<LayerTyp
 
 void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(LayerChromium* layer, LayerChromium* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize)
 {
-    WebCore::calculateDrawTransformsAndVisibilityInternal<LayerChromium, RenderSurfaceChromium, void*>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, renderSurfaceLayerList, layerList, 0, maxTextureSize);
+    WebCore::calculateDrawTransformsAndVisibilityInternal<LayerChromium, RenderSurfaceChromium, void*>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, 0, maxTextureSize);
     walkLayersAndCalculateVisibleLayerRects<LayerChromium, RenderSurfaceChromium>(renderSurfaceLayerList);
 }
 
 void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(CCLayerImpl* layer, CCLayerImpl* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<CCLayerImpl> >& renderSurfaceLayerList, Vector<RefPtr<CCLayerImpl> >& layerList, CCLayerSorter* layerSorter, int maxTextureSize)
 {
-    calculateDrawTransformsAndVisibilityInternal<CCLayerImpl, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
+    calculateDrawTransformsAndVisibilityInternal<CCLayerImpl, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
     walkLayersAndCalculateVisibleLayerRects<CCLayerImpl, CCRenderSurface>(renderSurfaceLayerList);
 }
 
index 898e8fd..1699998 100644 (file)
@@ -51,6 +51,7 @@ CCRenderSurface::CCRenderSurface(CCLayerImpl* owningLayer)
     , m_skipsDraw(false)
     , m_surfacePropertyChanged(false)
     , m_drawOpacity(1)
+    , m_nearestAncestorThatMovesPixels(0)
 {
     m_damageTracker = CCDamageTracker::create();
 }
index 437a91c..1bcec92 100644 (file)
@@ -76,6 +76,9 @@ public:
     const FilterOperations& filters() const { return m_filters; }
     SkBitmap applyFilters(LayerRendererChromium*);
 
+    void setNearestAncestorThatMovesPixels(CCRenderSurface* surface) { m_nearestAncestorThatMovesPixels = surface; }
+    const CCRenderSurface* nearestAncestorThatMovesPixels() const { return m_nearestAncestorThatMovesPixels; }
+
     void setReplicaDrawTransform(const TransformationMatrix& replicaDrawTransform) { m_replicaDrawTransform = replicaDrawTransform; }
     const TransformationMatrix& replicaDrawTransform() const { return m_replicaDrawTransform; }
 
@@ -132,6 +135,10 @@ private:
     IntRect m_clipRect;
     Vector<RefPtr<CCLayerImpl> > m_layerList;
 
+    // The nearest ancestor target surface that will contain the contents of this surface, and that is going
+    // to move pixels within the surface (such as with a blur). This can point to itself.
+    CCRenderSurface* m_nearestAncestorThatMovesPixels;
+
     OwnPtr<CCDamageTracker> m_damageTracker;
 
     // Stored in the "surface space" where this damage can be used for scissoring.
index 17b00b0..9d7ef65 100644 (file)
@@ -77,6 +77,11 @@ public:
     
     virtual bool isDefault() const { return false; }
 
+    // True if the alpha channel of any pixel can change under this operation.
+    virtual bool affectsOpacity() const { return false; }
+    // True if the the value of one pixel can affect the value of another pixel under this operation, such as blur.
+    virtual bool movesPixels() const { return false; }
+
 protected:
     FilterOperation(OperationType type)
         : m_type(type)
@@ -135,6 +140,9 @@ public:
         return adoptRef(new ReferenceFilterOperation(reference, type));
     }
 
+    virtual bool affectsOpacity() const { return true; }
+    virtual bool movesPixels() const { return true; }
+
     const AtomicString& reference() const { return m_reference; }
 
 private:
@@ -199,6 +207,8 @@ public:
 
     double amount() const { return m_amount; }
 
+    virtual bool affectsOpacity() const { return m_type == OPACITY; }
+
     virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false);
 
 private:
@@ -265,6 +275,9 @@ public:
 
     Length stdDeviation() const { return m_stdDeviation; }
 
+    virtual bool affectsOpacity() const { return true; }
+    virtual bool movesPixels() const { return true; }
+
     virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false);
 
 private:
@@ -297,6 +310,8 @@ public:
     int stdDeviation() const { return m_stdDeviation; }
     Color color() const { return m_color; }
 
+    virtual bool affectsOpacity() const { return true; }
+
     virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false);
 
 private:
index dd92ac1..35282cb 100644 (file)
@@ -136,6 +136,22 @@ void FilterOperations::getOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit
     }
 }
 
+bool FilterOperations::hasFilterThatAffectsOpacity() const
+{
+    for (size_t i = 0; i < m_operations.size(); ++i)
+        if (m_operations[i]->affectsOpacity())
+            return true;
+    return false;
+}
+
+bool FilterOperations::hasFilterThatMovesPixels() const
+{
+    for (size_t i = 0; i < m_operations.size(); ++i)
+        if (m_operations[i]->movesPixels())
+            return true;
+    return false;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(CSS_FILTERS)
index 64cee88..0b492eb 100644 (file)
@@ -57,6 +57,7 @@ public:
     Vector<RefPtr<FilterOperation> >& operations() { return m_operations; }
     const Vector<RefPtr<FilterOperation> >& operations() const { return m_operations; }
 
+    bool isEmpty() const { return !m_operations.size(); }
     size_t size() const { return m_operations.size(); }
     const FilterOperation* at(size_t index) const { return index < m_operations.size() ? m_operations.at(index).get() : 0; }
 
@@ -65,6 +66,9 @@ public:
     bool hasOutsets() const;
     void getOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const;
 
+    bool hasFilterThatAffectsOpacity() const;
+    bool hasFilterThatMovesPixels() const;
+
 private:
     Vector<RefPtr<FilterOperation> > m_operations;
 };
index 31c38ee..5207294 100644 (file)
@@ -1,3 +1,17 @@
+2012-02-16  Dana Jansens  <danakj@chromium.org>
+
+        [Chromium] Occlusion tracking with CSS filters
+        https://bugs.webkit.org/show_bug.cgi?id=77498
+
+        Reviewed by James Robinson.
+
+        * tests/CCLayerTreeHostTest.cpp:
+        (CCLayerTreeHostTestLayerOcclusionWithFilters):
+        (WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::CCLayerTreeHostTestLayerOcclusionWithFilters):
+        (WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::beginTest):
+        (WTF::CCLayerTreeHostTestLayerOcclusionWithFilters::afterTest):
+        (WTF):
+
 2012-02-16  Joshua Bell  <jsbell@chromium.org>
 
         IndexedDB: Chromium WebKit API support for IDBObjectStore.delete(IDBKeyRange)
index 04fcc75..e12ea48 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "CompositorFakeWebGraphicsContext3D.h"
 #include "ContentLayerChromium.h"
+#include "FilterOperations.h"
 #include "GraphicsContext3DPrivate.h"
 #include "LayerChromium.h"
 #include "Region.h"
@@ -1665,6 +1666,94 @@ public:
 
 SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestLayerOcclusion)
 
+class CCLayerTreeHostTestLayerOcclusionWithFilters : public CCLayerTreeHostTest {
+public:
+    CCLayerTreeHostTestLayerOcclusionWithFilters() { }
+
+    virtual void beginTest()
+    {
+        RefPtr<TestLayerChromium> rootLayer = TestLayerChromium::create();
+        RefPtr<TestLayerChromium> child = TestLayerChromium::create();
+        RefPtr<TestLayerChromium> child2 = TestLayerChromium::create();
+        RefPtr<TestLayerChromium> grandChild = TestLayerChromium::create();
+        RefPtr<TestLayerChromium> mask = TestLayerChromium::create();
+
+        TransformationMatrix identityMatrix;
+        TransformationMatrix childTransform;
+        childTransform.translate(250, 250);
+        childTransform.rotate(90);
+        childTransform.translate(-250, -250);
+
+        child->setMasksToBounds(true);
+
+        // If the child layer has a filter that changes alpha values, and is below child2, then child2 should contribute to occlusion on everything,
+        // and child shouldn't contribute to the rootLayer
+        setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true);
+        setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true);
+        setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true);
+        setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true);
+
+        {
+            FilterOperations filters;
+            filters.operations().append(BasicComponentTransferFilterOperation::create(0.5, FilterOperation::OPACITY));
+            child->setFilters(filters);
+        }
+
+        m_layerTreeHost->setRootLayer(rootLayer);
+        m_layerTreeHost->setViewportSize(rootLayer->bounds());
+        m_layerTreeHost->updateLayers();
+        m_layerTreeHost->commitComplete();
+
+        EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds());
+        EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), grandChild->occludedScreenSpace().bounds());
+        EXPECT_EQ(1u, grandChild->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(10, 40, 90, 60), child->occludedScreenSpace().bounds());
+        EXPECT_EQ(2u, child->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds());
+        EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size());
+
+        // If the child layer has a filter that moves pixels/changes alpha, and is below child2, then child should not inherit occlusion from outside its subtree,
+        // and should not contribute to the rootLayer
+        setLayerPropertiesForTesting(rootLayer.get(), 0, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true);
+        setLayerPropertiesForTesting(child.get(), rootLayer.get(), childTransform, FloatPoint(0, 0), FloatPoint(30, 30), IntSize(500, 500), true);
+        setLayerPropertiesForTesting(grandChild.get(), child.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 10), IntSize(500, 500), true);
+        setLayerPropertiesForTesting(child2.get(), rootLayer.get(), identityMatrix, FloatPoint(0, 0), FloatPoint(10, 70), IntSize(500, 500), true);
+
+        {
+            FilterOperations filters;
+            filters.operations().append(BlurFilterOperation::create(Length(10, WebCore::Percent), FilterOperation::BLUR));
+            child->setFilters(filters);
+        }
+
+        m_layerTreeHost->setRootLayer(rootLayer);
+        m_layerTreeHost->setViewportSize(rootLayer->bounds());
+        m_layerTreeHost->updateLayers();
+        m_layerTreeHost->commitComplete();
+
+        EXPECT_EQ_RECT(IntRect(), child2->occludedScreenSpace().bounds());
+        EXPECT_EQ(0u, child2->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(), grandChild->occludedScreenSpace().bounds());
+        EXPECT_EQ(0u, grandChild->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(30, 40, 70, 60), child->occludedScreenSpace().bounds());
+        EXPECT_EQ(1u, child->occludedScreenSpace().rects().size());
+        EXPECT_EQ_RECT(IntRect(10, 70, 90, 30), rootLayer->occludedScreenSpace().bounds());
+        EXPECT_EQ(1u, rootLayer->occludedScreenSpace().rects().size());
+
+        // Kill the layerTreeHost immediately.
+        m_layerTreeHost->setRootLayer(0);
+        m_layerTreeHost.clear();
+
+        endTest();
+    }
+
+    virtual void afterTest()
+    {
+    }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestLayerOcclusionWithFilters)
+
 class CCLayerTreeHostTestManySurfaces : public CCLayerTreeHostTest {
 public:
     CCLayerTreeHostTestManySurfaces() { }