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 3387cef47d0c559ae37dbe711b4749694ba9fd31..73d2f5673a07a5363f36b0e0e4ae985728cda8d1 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 eb5d0efb1d9776c30e3210cd77b934876c4ff849..cdf222e4ec275a9b6bf823fba8afe8b068cf6d65 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 b100d1d29c655e21c423b8bcdf9e81772389d6a1..2fd7a0237584065828540e30def5dcb3d82f7069 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 0d1b5e7f0c6a20684a131502ee159081fd493108..2df96c3eb834b87c54b9651a425110cf793fac00 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 20a31844c25edf5f38ca3e0dbdd7dc2c77fa60d9..992256af8a66825f24f2acf768bb75135df733fa 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 0e6b720488b86693f8191f11d3d08127da9c06f6..3a976bbcf41bd2c78dfcb55c4513c41c82c11270 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 e32d1096dda09e2a2e8676312ac330779bcb43d8..5916589f4a907388509326db0cf95a442dae7f89 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 8885373a5781f308430d8eeb47e61853c25b6e8f..0883390c1ea4987751f7e78c59a0a054b806132e 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 9b320f6f2c1fff444b2e062e51bca7b6e75b9fd3..89b5883055d19c01705821e215cdb716c575c2ef 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>