Don't always make backing store for -webkit-backface-visibility:hidden
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 May 2014 20:56:21 +0000 (20:56 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 May 2014 20:56:21 +0000 (20:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=132420

Reviewed by Sam Weinig.

Source/WebCore:
Previously, -webkit-backface-visibility:hidden unconditionally created
compositing layers with backing store. This results in high memory use
on pages with this style applied to many elements (a cargo-cult "optimization").

Fix by only having -webkit-backface-visibility:hidden create compositing layers
if some ancestor has a 3D transform. That's the only scenario in which the
element can be flipped around to reveal the back side, so the only time we need
to do compositing for this property. In future, we could be smarter, and only
consider 3D transforms in the current preserve-3d context.

Tests: compositing/backing/backface-visibility-in-3dtransformed.html
       compositing/backing/backface-visibility-in-transformed.html
       compositing/backing/backface-visibility.html

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::RenderLayer):
(WebCore::RenderLayer::updateLayerPositions):
(WebCore::RenderLayer::hitTestLayer):
* rendering/RenderLayer.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::requiresCompositingLayer):
(WebCore::RenderLayerCompositor::requiresOwnBackingStore):
(WebCore::RenderLayerCompositor::requiresCompositingForBackfaceVisibility):
* rendering/RenderLayerCompositor.h:

LayoutTests:
Dump layers for elements with backface-visibility: hidden with various types
of ancestors.

* compositing/backing/backface-visibility-expected.txt: Added.
* compositing/backing/backface-visibility-in-3dtransformed-expected.txt: Added.
* compositing/backing/backface-visibility-in-3dtransformed.html: Added.
* compositing/backing/backface-visibility-in-transformed-expected.txt: Added.
* compositing/backing/backface-visibility-in-transformed.html: Added.
* compositing/backing/backface-visibility.html: Added.
* inspector-protocol/layers/layers-anonymous.html: Don't use backface-visibility
for force a layer.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/compositing/backing/backface-visibility-expected.txt [new file with mode: 0644]
LayoutTests/compositing/backing/backface-visibility-in-3dtransformed-expected.txt [new file with mode: 0644]
LayoutTests/compositing/backing/backface-visibility-in-3dtransformed.html [new file with mode: 0644]
LayoutTests/compositing/backing/backface-visibility-in-transformed-expected.txt [new file with mode: 0644]
LayoutTests/compositing/backing/backface-visibility-in-transformed.html [new file with mode: 0644]
LayoutTests/compositing/backing/backface-visibility.html [new file with mode: 0644]
LayoutTests/inspector-protocol/layers/layers-anonymous.html
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h
WebKit.xcworkspace/xcshareddata/xcschemes/All Source (target WebProcess).xcscheme
WebKit.xcworkspace/xcshareddata/xcschemes/All Source.xcscheme

index 3387cef..73d2f56 100644 (file)
@@ -1,3 +1,22 @@
+2014-05-01  Simon Fraser  <simon.fraser@apple.com>
+
+        Don't always make backing store for -webkit-backface-visibility:hidden
+        https://bugs.webkit.org/show_bug.cgi?id=132420
+
+        Reviewed by Sam Weinig.
+        
+        Dump layers for elements with backface-visibility: hidden with various types
+        of ancestors.
+
+        * compositing/backing/backface-visibility-expected.txt: Added.
+        * compositing/backing/backface-visibility-in-3dtransformed-expected.txt: Added.
+        * compositing/backing/backface-visibility-in-3dtransformed.html: Added.
+        * compositing/backing/backface-visibility-in-transformed-expected.txt: Added.
+        * compositing/backing/backface-visibility-in-transformed.html: Added.
+        * compositing/backing/backface-visibility.html: Added.
+        * inspector-protocol/layers/layers-anonymous.html: Don't use backface-visibility
+        for force a layer.
+
 2014-05-01  Brent Fulgham  <bfulgham@apple.com>
 
         Fix handling of attributes prior to compiling shader
