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/inspector/InspectorTraceEvents.h"
31 #include "core/rendering/compositing/CompositedLayerMapping.h"
32 #include "platform/TraceEvent.h"
36 // We will only allow squashing if the bbox-area:squashed-area doesn't exceed
37 // the ratio |gSquashingSparsityTolerance|:1.
38 static uint64_t gSquashingSparsityTolerance = 6;
40 CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
41 : m_compositor(compositor)
42 , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
43 , m_layersChanged(false)
47 CompositingLayerAssigner::~CompositingLayerAssigner()
51 void CompositingLayerAssigner::assign(RenderLayer* updateRoot, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
53 TRACE_EVENT0("blink", "CompositingLayerAssigner::assign");
55 SquashingState squashingState;
56 assignLayersToBackingsInternal(updateRoot, squashingState, layersNeedingPaintInvalidation);
57 if (squashingState.hasMostRecentMapping)
58 squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex);
61 void CompositingLayerAssigner::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMapping* newCompositedLayerMapping, bool hasNewCompositedLayerMapping)
63 // The most recent backing is done accumulating any more squashing layers.
64 if (hasMostRecentMapping)
65 mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex);
67 nextSquashedLayerIndex = 0;
68 boundingRect = IntRect();
69 mostRecentMapping = newCompositedLayerMapping;
70 hasMostRecentMapping = hasNewCompositedLayerMapping;
71 haveAssignedBackingsToEntireSquashingLayerSubtree = false;
74 bool CompositingLayerAssigner::squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const CompositingLayerAssigner::SquashingState& squashingState)
76 IntRect bounds = candidate->clippedAbsoluteBoundingBox();
77 IntRect newBoundingRect = squashingState.boundingRect;
78 newBoundingRect.unite(bounds);
79 const uint64_t newBoundingRectArea = newBoundingRect.size().area();
80 const uint64_t newSquashedArea = squashingState.totalAreaOfSquashedRects + bounds.size().area();
81 return newBoundingRectArea > gSquashingSparsityTolerance * newSquashedArea;
84 bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const
86 if (!m_compositor->canBeComposited(layer))
89 // If squashing is disabled, then layers that would have been squashed should just be separately composited.
90 bool needsOwnBackingForDisabledSquashing = !m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons());
92 return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer());
95 CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer)
97 CompositingStateTransitionType update = NoCompositingStateChange;
98 if (needsOwnBacking(layer)) {
99 if (!layer->hasCompositedLayerMapping()) {
100 update = AllocateOwnCompositedLayerMapping;
103 if (layer->hasCompositedLayerMapping())
104 update = RemoveOwnCompositedLayerMapping;
106 if (m_layerSquashingEnabled) {
107 if (!layer->subtreeIsInvisible() && requiresSquashing(layer->compositingReasons())) {
108 // We can't compute at this time whether the squashing layer update is a no-op,
109 // since that requires walking the render layer tree.
110 update = PutInSquashingLayer;
111 } else if (layer->groupedMapping() || layer->lostGroupedMapping()) {
112 update = RemoveFromSquashingLayer;
119 CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const RenderLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
121 if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
122 return CompositingReasonSquashingWouldBreakPaintOrder;
124 ASSERT(squashingState.hasMostRecentMapping);
125 const RenderLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer();
127 // FIXME: this special case for video exists only to deal with corner cases
128 // where a RenderVideo does not report that it needs to be directly composited.
129 // Video does not currently support sharing a backing, but this could be
130 // generalized in the future. The following layout tests fail if we permit the
131 // video to share a backing with other layers.
133 // compositing/video/video-controls-layer-creation.html
134 if (layer->renderer()->isVideo() || squashingLayer.renderer()->isVideo())
135 return CompositingReasonSquashingVideoIsDisallowed;
137 // Don't squash iframes, frames or plugins.
138 // FIXME: this is only necessary because there is frame code that assumes that composited frames are not squashed.
139 if (layer->renderer()->isRenderPart() || squashingLayer.renderer()->isRenderPart())
140 return CompositingReasonSquashingRenderPartIsDisallowed;
142 if (layer->reflectionInfo())
143 return CompositingReasonSquashingReflectionIsDisallowed;
145 if (squashingWouldExceedSparsityTolerance(layer, squashingState))
146 return CompositingReasonSquashingSparsityExceeded;
148 if (layer->renderer()->hasBlendMode())
149 return CompositingReasonSquashingBlendingIsDisallowed;
151 // FIXME: this is not efficient, since it walks up the tree. We should store these values on the CompositingInputsCache.
152 if (layer->clippingContainer() != squashingLayer.clippingContainer() && !squashingLayer.compositedLayerMapping()->containingSquashedLayer(layer->clippingContainer(), squashingState.nextSquashedLayerIndex))
153 return CompositingReasonSquashingClippingContainerMismatch;
155 // Composited descendants need to be clipped by a child containment graphics layer, which would not be available if the layer is
156 // squashed (and therefore has no CLM nor a child containment graphics layer).
157 if (m_compositor->clipsCompositingDescendants(layer))
158 return CompositingReasonSquashedLayerClipsCompositingDescendants;
160 if (layer->scrollsWithRespectTo(&squashingLayer))
161 return CompositingReasonScrollsWithRespectToSquashingLayer;
163 const RenderLayer::AncestorDependentCompositingInputs& compositingInputs = layer->ancestorDependentCompositingInputs();
164 const RenderLayer::AncestorDependentCompositingInputs& squashingLayerCompositingInputs = squashingLayer.ancestorDependentCompositingInputs();
166 if (compositingInputs.opacityAncestor != squashingLayerCompositingInputs.opacityAncestor)
167 return CompositingReasonSquashingOpacityAncestorMismatch;
169 if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor)
170 return CompositingReasonSquashingTransformAncestorMismatch;
172 if (layer->hasFilter() || compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
173 return CompositingReasonSquashingFilterMismatch;
175 return CompositingReasonNone;
178 void CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate,
179 Vector<RenderLayer*>& layersNeedingPaintInvalidation)
181 // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than
182 // the squashed RenderLayer's own primary contents. This would happen when we have a composited negative z-index element that needs
183 // to paint on top of the background, but below the layer's main contents. For now, because we always composite layers
184 // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue.
185 if (compositedLayerUpdate == PutInSquashingLayer) {
186 // A layer that is squashed with other layers cannot have its own CompositedLayerMapping.
187 ASSERT(!layer->hasCompositedLayerMapping());
188 ASSERT(squashingState.hasMostRecentMapping);
190 bool changedSquashingLayer =
191 squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex);
192 if (!changedSquashingLayer)
195 // If we've modified the collection of squashed layers, we must update
196 // the graphics layer geometry.
197 squashingState.mostRecentMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
199 layer->clipper().clearClipRectsIncludingDescendants();
201 // Issue a paint invalidation, since |layer| may have been added to an already-existing squashing layer.
202 TRACE_LAYER_INVALIDATION(layer, InspectorLayerInvalidationTrackingEvent::AddedToSquashingLayer);
203 layersNeedingPaintInvalidation.append(layer);
204 m_layersChanged = true;
205 } else if (compositedLayerUpdate == RemoveFromSquashingLayer) {
206 if (layer->groupedMapping()) {
207 // Before removing |layer| from an already-existing squashing layer that may have other content, issue a paint invalidation.
208 m_compositor->paintInvalidationOnCompositingChange(layer);
209 layer->groupedMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
210 layer->setGroupedMapping(0);
213 // If we need to issue paint invalidations, do so now that we've removed it from a squashed layer.
214 TRACE_LAYER_INVALIDATION(layer, InspectorLayerInvalidationTrackingEvent::RemovedFromSquashingLayer);
215 layersNeedingPaintInvalidation.append(layer);
216 m_layersChanged = true;
218 layer->setLostGroupedMapping(false);
222 void CompositingLayerAssigner::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
224 CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(reflectionLayer);
225 if (compositedLayerUpdate != NoCompositingStateChange) {
226 TRACE_LAYER_INVALIDATION(reflectionLayer, InspectorLayerInvalidationTrackingEvent::ReflectionLayerChanged);
227 layersNeedingPaintInvalidation.append(reflectionLayer);
228 m_layersChanged = true;
229 m_compositor->allocateOrClearCompositedLayerMapping(reflectionLayer, compositedLayerUpdate);
231 m_compositor->updateDirectCompositingReasons(reflectionLayer);
233 // FIXME: Why do we updateGraphicsLayerConfiguration here instead of in the GraphicsLayerUpdater?
234 if (reflectionLayer->hasCompositedLayerMapping())
235 reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration();
238 void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
240 if (m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons())) {
241 CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
242 if (reasonsPreventingSquashing)
243 layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing);
246 CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer);
248 if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) {
249 TRACE_LAYER_INVALIDATION(layer, InspectorLayerInvalidationTrackingEvent::NewCompositedLayer);
250 layersNeedingPaintInvalidation.append(layer);
251 m_layersChanged = true;
254 // FIXME: special-casing reflection layers here is not right.
255 if (layer->reflectionInfo())
256 assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersNeedingPaintInvalidation);
258 // Add this layer to a squashing backing if needed.
259 if (m_layerSquashingEnabled) {
260 updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingPaintInvalidation);
262 const bool layerIsSquashed = compositedLayerUpdate == PutInSquashingLayer || (compositedLayerUpdate == NoCompositingStateChange && layer->groupedMapping());
263 if (layerIsSquashed) {
264 squashingState.nextSquashedLayerIndex++;
265 IntRect layerBounds = layer->clippedAbsoluteBoundingBox();
266 squashingState.totalAreaOfSquashedRects += layerBounds.size().area();
267 squashingState.boundingRect.unite(layerBounds);
271 if (layer->stackingNode()->isStackingContext()) {
272 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
273 while (RenderLayerStackingNode* curNode = iterator.next())
274 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
277 if (m_layerSquashingEnabled) {
278 // At this point, if the layer is to be separately composited, then its backing becomes the most recent in paint-order.
279 if (layer->compositingState() == PaintsIntoOwnBacking) {
280 ASSERT(!requiresSquashing(layer->compositingReasons()));
281 squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping());
285 if (layer->scrollParent())
286 layer->scrollParent()->scrollableArea()->setTopmostScrollChild(layer);
288 if (layer->needsCompositedScrolling())
289 layer->scrollableArea()->setTopmostScrollChild(0);
291 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
292 while (RenderLayerStackingNode* curNode = iterator.next())
293 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
295 if (squashingState.hasMostRecentMapping && &squashingState.mostRecentMapping->owningLayer() == layer)
296 squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree = true;