Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Don't always make backing store for -webkit-backface-visibility:hidden
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.

Canonical link: https://commits.webkit.org/150473@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@168119 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
smfr committed May 1, 2014
1 parent e2a1890 commit 90191e2
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 14 deletions.
19 changes: 19 additions & 0 deletions LayoutTests/ChangeLog
@@ -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
Expand Down
@@ -0,0 +1,3 @@
Should be no layers here.


@@ -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)
)
)
)
)
)
)
)

@@ -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>
@@ -0,0 +1,3 @@
Should be no layers here.


@@ -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>
35 changes: 35 additions & 0 deletions LayoutTests/compositing/backing/backface-visibility.html
@@ -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>
Expand Up @@ -127,7 +127,7 @@

#first-letter::first-letter {
float: left;
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0);
}

</style>
Expand Down
32 changes: 32 additions & 0 deletions Source/WebCore/ChangeLog
@@ -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.
Expand Down
12 changes: 11 additions & 1 deletion Source/WebCore/rendering/RenderLayer.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
15 changes: 11 additions & 4 deletions Source/WebCore/rendering/RenderLayer.h
Expand Up @@ -499,7 +499,9 @@ class RenderLayer final : public ScrollableArea {
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;
Expand Down Expand Up @@ -1113,10 +1115,11 @@ class RenderLayer final : public ScrollableArea {
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();
Expand Down Expand Up @@ -1253,6 +1256,10 @@ class RenderLayer final : public ScrollableArea {
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;

Expand Down
12 changes: 10 additions & 2 deletions Source/WebCore/rendering/RenderLayerCompositor.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/rendering/RenderLayerCompositor.h
Expand Up @@ -392,6 +392,7 @@ class RenderLayerCompositor : public GraphicsLayerClient, public GraphicsLayerUp
// 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;
Expand Down
Expand Up @@ -115,9 +115,9 @@
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>
Expand Down
6 changes: 3 additions & 3 deletions WebKit.xcworkspace/xcshareddata/xcschemes/All Source.xcscheme
Expand Up @@ -115,9 +115,9 @@
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>
Expand Down

0 comments on commit 90191e2

Please sign in to comment.