diff --git a/LayoutTests/compositing/backing/backface-visibility-expected.txt b/LayoutTests/compositing/backing/backface-visibility-expected.txt
new file mode 100644 (file)
index 0000000..adf6bcc
--- /dev/null
@@ -0,0 +1,3 @@
+Should be no layers here.
+
+
diff --git a/LayoutTests/compositing/backing/backface-visibility-in-3dtransformed-expected.txt b/LayoutTests/compositing/backing/backface-visibility-in-3dtransformed-expected.txt
new file mode 100644 (file)
index 0000000..559495b
--- /dev/null
@@ -0,0 +1,28 @@
+Should be several layers here.
+
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 8.00 50.00)
+          (bounds 122.00 122.00)
+          (drawsContent 1)
+          (transform [1.00 0.00 0.00 0.00] [0.00 1.00 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 10.00 1.00])
+          (children 1
+            (GraphicsLayer
+              (position 11.00 11.00)
+              (bounds 100.00 100.00)
+              (contentsOpaque 1)
+              (backfaceVisibility hidden)
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/backing/backface-visibility-in-3dtransformed.html b/LayoutTests/compositing/backing/backface-visibility-in-3dtransformed.html
new file mode 100644 (file)
index 0000000..667c050
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            height: 100px;
+            width: 100px;
+            padding: 10px;
+            border: 1px solid gray;
+        }
+        .box {
+          width: 100px;
+          height: 100px;
+          background-color: silver;
+        }
+        
+        .transformed {
+            -webkit-transform: translateZ(10px);
+        }
+        .backface-hidden {
+            -webkit-backface-visibility: hidden;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        function dumpLayers()
+        {
+            var layersResult = document.getElementById('layers');
+            if (window.testRunner)
+                layersResult.innerText = window.internals.layerTreeAsText(document);
+
+        }
+        window.addEventListener('load', dumpLayers, false)
+    </script>
+</head>
+<body>
+    <p>Should be several layers here.</p>
+    <div class="transformed container">
+        <div class="backface-hidden box"></div>
+    </div>
+<pre id="layers"></pre>
+</body>
+</html>
diff --git a/LayoutTests/compositing/backing/backface-visibility-in-transformed-expected.txt b/LayoutTests/compositing/backing/backface-visibility-in-transformed-expected.txt
new file mode 100644 (file)
index 0000000..adf6bcc
--- /dev/null
@@ -0,0 +1,3 @@
+Should be no layers here.
+
+
diff --git a/LayoutTests/compositing/backing/backface-visibility-in-transformed.html b/LayoutTests/compositing/backing/backface-visibility-in-transformed.html
new file mode 100644 (file)
index 0000000..563d6f3
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            height: 100px;
+            width: 100px;
+            padding: 10px;
+            border: 1px solid gray;
+        }
+        .box {
+          width: 100px;
+          height: 100px;
+          background-color: silver;
+        }
+        
+        .transformed {
+            -webkit-transform: translate(10px, 10px);
+        }
+        .backface-hidden {
+            -webkit-backface-visibility: hidden;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        function dumpLayers()
+        {
+            var layersResult = document.getElementById('layers');
+            if (window.testRunner)
+                layersResult.innerText = window.internals.layerTreeAsText(document);
+
+        }
+        window.addEventListener('load', dumpLayers, false)
+    </script>
+</head>
+<body>
+    <p>Should be no layers here.</p>
+    <div class="transformed container">
+        <div class="backface-hidden box"></div>
+    </div>
+<pre id="layers"></pre>
+</body>
+</html>
diff --git a/LayoutTests/compositing/backing/backface-visibility.html b/LayoutTests/compositing/backing/backface-visibility.html
new file mode 100644 (file)
index 0000000..2b053c5
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .box {
+          width: 100px;
+          height: 100px;
+          background-color: silver;
+        }
+        
+        .backface-hidden {
+            -webkit-backface-visibility: hidden;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        function dumpLayers()
+        {
+            var layersResult = document.getElementById('layers');
+            if (window.testRunner)
+                layersResult.innerText = window.internals.layerTreeAsText(document);
+
+        }
+        window.addEventListener('load', dumpLayers, false)
+    </script>
+</head>
+<body>
+    <p>Should be no layers here.</p>
+    <div class="backface-hidden box"></div>
+<pre id="layers"></pre>
+</body>
+</html>
index eb5d0ef..cdf222e 100644 (file)
@@ -127,7 +127,7 @@ window.addEventListener("DOMContentLoaded", function()
 
     #first-letter::first-letter {
         float: left;
-        -webkit-backface-visibility: hidden;
+        -webkit-transform: translateZ(0);
     }
 
 </style>
index b100d1d..2fd7a02 100644 (file)
@@ -1,3 +1,35 @@
+2014-05-01  Simon Fraser  <simon.fraser@apple.com>
+
+        Don't always make backing store for -webkit-backface-visibility:hidden
+        https://bugs.webkit.org/show_bug.cgi?id=132420
+
+        Reviewed by Sam Weinig.
+        
+        Previously, -webkit-backface-visibility:hidden unconditionally created
+        compositing layers with backing store. This results in high memory use
+        on pages with this style applied to many elements (a cargo-cult "optimization").
+        
+        Fix by only having -webkit-backface-visibility:hidden create compositing layers
+        if some ancestor has a 3D transform. That's the only scenario in which the
+        element can be flipped around to reveal the back side, so the only time we need
+        to do compositing for this property. In future, we could be smarter, and only
+        consider 3D transforms in the current preserve-3d context.
+
+        Tests: compositing/backing/backface-visibility-in-3dtransformed.html
+               compositing/backing/backface-visibility-in-transformed.html
+               compositing/backing/backface-visibility.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::RenderLayer):
+        (WebCore::RenderLayer::updateLayerPositions):
+        (WebCore::RenderLayer::hitTestLayer):
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::requiresCompositingLayer):
+        (WebCore::RenderLayerCompositor::requiresOwnBackingStore):
+        (WebCore::RenderLayerCompositor::requiresCompositingForBackfaceVisibility):
+        * rendering/RenderLayerCompositor.h:
+
 2014-05-01  Alex Christensen  <achristensen@webkit.org>
 
         Finish updating ANGLE.
index 0d1b5e7..2df96c3 100644 (file)
@@ -169,6 +169,8 @@ RenderLayer::RenderLayer(RenderLayerModelObject& rendererLayerModelObject)
     , m_3DTransformedDescendantStatusDirty(true)
     , m_has3DTransformedDescendant(false)
     , m_hasCompositingDescendant(false)
+    , m_hasTransformedAncestor(false)
+    , m_has3DTransformedAncestor(false)
     , m_indirectCompositingReason(NoIndirectCompositingReason)
     , m_viewportConstrainedNotCompositedReason(NoNotCompositedReason)
 #if PLATFORM(IOS)
@@ -449,6 +451,8 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
         clearRepaintRects();
 
     m_repaintStatus = NeedsNormalRepaint;
+    m_hasTransformedAncestor = flags & SeenTransformedLayer;
+    m_has3DTransformedAncestor = flags & Seen3DTransformedLayer;
 
     // Go ahead and update the reflection's position and size.
     if (m_reflection)
@@ -467,6 +471,12 @@ void RenderLayer::updateLayerPositions(RenderGeometryMap* geometryMap, UpdateLay
     if (renderer().hasColumns())
         flags |= UpdatePagination;
 
+    if (transform()) {
+        flags |= SeenTransformedLayer;
+        if (!transform()->isAffine())
+            flags |= Seen3DTransformedLayer;
+    }
+
     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
         child->updateLayerPositions(geometryMap, flags);
 
@@ -4931,7 +4941,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
         // We computed the correct state in the caller (above code), so just reference it.
         ASSERT(transformState);
         localTransformState = const_cast<HitTestingTransformState*>(transformState);
-    } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
+    } else if (transformState || has3DTransformedDescendant() || preserves3D()) {
         // We need transform state for the first time, or to offset the container state, so create it here.
         localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
     }
