[CSS Filters] RenderLayerCompositor::addToOverlapMap should take into account the...
authormvujovic@adobe.com <mvujovic@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Jan 2013 18:16:00 +0000 (18:16 +0000)
committermvujovic@adobe.com <mvujovic@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Jan 2013 18:16:00 +0000 (18:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=94022

Reviewed by Simon Fraser.

Source/WebCore:

When a layer has a filter that moves pixels, we need to add its entire bounds, including its
outsets and children, to the overlap map. The filter can move the children's pixels
anywhere in the layer, so we can't rely on the children's bounds.

Eventually, we should avoid adding children to the overlap map if the parent's bounds used
for overlap testing already include the children. I've added a FIXME for this optimization.

Tests: compositing/filters/sw-layer-overlaps-hw-shadow.html
       compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html
       compositing/filters/sw-shadow-overlaps-hw-layer.html
       compositing/filters/sw-shadow-overlaps-hw-shadow.html

* rendering/RenderLayer.h:
(WebCore::RenderLayer::overlapBounds):
    If necessary, return the calculated layer bounds, including the children. Otherwise,
    return the localBoundingBox.
(RenderLayer):
(WebCore::RenderLayer::overlapBoundsIncludeChildren):
    If the layer has a filter that moves pixels, return true.
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::addToOverlapMap):
    Add the overlapBounds instead of the localBoundingBox to the overlap map.
(WebCore::RenderLayerCompositor::computeCompositingRequirements):
    Use the overlapBounds instead of the localBoundingBox for overlap testing.

LayoutTests:

Add tests to check several combinations of software layer and composited layer overlap when
filter outsets are involved.

* compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt: Added.
* compositing/filters/sw-layer-overlaps-hw-shadow.html: Added.
* compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt: Added.
* compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html: Added.
* compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt: Added.
* compositing/filters/sw-shadow-overlaps-hw-layer.html: Added.
* compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt: Added.
* compositing/filters/sw-shadow-overlaps-hw-shadow.html: Added.
* platform/chromium/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt: Added.
* platform/chromium/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt [new file with mode: 0644]
LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow.html [new file with mode: 0644]
LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt [new file with mode: 0644]
LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html [new file with mode: 0644]
LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt [new file with mode: 0644]
LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer.html [new file with mode: 0644]
LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt [new file with mode: 0644]
LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow.html [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerCompositor.cpp

index eb9db35..76b0c8f 100644 (file)
@@ -1,3 +1,24 @@
+2013-01-10  Max Vujovic  <mvujovic@adobe.com>
+
+        [CSS Filters] RenderLayerCompositor::addToOverlapMap should take into account the filters outsets (ie. blur and drop-shadow)
+        https://bugs.webkit.org/show_bug.cgi?id=94022
+
+        Reviewed by Simon Fraser.
+
+        Add tests to check several combinations of software layer and composited layer overlap when
+        filter outsets are involved.
+
+        * compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt: Added.
+        * compositing/filters/sw-layer-overlaps-hw-shadow.html: Added.
+        * compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt: Added.
+        * compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html: Added.
+        * compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt: Added.
+        * compositing/filters/sw-shadow-overlaps-hw-layer.html: Added.
+        * compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt: Added.
+        * compositing/filters/sw-shadow-overlaps-hw-shadow.html: Added.
+        * platform/chromium/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt: Added.
+        * platform/chromium/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt: Added.
+
 2013-01-09  Ojan Vafai  <ojan@chromium.org>
 
         intrinsic min-widths don't override width for file upload controls
diff --git a/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt b/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt
new file mode 100644 (file)
index 0000000..97b9e75
--- /dev/null
@@ -0,0 +1,20 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 80.00 80.00)
+          (anchor 0.60 0.60)
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+        (GraphicsLayer
+          (bounds 100.00 100.00)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow.html b/LayoutTests/compositing/filters/sw-layer-overlaps-hw-shadow.html
new file mode 100644 (file)
index 0000000..d21c879
--- /dev/null
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+<head>
+    <title>
+        This test verifies that a software layer will be promoted to a composited layer
+        if it intersects a composited layer's drop shadow.
+    </title>
+    <!-- If the test passes, the light green drop shadow should appear over the the black div where they intersect. -->
+    <style>
+        #software {
+            background-color: green;
+
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+        }
+        #composited {
+            background-color: black;
+            -webkit-filter: drop-shadow(-25px -25px 0 gray);
+
+            position: absolute;
+            top: 105px;
+            left: 105px;
+            width: 100px;
+            height: 100px;
+            -webkit-transform: translate3d(0, 0, 0);
+        }
+    </style>
+</head>
+<body>
+    <div id="composited"></div>
+    <div id="software"></div>
+    <pre id="console"></pre>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            document.getElementById("console").appendChild(document.createTextNode(window.internals.layerTreeAsText(document)));
+        }
+    </script>
+</body>
+</html>
+
diff --git a/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt b/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
new file mode 100644 (file)
index 0000000..3d308f6
--- /dev/null
@@ -0,0 +1,21 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 205.00 205.00)
+          (anchor 0.78 0.78)
+          (bounds 225.00 225.00)
+          (drawsContent 1)
+        )
+        (GraphicsLayer
+          (bounds 225.00 225.00)
+          (drawsContent 1)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html b/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html
new file mode 100644 (file)
index 0000000..8913a11
--- /dev/null
@@ -0,0 +1,68 @@
+<!doctype html>
+<html>
+<head>
+    <title>
+        This test verifies that a software layer will be promoted to a composited layer
+        if its nested drop shadow intersects a composited layer's nested drop shadow.
+    </title>
+    <!-- If the test passes, the light green drop shadow should appear over the the gray drop shadow where they intersect. -->
+    <style>
+        #software-parent {
+            background-color: green;
+            -webkit-filter: drop-shadow(25px 25px 0 lightgreen);
+
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+        }
+        #software-child {
+            background-color: blue;
+            -webkit-filter: drop-shadow(50px 50px 0 lightblue);
+
+            position: absolute;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+        }
+        #composited-parent {
+            background-color: black;
+            -webkit-filter: drop-shadow(-25px -25px 0 gray);
+
+            position: absolute;
+            top: 330px;
+            left: 330px;
+            width: 100px;
+            height: 100px;
+            -webkit-transform: translate3d(0, 0, 0);
+        }
+        #composited-child {
+            background-color: blue;
+            -webkit-filter: drop-shadow(-50px -50px 0 lightblue);
+
+            position: absolute;
+            top: -50px;
+            left: -50px;
+            width: 50px;
+            height: 50px;
+        }
+    </style>
+</head>
+<body>
+    <div id="composited-parent">
+        <div id="composited-child"></div>
+    </div>
+    <div id="software-parent">
+        <div id="software-child"></div>
+    </div>
+    <pre id="console"></pre>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            document.getElementById("console").appendChild(document.createTextNode(window.internals.layerTreeAsText(document)));
+        }
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt b/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt
new file mode 100644 (file)
index 0000000..71410f5
--- /dev/null
@@ -0,0 +1,19 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 105.00 105.00)
+          (bounds 100.00 100.00)
+        )
+        (GraphicsLayer
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer.html b/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer.html
new file mode 100644 (file)
index 0000000..e2e3169
--- /dev/null
@@ -0,0 +1,43 @@
+<!doctype html>
+<html>
+<head>
+    <title>
+        This test verifies that a software layer will be promoted to a composited layer
+        if its drop shadow intersects a composited layer.
+    </title>
+    <!-- If the test passes, the light green drop shadow should appear over the the black div where they intersect. -->
+    <style>
+        #software {
+            background-color: green;
+            -webkit-filter: drop-shadow(25px 25px 0 lightgreen);
+
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+        }
+        #composited {
+            background-color: black;
+
+            position: absolute;
+            top: 105px;
+            left: 105px;
+            width: 100px;
+            height: 100px;
+            -webkit-transform: translate3d(0, 0, 0);
+        }
+    </style>
+</head>
+<body>
+    <div id="composited"></div>
+    <div id="software"></div>
+    <pre id="console"></pre>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            document.getElementById("console").appendChild(document.createTextNode(window.internals.layerTreeAsText(document)));
+        }
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt b/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt
new file mode 100644 (file)
index 0000000..b8902bf
--- /dev/null
@@ -0,0 +1,21 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 105.00 105.00)
+          (anchor 0.60 0.60)
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+        (GraphicsLayer
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow.html b/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow.html
new file mode 100644 (file)
index 0000000..202636d
--- /dev/null
@@ -0,0 +1,45 @@
+<!doctype html>
+<html>
+<head>
+    <title>
+        This test verifies that a software layer will be promoted to a composited layer
+        if its drop shadow intersects a composited layer's drop shadow.
+    </title>
+    <!-- If the test passes, the light green drop shadow should appear over the the gray drop shadow where they intersect. -->
+    <style>
+        #software {
+            background-color: green;
+            -webkit-filter: drop-shadow(25px 25px 0 lightgreen);
+
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100px;
+            height: 100px;
+        }
+        #composited {
+            background-color: black;
+            -webkit-filter: drop-shadow(-25px -25px 0 gray);
+
+            position: absolute;
+            top: 130px;
+            left: 130px;
+            width: 100px;
+            height: 100px;
+            -webkit-transform: translate3d(0, 0, 0);
+        }
+    </style>
+</head>
+<body>
+    <div id="composited"></div>
+    <div id="software"></div>
+    <pre id="console"></pre>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            document.getElementById("console").appendChild(document.createTextNode(window.internals.layerTreeAsText(document)));
+        }
+    </script>
+</body>
+</html>
+
diff --git a/LayoutTests/platform/chromium/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt b/LayoutTests/platform/chromium/compositing/filters/sw-layer-overlaps-hw-shadow-expected.txt
new file mode 100644 (file)
index 0000000..9269070
--- /dev/null
@@ -0,0 +1,21 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 80.00 80.00)
+          (anchor 0.60 0.60)
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+        (GraphicsLayer
+          (bounds 100.00 100.00)
+          (drawsContent 1)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/platform/chromium/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt b/LayoutTests/platform/chromium/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt
new file mode 100644 (file)
index 0000000..7f36dc3
--- /dev/null
@@ -0,0 +1,20 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (children 2
+        (GraphicsLayer
+          (position 105.00 105.00)
+          (bounds 100.00 100.00)
+          (drawsContent 1)
+        )
+        (GraphicsLayer
+          (bounds 125.00 125.00)
+          (drawsContent 1)
+        )
+      )
+    )
+  )
+)
+
index b02b46b..af6628e 100644 (file)
@@ -1,3 +1,35 @@
+2013-01-10  Max Vujovic  <mvujovic@adobe.com>
+
+        [CSS Filters] RenderLayerCompositor::addToOverlapMap should take into account the filters outsets (ie. blur and drop-shadow)
+        https://bugs.webkit.org/show_bug.cgi?id=94022
+
+        Reviewed by Simon Fraser.
+
+        When a layer has a filter that moves pixels, we need to add its entire bounds, including its
+        outsets and children, to the overlap map. The filter can move the children's pixels
+        anywhere in the layer, so we can't rely on the children's bounds.
+
+        Eventually, we should avoid adding children to the overlap map if the parent's bounds used
+        for overlap testing already include the children. I've added a FIXME for this optimization.
+
+        Tests: compositing/filters/sw-layer-overlaps-hw-shadow.html
+               compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html
+               compositing/filters/sw-shadow-overlaps-hw-layer.html
+               compositing/filters/sw-shadow-overlaps-hw-shadow.html
+
+        * rendering/RenderLayer.h:
+        (WebCore::RenderLayer::overlapBounds):
+            If necessary, return the calculated layer bounds, including the children. Otherwise,
+            return the localBoundingBox.
+        (RenderLayer):
+        (WebCore::RenderLayer::overlapBoundsIncludeChildren):
+            If the layer has a filter that moves pixels, return true.
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::addToOverlapMap):
+            Add the overlapBounds instead of the localBoundingBox to the overlap map.
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
+            Use the overlapBounds instead of the localBoundingBox for overlap testing.
+
 2013-01-09  Ojan Vafai  <ojan@chromium.org>
 
         intrinsic min-widths don't override width for file upload controls
