https://bugs.webkit.org/show_bug.cgi?id=40547
Source/WebCore:
Reviewed by Dean Jackson.
If a layer becomes composited because it needs to clip composited
descendants, or if it has perspective, then it doesn't actually
needs its own backing store; its contents can be painted by an
ancestor, and we can just have an empty layer that does the clipping
or applies the perspective transform.
This saves backing store memory on some pages.
Tests: compositing/backing/no-backing-for-clip-overlap.html
compositing/backing/no-backing-for-clip.html
compositing/backing/no-backing-for-perspective.html
* rendering/RenderLayer.cpp:
(WebCore):
(WebCore::RenderLayer::enclosingCompositingLayerForRepaint):
(WebCore::RenderLayer::paintLayer):
* rendering/RenderLayer.h:
(RenderLayer):
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::RenderLayerBacking):
(WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
(WebCore::RenderLayerBacking::containsPaintedContent):
(WebCore::RenderLayerBacking::setContentsNeedDisplay):
(WebCore::RenderLayerBacking::setContentsNeedDisplayInRect):
(WebCore::RenderLayerBacking::paintIntoLayer):
* rendering/RenderLayerBacking.h:
(RenderLayerBacking):
(WebCore::RenderLayerBacking::paintsIntoCompositedAncestor):
(WebCore::RenderLayerBacking::setRequiresOwnBackingStore):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::layerWillBeRemoved):
(WebCore::RenderLayerCompositor::recursiveRepaintLayerRect):
(WebCore::RenderLayerCompositor::requiresCompositingLayer):
(WebCore::RenderLayerCompositor::requiresOwnBackingStore):
(WebCore):
* rendering/RenderLayerCompositor.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::containerForRepaint):
* rendering/RenderTreeAsText.cpp:
(WebCore::write):
* rendering/RenderView.cpp:
(WebCore::RenderView::paintBoxDecorations):
LayoutTests:
Reviewed by Dean Jackson.
New tests for backing store elimination with clip or perspective.
New results for some tests that no longer have backing store on some
layers.
* compositing/backing/no-backing-for-clip-expected.txt: Added.
* compositing/backing/no-backing-for-clip-overlap-expected.txt: Added.
* compositing/backing/no-backing-for-clip-overlap.html: Added.
* compositing/backing/no-backing-for-clip.html: Added.
* compositing/backing/no-backing-for-perspective-expected.txt: Added.
* compositing/backing/no-backing-for-perspective.html: Added.
* compositing/geometry/preserve-3d-switching-expected.txt:
* compositing/visibility/layer-visible-content-expected.png:
* compositing/visibility/layer-visible-content-expected.txt:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@114283
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-04-13 Simon Fraser <simon.fraser@apple.com>
+
+ Avoid using backing store for compositing layers that just need to clip
+ https://bugs.webkit.org/show_bug.cgi?id=40547
+
+ Reviewed by Dean Jackson.
+
+ New tests for backing store elimination with clip or perspective.
+
+ New results for some tests that no longer have backing store on some
+ layers.
+
+ * compositing/backing/no-backing-for-clip-expected.txt: Added.
+ * compositing/backing/no-backing-for-clip-overlap-expected.txt: Added.
+ * compositing/backing/no-backing-for-clip-overlap.html: Added.
+ * compositing/backing/no-backing-for-clip.html: Added.
+ * compositing/backing/no-backing-for-perspective-expected.txt: Added.
+ * compositing/backing/no-backing-for-perspective.html: Added.
+ * compositing/geometry/preserve-3d-switching-expected.txt:
+ * compositing/visibility/layer-visible-content-expected.png:
+ * compositing/visibility/layer-visible-content-expected.txt:
+
2012-04-16 Vincent Scheib <scheib@chromium.org>
[Chromium] Marking css3/filters/huge-region.html and composited version MISSING, CRASH.
--- /dev/null
+This layer should not have backing store.
+This layer should not have backing store.
+(GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (position 8.00 8.00)
+ (bounds 342.00 240.00)
+ (children 1
+ (GraphicsLayer
+ (position 1.00 1.00)
+ (bounds 340.00 238.00)
+ (children 1
+ (GraphicsLayer
+ (position 20.00 38.00)
+ (bounds 320.00 180.00)
+ (children 1
+ (GraphicsLayer
+ (position 1.00 1.00)
+ (bounds 340.00 178.00)
+ (children 1
+ (GraphicsLayer
+ (position 30.00 48.00)
+ (bounds 100.00 100.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
--- /dev/null
+This layer should not have backing store.
+This layer should have backing store.
+(GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 2
+ (GraphicsLayer
+ (position 8.00 8.00)
+ (bounds 342.00 180.00)
+ (children 1
+ (GraphicsLayer
+ (position 1.00 1.00)
+ (bounds 340.00 178.00)
+ (children 1
+ (GraphicsLayer
+ (position 30.00 48.00)
+ (bounds 100.00 100.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ (GraphicsLayer
+ (position 8.00 178.00)
+ (bounds 342.00 180.00)
+ (drawsContent 1)
+ (children 1
+ (GraphicsLayer
+ (position 1.00 1.00)
+ (bounds 340.00 178.00)
+ (children 1
+ (GraphicsLayer
+ (position 30.00 48.00)
+ (bounds 100.00 100.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style type="text/css" media="screen">
+ .box {
+ position: relative;
+ height: 100px;
+ width: 100px;
+ margin: 10px;
+ left: 0;
+ top: 0;
+ background-color: silver;
+ }
+
+ .clipping {
+ position: relative;
+ z-index: 0;
+ width: 300px;
+ border: 1px solid black;
+ padding: 20px;
+ overflow: hidden;
+ }
+
+ .composited {
+ -webkit-transform: translateZ(0);
+ }
+ </style>
+
+ <script>
+ if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+ function dumpLayers()
+ {
+ var layersResult = document.getElementById('layers');
+ if (window.layoutTestController)
+ layersResult.innerText = layoutTestController.layerTreeAsText();
+
+ }
+ window.addEventListener('load', dumpLayers, false)
+ </script>
+
+</head>
+<body>
+
+ <div class="clipping">
+ This layer should not have backing store.
+ <div class="box composited"></div>
+ </div>
+ <div class="clipping" style="margin-top: -10px;">
+ This layer should have backing store.
+ <div class="box composited"></div>
+ </div>
+
+<pre id="layers">Layer tree goes here in DRT</pre>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style type="text/css" media="screen">
+ .box {
+ position: relative;
+ height: 100px;
+ width: 100px;
+ margin: 10px;
+ left: 0;
+ top: 0;
+ background-color: silver;
+ }
+
+ .clipping {
+ position: relative;
+ z-index: 0;
+ width: 300px;
+ border: 1px solid black;
+ padding: 20px;
+ overflow: hidden;
+ }
+
+ .composited {
+ -webkit-transform: translateZ(0);
+ }
+ </style>
+
+ <script>
+ if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+ function dumpLayers()
+ {
+ var layersResult = document.getElementById('layers');
+ if (window.layoutTestController)
+ layersResult.innerText = layoutTestController.layerTreeAsText();
+
+ }
+ window.addEventListener('load', dumpLayers, false)
+ </script>
+
+</head>
+<body>
+
+ <div class="clipping">
+ This layer should not have backing store.
+ <div class="clipping">
+ This layer should not have backing store.
+ <div class="box composited">
+ </div>
+ </div>
+ </div>
+
+<pre id="layers">Layer tree goes here in DRT</pre>
+
+</body>
+</html>
--- /dev/null
+This layer should not have backing store.
+This layer should not have backing store.
+(GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (bounds 800.00 600.00)
+ (children 1
+ (GraphicsLayer
+ (position 8.00 8.00)
+ (bounds 342.00 240.00)
+ (childrenTransform [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 0.00 1.00])
+ (children 1
+ (GraphicsLayer
+ (position 21.00 39.00)
+ (bounds 342.00 180.00)
+ (childrenTransform [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 0.00 1.00])
+ (children 1
+ (GraphicsLayer
+ (position 31.00 49.00)
+ (bounds 100.00 100.00)
+ (drawsContent 1)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+)
+
--- /dev/null
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style type="text/css" media="screen">
+ .box {
+ position: relative;
+ height: 100px;
+ width: 100px;
+ margin: 10px;
+ left: 0;
+ top: 0;
+ background-color: silver;
+ }
+
+ .perspective {
+ width: 300px;
+ border: 1px solid black;
+ padding: 20px;
+ -webkit-perspective: 500px;
+ }
+
+ .composited {
+ -webkit-transform: translateZ(0);
+ }
+ </style>
+
+ <script>
+ if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+ function dumpLayers()
+ {
+ var layersResult = document.getElementById('layers');
+ if (window.layoutTestController)
+ layersResult.innerText = layoutTestController.layerTreeAsText();
+
+ }
+ window.addEventListener('load', dumpLayers, false)
+ </script>
+
+</head>
+<body>
+
+ <div class="perspective">
+ This layer should not have backing store.
+ <div class="perspective">
+ This layer should not have backing store.
+ <div class="box composited">
+ </div>
+ </div>
+ </div>
+
+<pre id="layers">Layer tree goes here in DRT</pre>
+
+</body>
+</html>
(GraphicsLayer
(position 108.00 73.00)
(bounds 304.00 304.00)
- (drawsContent 1)
(childrenTransform [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 0.00 1.00])
(children 1
(GraphicsLayer
(children 2
(GraphicsLayer
(bounds 200.00 200.00)
- (drawsContent 1)
(children 1
(GraphicsLayer
(bounds 200.00 200.00)
+2012-04-13 Simon Fraser <simon.fraser@apple.com>
+
+ Avoid using backing store for compositing layers that just need to clip
+ https://bugs.webkit.org/show_bug.cgi?id=40547
+
+ Reviewed by Dean Jackson.
+
+ If a layer becomes composited because it needs to clip composited
+ descendants, or if it has perspective, then it doesn't actually
+ needs its own backing store; its contents can be painted by an
+ ancestor, and we can just have an empty layer that does the clipping
+ or applies the perspective transform.
+
+ This saves backing store memory on some pages.
+
+ Tests: compositing/backing/no-backing-for-clip-overlap.html
+ compositing/backing/no-backing-for-clip.html
+ compositing/backing/no-backing-for-perspective.html
+
+ * rendering/RenderLayer.cpp:
+ (WebCore):
+ (WebCore::RenderLayer::enclosingCompositingLayerForRepaint):
+ (WebCore::RenderLayer::paintLayer):
+ * rendering/RenderLayer.h:
+ (RenderLayer):
+ * rendering/RenderLayerBacking.cpp:
+ (WebCore::RenderLayerBacking::RenderLayerBacking):
+ (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
+ (WebCore::RenderLayerBacking::containsPaintedContent):
+ (WebCore::RenderLayerBacking::setContentsNeedDisplay):
+ (WebCore::RenderLayerBacking::setContentsNeedDisplayInRect):
+ (WebCore::RenderLayerBacking::paintIntoLayer):
+ * rendering/RenderLayerBacking.h:
+ (RenderLayerBacking):
+ (WebCore::RenderLayerBacking::paintsIntoCompositedAncestor):
+ (WebCore::RenderLayerBacking::setRequiresOwnBackingStore):
+ * rendering/RenderLayerCompositor.cpp:
+ (WebCore::RenderLayerCompositor::layerWillBeRemoved):
+ (WebCore::RenderLayerCompositor::recursiveRepaintLayerRect):
+ (WebCore::RenderLayerCompositor::requiresCompositingLayer):
+ (WebCore::RenderLayerCompositor::requiresOwnBackingStore):
+ (WebCore):
+ * rendering/RenderLayerCompositor.h:
+ * rendering/RenderObject.cpp:
+ (WebCore::RenderObject::containerForRepaint):
+ * rendering/RenderTreeAsText.cpp:
+ (WebCore::write):
+ * rendering/RenderView.cpp:
+ (WebCore::RenderView::paintBoxDecorations):
+
2012-04-16 Brady Eidson <beidson@apple.com>
<rdar://problem/11249336> and https://bugs.webkit.org/show_bug.cgi?id=84050
return 0;
}
+
+RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const
+{
+ if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor())
+ return const_cast<RenderLayer*>(this);
+
+ for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
+ if (curr->isComposited() && !curr->backing()->paintsIntoCompositedAncestor())
+ return const_cast<RenderLayer*>(curr);
+ }
+
+ return 0;
+}
#endif
#if ENABLE(CSS_FILTERS)
// but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
if (context->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
paintFlags |= PaintLayerTemporaryClipRects;
- else if (!backing()->paintsIntoWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
+ else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
// If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
return;
}
#if USE(ACCELERATED_COMPOSITING)
// Enclosing compositing layer; if includeSelf is true, may return this.
RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const;
+ RenderLayer* enclosingCompositingLayerForRepaint(bool includeSelf = true) const;
// Ancestor compositing layer, excluding this.
RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(false); }
#endif
, m_artificiallyInflatedBounds(false)
, m_isMainFrameRenderViewLayer(false)
, m_usingTiledCacheLayer(false)
+ , m_requiresOwnBackingStore(true)
#if ENABLE(CSS_FILTERS)
, m_canCompositeFilters(false)
#endif
}
m_graphicsLayer->setContentsRect(contentsBox());
+
+ // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
+ setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor));
+
updateDrawsContent();
updateAfterWidgetResize();
}
bool RenderLayerBacking::containsPaintedContent() const
{
- if (isSimpleContainerCompositingLayer() || paintsIntoWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
+ if (isSimpleContainerCompositingLayer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
return false;
if (isDirectlyCompositedImage())
void RenderLayerBacking::setContentsNeedDisplay()
{
+ ASSERT(!paintsIntoCompositedAncestor());
+
if (m_graphicsLayer && m_graphicsLayer->drawsContent())
m_graphicsLayer->setNeedsDisplay();
// r is in the coordinate space of the layer's render object
void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
{
+ ASSERT(!paintsIntoCompositedAncestor());
+
if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
IntRect layerDirtyRect = r;
layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer());
PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase,
RenderObject* paintingRoot)
{
- if (paintsIntoWindow()) {
+ if (paintsIntoWindow() || paintsIntoCompositedAncestor()) {
ASSERT_NOT_REACHED();
return;
}
// This returns false for other layers, and when the document layer actually needs to paint into its backing store
// for some reason.
bool paintsIntoWindow() const;
+
+ // Returns true for a composited layer that has no backing store of its own, so
+ // paints into some ancestor layer.
+ bool paintsIntoCompositedAncestor() const { return !m_requiresOwnBackingStore; }
+
+ void setRequiresOwnBackingStore(bool flag) { m_requiresOwnBackingStore = flag; }
void setContentsNeedDisplay();
// r is in the coordinate space of the layer's render object
bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
bool m_isMainFrameRenderViewLayer;
bool m_usingTiledCacheLayer;
+ bool m_requiresOwnBackingStore;
#if ENABLE(CSS_FILTERS)
bool m_canCompositeFilters;
#endif
setCompositingParent(child, 0);
- RenderLayer* compLayer = parent->enclosingCompositingLayer();
+ RenderLayer* compLayer = parent->enclosingCompositingLayerForRepaint();
if (compLayer) {
ASSERT(compLayer->backing());
LayoutRect compBounds = child->backing()->compositedBounds();
void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect)
{
// FIXME: This method does not work correctly with transforms.
- if (layer->isComposited())
+ if (layer->isComposited() && !layer->backing()->paintsIntoCompositedAncestor())
layer->setBackingNeedsRepaintInRect(rect);
#if !ASSERT_DISABLED
}
// The root layer always has a compositing layer, but it may not have backing.
return requiresCompositingForTransform(renderer)
- || requiresCompositingForVideo(renderer)
- || requiresCompositingForCanvas(renderer)
- || requiresCompositingForPlugin(renderer)
- || requiresCompositingForFrame(renderer)
- || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden)
- || clipsCompositingDescendants(layer)
- || requiresCompositingForAnimation(renderer)
- || requiresCompositingForFilters(renderer)
- || requiresCompositingForPosition(renderer, layer);
+ || requiresCompositingForVideo(renderer)
+ || requiresCompositingForCanvas(renderer)
+ || requiresCompositingForPlugin(renderer)
+ || requiresCompositingForFrame(renderer)
+ || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden)
+ || clipsCompositingDescendants(layer)
+ || requiresCompositingForAnimation(renderer)
+ || requiresCompositingForFilters(renderer)
+ || requiresCompositingForPosition(renderer, layer);
}
bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const
return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer();
}
+bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, const RenderLayer* compositingAncestorLayer) const
+{
+ RenderObject* renderer = layer->renderer();
+ if (compositingAncestorLayer
+ && !(compositingAncestorLayer->backing()->graphicsLayer()->drawsContent()
+ || compositingAncestorLayer->backing()->paintsIntoWindow()
+ || compositingAncestorLayer->backing()->paintsIntoCompositedAncestor()))
+ return true;
+
+ return layer->isRootLayer()
+ || layer->transform() // note: excludes perspective and transformStyle3D.
+ || requiresCompositingForVideo(renderer)
+ || requiresCompositingForCanvas(renderer)
+ || requiresCompositingForPlugin(renderer)
+ || requiresCompositingForFrame(renderer)
+ || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden)
+ || requiresCompositingForAnimation(renderer)
+ || requiresCompositingForFilters(renderer)
+ || requiresCompositingForPosition(renderer, layer)
+ || renderer->isTransparent()
+ || renderer->hasMask()
+ || renderer->hasReflection()
+ || renderer->hasFilter()
+ || layer->mustOverlapCompositedLayers();
+}
+
// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips,
// up to the enclosing compositing ancestor. This is required because compositing layers are parented
// according to the z-order hierarchy, yet clipping goes down the renderer hierarchy.
// Repaint parts of all composited layers that intersect the given absolute rectangle.
void repaintCompositedLayersAbsoluteRect(const IntRect&);
+ // Returns true if the given layer needs it own backing store.
+ bool requiresOwnBackingStore(const RenderLayer*, const RenderLayer* compositingAncestorLayer) const;
+
RenderLayer* rootRenderLayer() const;
GraphicsLayer* rootGraphicsLayer() const;
GraphicsLayer* scrollLayer() const;
#if USE(ACCELERATED_COMPOSITING)
if (v->usesCompositing()) {
- RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayer();
+ RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayerForRepaint();
if (compLayer)
repaintContainer = compLayer->renderer();
}
#if USE(ACCELERATED_COMPOSITING)
if (behavior & RenderAsTextShowCompositedLayers) {
if (l.isComposited())
- ts << " (composited, bounds " << l.backing()->compositedBounds() << ")";
+ ts << " (composited, bounds=" << l.backing()->compositedBounds() << ", drawsContent=" << l.backing()->graphicsLayer()->drawsContent() << ", paints into ancestor=" << l.backing()->paintsIntoCompositedAncestor() << ")";
}
#else
UNUSED_PARAM(behavior);
}
#if USE(ACCELERATED_COMPOSITING)
- if (RenderLayer* compositingLayer = layer->enclosingCompositingLayer()) {
+ if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) {
if (!compositingLayer->backing()->paintsIntoWindow()) {
frameView()->setCannotBlitToWindow();
break;