index 20a3184..992256a 100644 (file)
@@ -499,7 +499,9 @@ public:
         NeedsFullRepaintInBacking = 1 << 1,
         IsCompositingUpdateRoot = 1 << 2,
         UpdateCompositingLayers = 1 << 3,
-        UpdatePagination = 1 << 4
+        UpdatePagination = 1 << 4,
+        SeenTransformedLayer = 1 << 5,
+        Seen3DTransformedLayer = 1 << 6
     };
     typedef unsigned UpdateLayerPositionsFlags;
     static const UpdateLayerPositionsFlags defaultFlags = CheckForRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers;
@@ -1113,10 +1115,11 @@ private:
     void updateDescendantDependentFlags(HashSet<const RenderObject*>* outOfFlowDescendantContainingBlocks = 0);
     bool checkIfDescendantClippingContextNeedsUpdate(bool isClipping);
 
-    // This flag is computed by RenderLayerCompositor, which knows more about 3d hierarchies than we do.
-    void setHas3DTransformedDescendant(bool b) { m_has3DTransformedDescendant = b; }
     bool has3DTransformedDescendant() const { return m_has3DTransformedDescendant; }
-    
+
+    bool hasTransformedAncestor() const { return m_hasTransformedAncestor; }
+    bool has3DTransformedAncestor() const { return m_has3DTransformedAncestor; }
+
     void dirty3DTransformedDescendantStatus();
     // Both updates the status, and returns true if descendants of this have 3d.
     bool update3DTransformedDescendantStatus();