index df49201..bb9bf12 100644 (file)
@@ -604,6 +604,17 @@ public:
     // Pixel snapped bounding box relative to the root.
     IntRect absoluteBoundingBox() const;
 
+    // Bounds used for layer overlap testing in RenderLayerCompositor.
+    LayoutRect overlapBounds() const { return overlapBoundsIncludeChildren() ? calculateLayerBounds(this) : localBoundingBox(); }
+
+#if ENABLE(CSS_FILTERS)
+    // If true, this layer's children are included in its bounds for overlap testing.
+    // We can't rely on the children's positions if this layer has a filter that could have moved the children's pixels around.
+    bool overlapBoundsIncludeChildren() const { return hasFilter() && renderer()->style()->filter().hasFilterThatMovesPixels(); }
+#else
+    bool overlapBoundsIncludeChildren() const { return false; }
+#endif
+
     // Can pass offsetFromRoot if known.
     IntRect calculateLayerBounds(const RenderLayer* ancestorLayer, const LayoutPoint* offsetFromRoot = 0, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags) const;
     
index fde3297..20ae5d2 100644 (file)
@@ -737,7 +737,9 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer*
         return;
 
     if (!boundsComputed) {
-        layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->localBoundingBox()));
+        // FIXME: If this layer's overlap bounds include its children, we don't need to add its
+        // children's bounds to the overlap map.
+        layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->overlapBounds()));
         // Empty rects never intersect, but we need them to for the purposes of overlap testing.
         if (layerBounds.isEmpty())
             layerBounds.setSize(IntSize(1, 1));
@@ -824,7 +826,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
     IntRect absBounds;
     if (overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) {
         // If we're testing for overlap, we only need to composite if we overlap something that is already composited.
-        absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->localBoundingBox()));
+        absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds()));
 
         // Empty rects never intersect, but we need them to for the purposes of overlap testing.
         if (absBounds.isEmpty())