2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "core/rendering/compositing/CompositingLayerAssigner.h"
30 #include "core/rendering/compositing/CompositedLayerMapping.h"
31 #include "platform/TraceEvent.h"
35 // We will only allow squashing if the bbox-area:squashed-area doesn't exceed
36 // the ratio |gSquashingSparsityTolerance|:1.
37 static uint64_t gSquashingSparsityTolerance = 6;
39 CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
40 : m_compositor(compositor)
41 , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
42 , m_layersChanged(false)
46 CompositingLayerAssigner::~CompositingLayerAssigner()
50 void CompositingLayerAssigner::assign(RenderLayer* updateRoot, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
52 TRACE_EVENT0("blink", "CompositingLayerAssigner::assign");
54 SquashingState squashingState;
55 assignLayersToBackingsInternal(updateRoot, squashingState, layersNeedingPaintInvalidation);
56 if (squashingState.hasMostRecentMapping)
57 squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex);
60 void CompositingLayerAssigner::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMapping* newCompositedLayerMapping, bool hasNewCompositedLayerMapping)
62 // The most recent backing is done accumulating any more squashing layers.
63 if (hasMostRecentMapping)
64 mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex);
66 nextSquashedLayerIndex = 0;
67 boundingRect = IntRect();
68 mostRecentMapping = newCompositedLayerMapping;
69 hasMostRecentMapping = hasNewCompositedLayerMapping;
70 haveAssignedBackingsToEntireSquashingLayerSubtree = false;
73 bool CompositingLayerAssigner::squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const CompositingLayerAssigner::SquashingState& squashingState)
75 IntRect bounds = candidate->clippedAbsoluteBoundingBox();
76 IntRect newBoundingRect = squashingState.boundingRect;
77 newBoundingRect.unite(bounds);
78 const uint64_t newBoundingRectArea = newBoundingRect.size().area();
79 const uint64_t newSquashedArea = squashingState.totalAreaOfSquashedRects + bounds.size().area();
80 return newBoundingRectArea > gSquashingSparsityTolerance * newSquashedArea;
83 bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const
85 if (!m_compositor->canBeComposited(layer))
88 // If squashing is disabled, then layers that would have been squashed should just be separately composited.
89 bool needsOwnBackingForDisabledSquashing = !m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons());
91 return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer());
94 CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer)
96 CompositingStateTransitionType update = NoCompositingStateChange;
97 if (needsOwnBacking(layer)) {
98 if (!layer->hasCompositedLayerMapping()) {
99 update = AllocateOwnCompositedLayerMapping;
102 if (layer->hasCompositedLayerMapping())
103 update = RemoveOwnCompositedLayerMapping;
105 if (m_layerSquashingEnabled) {
106 if (!layer->subtreeIsInvisible() && requiresSquashing(layer->compositingReasons())) {
107 // We can't compute at this time whether the squashing layer update is a no-op,
108 // since that requires walking the render layer tree.
109 update = PutInSquashingLayer;
110 } else if (layer->groupedMapping() || layer->lostGroupedMapping()) {
111 update = RemoveFromSquashingLayer;
118 CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const RenderLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
120 if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
121 return CompositingReasonSquashingWouldBreakPaintOrder;
123 // FIXME: this special case for video exists only to deal with corner cases
124 // where a RenderVideo does not report that it needs to be directly composited.
125 // Video does not currently support sharing a backing, but this could be
126 // generalized in the future. The following layout tests fail if we permit the
127 // video to share a backing with other layers.
129 // compositing/video/video-controls-layer-creation.html
130 // virtual/softwarecompositing/video/video-controls-layer-creation.html
131 if (layer->renderer()->isVideo())
132 return CompositingReasonSquashingVideoIsDisallowed;
134 // Don't squash iframes, frames or plugins.
135 // FIXME: this is only necessary because there is frame code that assumes that composited frames are not squashed.
136 if (layer->renderer()->isRenderPart())
137 return CompositingReasonSquashingRenderPartIsDisallowed;
139 if (layer->reflectionInfo())
140 return CompositingReasonSquashingReflectionIsDisallowed;
142 if (squashingWouldExceedSparsityTolerance(layer, squashingState))
143 return CompositingReasonSquashingSparsityExceeded;
145 // FIXME: this is not efficient, since it walks up the tree . We should store these values on the CompositingInputsCache.
146 ASSERT(squashingState.hasMostRecentMapping);
147 const RenderLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer();
149 if (layer->clippingContainer() != squashingLayer.clippingContainer() && !squashingLayer.compositedLayerMapping()->containingSquashedLayer(layer->clippingContainer()))
150 return CompositingReasonSquashingClippingContainerMismatch;
152 // Composited descendants need to be clipped by a child containment graphics layer, which would not be available if the layer is
153 // squashed (and therefore has no CLM nor a child containment graphics layer).
154 if (m_compositor->clipsCompositingDescendants(layer))
155 return CompositingReasonSquashedLayerClipsCompositingDescendants;
157 if (layer->scrollsWithRespectTo(&squashingLayer))
158 return CompositingReasonScrollsWithRespectToSquashingLayer;
160 const RenderLayer::AncestorDependentCompositingInputs& compositingInputs = layer->ancestorDependentCompositingInputs();
161 const RenderLayer::AncestorDependentCompositingInputs& squashingLayerCompositingInputs = squashingLayer.ancestorDependentCompositingInputs();
163 if (compositingInputs.opacityAncestor != squashingLayerCompositingInputs.opacityAncestor)
164 return CompositingReasonSquashingOpacityAncestorMismatch;
166 if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor)
167 return CompositingReasonSquashingTransformAncestorMismatch;
169 if (compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
170 return CompositingReasonSquashingFilterAncestorMismatch;
172 return CompositingReasonNone;
175 void CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate,
176 Vector<RenderLayer*>& layersNeedingPaintInvalidation)
178 // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than
179 // the squashed RenderLayer's own primary contents. This would happen when we have a composited negative z-index element that needs
180 // to paint on top of the background, but below the layer's main contents. For now, because we always composite layers
181 // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue.
182 if (compositedLayerUpdate == PutInSquashingLayer) {
183 // A layer that is squashed with other layers cannot have its own CompositedLayerMapping.
184 ASSERT(!layer->hasCompositedLayerMapping());
185 ASSERT(squashingState.hasMostRecentMapping);
187 bool changedSquashingLayer =
188 squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex);
189 if (!changedSquashingLayer)
192 // If we've modified the collection of squashed layers, we must update
193 // the graphics layer geometry.
194 squashingState.mostRecentMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
196 layer->clipper().clearClipRectsIncludingDescendants();
198 // Issue a paint invalidation, since |layer| may have been added to an already-existing squashing layer.
199 layersNeedingPaintInvalidation.append(layer);
200 m_layersChanged = true;
201 } else if (compositedLayerUpdate == RemoveFromSquashingLayer) {
202 if (layer->groupedMapping()) {
203 // Before removing |layer| from an already-existing squashing layer that may have other content, issue a paint invalidation.
204 m_compositor->paintInvalidationOnCompositingChange(layer);
205 layer->groupedMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
206 layer->setGroupedMapping(0);
209 // If we need to issue paint invalidations, do so now that we've removed it from a squashed layer.
210 layersNeedingPaintInvalidation.append(layer);
211 m_layersChanged = true;
213 layer->setLostGroupedMapping(false);
217 void CompositingLayerAssigner::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
219 CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(reflectionLayer);
220 if (compositedLayerUpdate != NoCompositingStateChange) {
221 layersNeedingPaintInvalidation.append(reflectionLayer);
222 m_layersChanged = true;
223 m_compositor->allocateOrClearCompositedLayerMapping(reflectionLayer, compositedLayerUpdate);
225 m_compositor->updateDirectCompositingReasons(reflectionLayer);
227 // FIXME: Why do we updateGraphicsLayerConfiguration here instead of in the GraphicsLayerUpdater?
228 if (reflectionLayer->hasCompositedLayerMapping())
229 reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration();
232 void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
234 if (m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons())) {
235 CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
236 if (reasonsPreventingSquashing)
237 layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing);
240 CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer);
242 if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) {
243 layersNeedingPaintInvalidation.append(layer);
244 m_layersChanged = true;
247 // FIXME: special-casing reflection layers here is not right.
248 if (layer->reflectionInfo())
249 assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersNeedingPaintInvalidation);
251 // Add this layer to a squashing backing if needed.
252 if (m_layerSquashingEnabled) {
253 updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingPaintInvalidation);
255 const bool layerIsSquashed = compositedLayerUpdate == PutInSquashingLayer || (compositedLayerUpdate == NoCompositingStateChange && layer->groupedMapping());
256 if (layerIsSquashed) {
257 squashingState.nextSquashedLayerIndex++;
258 IntRect layerBounds = layer->clippedAbsoluteBoundingBox();
259 squashingState.totalAreaOfSquashedRects += layerBounds.size().area();
260 squashingState.boundingRect.unite(layerBounds);
264 if (layer->stackingNode()->isStackingContext()) {
265 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
266 while (RenderLayerStackingNode* curNode = iterator.next())
267 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
270 if (m_layerSquashingEnabled) {
271 // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order.
272 if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) {
273 ASSERT(!requiresSquashing(layer->compositingReasons()));
274 squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping());
278 if (layer->scrollParent())
279 layer->scrollParent()->scrollableArea()->setTopmostScrollChild(layer);
281 if (layer->needsCompositedScrolling())
282 layer->scrollableArea()->setTopmostScrollChild(0);
284 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
285 while (RenderLayerStackingNode* curNode = iterator.next())
286 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
288 if (squashingState.hasMostRecentMapping && &squashingState.mostRecentMapping->owningLayer() == layer)
289 squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree = true;