@@ -1253,6 +1256,10 @@ private:
     bool m_has3DTransformedDescendant : 1;  // Set on a stacking context layer that has 3D descendants anywhere
                                             // in a preserves3D hierarchy. Hint to do 3D-aware hit testing.
     bool m_hasCompositingDescendant : 1; // In the z-order tree.
+
+    bool m_hasTransformedAncestor : 1;
+    bool m_has3DTransformedAncestor : 1;
+
     unsigned m_indirectCompositingReason : 3;
     unsigned m_viewportConstrainedNotCompositedReason : 2;
 
index 0e6b720..3a976bb 100644 (file)
@@ -2032,7 +2032,7 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer& layer, R
         || requiresCompositingForCanvas(*renderer)
         || requiresCompositingForPlugin(*renderer)
         || requiresCompositingForFrame(*renderer)
-        || (canRender3DTransforms() && renderer->style().backfaceVisibility() == BackfaceVisibilityHidden)
+        || requiresCompositingForBackfaceVisibility(*renderer)
         || clipsCompositingDescendants(*renderer->layer())
         || requiresCompositingForAnimation(*renderer)
         || requiresCompositingForFilters(*renderer)
@@ -2075,7 +2075,7 @@ bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer& layer, co
         || requiresCompositingForCanvas(renderer)
         || requiresCompositingForPlugin(renderer)
         || requiresCompositingForFrame(renderer)
-        || (canRender3DTransforms() && renderer.style().backfaceVisibility() == BackfaceVisibilityHidden)
+        || requiresCompositingForBackfaceVisibility(renderer)
         || requiresCompositingForAnimation(renderer)
         || requiresCompositingForFilters(renderer)
         || requiresCompositingForPosition(renderer, layer)
@@ -2342,6 +2342,14 @@ bool RenderLayerCompositor::requiresCompositingForTransform(RenderLayerModelObje
     return renderer.hasTransform() && renderer.style().transform().has3DOperation();
 }
 
+bool RenderLayerCompositor::requiresCompositingForBackfaceVisibility(RenderLayerModelObject& renderer) const
+{
+    if (!(m_compositingTriggers & ChromeClient::ThreeDTransformTrigger))
+        return false;
+
+    return renderer.style().backfaceVisibility() == BackfaceVisibilityHidden && renderer.layer()->has3DTransformedAncestor();
+}
+
 bool RenderLayerCompositor::requiresCompositingForVideo(RenderLayerModelObject& renderer) const
 {
     if (!(m_compositingTriggers & ChromeClient::VideoTrigger))
index e32d109..5916589 100644 (file)
@@ -392,6 +392,7 @@ private:
     // Whether a running transition or animation enforces the need for a compositing layer.
     bool requiresCompositingForAnimation(RenderLayerModelObject&) const;
     bool requiresCompositingForTransform(RenderLayerModelObject&) const;
+    bool requiresCompositingForBackfaceVisibility(RenderLayerModelObject&) const;
     bool requiresCompositingForVideo(RenderLayerModelObject&) const;
     bool requiresCompositingForCanvas(RenderLayerModelObject&) const;
     bool requiresCompositingForPlugin(RenderLayerModelObject&) const;
index 8885373..0883390 100644 (file)
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "1AD7451818D0D26C006F3A1E"
-               BuildableName = "WebKit.framework"
-               BlueprintName = "WebKit"
+               BlueprintIdentifier = "9398100A0824BF01008DF038"
+               BuildableName = "WebKitLegacy.framework"
+               BlueprintName = "WebKitLegacy"
                ReferencedContainer = "container:Source/WebKit/WebKit.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
index 9b320f6..89b5883 100644 (file)
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "1AD7451818D0D26C006F3A1E"
-               BuildableName = "WebKit.framework"
-               BlueprintName = "WebKit"
+               BlueprintIdentifier = "9398100A0824BF01008DF038"
+               BuildableName = "WebKitLegacy.framework"
+               BlueprintName = "WebKitLegacy"
                ReferencedContainer = "container:Source/WebKit/WebKit.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>