1 /*
2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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.
25 */
26
27 #include "config.h"
28 #include "core/rendering/compositing/CompositingLayerAssigner.h"
29
30 #include "core/inspector/InspectorTraceEvents.h"
31 #include "core/rendering/compositing/CompositedLayerMapping.h"
32 #include "platform/TraceEvent.h"
33
34 namespace blink {
35
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;
39
CompositingLayerAssigner(RenderLayerCompositor * compositor)40 CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
41 : m_compositor(compositor)
42 , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
43 , m_layersChanged(false)
44 {
45 }
46
~CompositingLayerAssigner()47 CompositingLayerAssigner::~CompositingLayerAssigner()
48 {
49 }
50
assign(RenderLayer * updateRoot,Vector<RenderLayer * > & layersNeedingPaintInvalidation)51 void CompositingLayerAssigner::assign(RenderLayer* updateRoot, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
52 {
53 TRACE_EVENT0("blink", "CompositingLayerAssigner::assign");
54
55 SquashingState squashingState;
56 assignLayersToBackingsInternal(updateRoot, squashingState, layersNeedingPaintInvalidation);
57 if (squashingState.hasMostRecentMapping)
58 squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex);
59 }
60
updateSquashingStateForNewMapping(CompositedLayerMapping * newCompositedLayerMapping,bool hasNewCompositedLayerMapping)61 void CompositingLayerAssigner::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMapping* newCompositedLayerMapping, bool hasNewCompositedLayerMapping)
62 {
63 // The most recent backing is done accumulating any more squashing layers.
64 if (hasMostRecentMapping)
65 mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex);
66
67 nextSquashedLayerIndex = 0;
68 boundingRect = IntRect();
69 mostRecentMapping = newCompositedLayerMapping;
70 hasMostRecentMapping = hasNewCompositedLayerMapping;
71 haveAssignedBackingsToEntireSquashingLayerSubtree = false;
72 }
73
squashingWouldExceedSparsityTolerance(const RenderLayer * candidate,const CompositingLayerAssigner::SquashingState & squashingState)74 bool CompositingLayerAssigner::squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const CompositingLayerAssigner::SquashingState& squashingState)
75 {
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;
82 }
83
needsOwnBacking(const RenderLayer * layer) const84 bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const
85 {
86 if (!m_compositor->canBeComposited(layer))
87 return false;
88
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());
91
92 return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer());
93 }
94
computeCompositedLayerUpdate(RenderLayer * layer)95 CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer)
96 {
97 CompositingStateTransitionType update = NoCompositingStateChange;
98 if (needsOwnBacking(layer)) {
99 if (!layer->hasCompositedLayerMapping()) {
100 update = AllocateOwnCompositedLayerMapping;
101 }
102 } else {
103 if (layer->hasCompositedLayerMapping())
104 update = RemoveOwnCompositedLayerMapping;
105
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;
113 }
114 }
115 }
116 return update;
117 }
118
getReasonsPreventingSquashing(const RenderLayer * layer,const CompositingLayerAssigner::SquashingState & squashingState)119 CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const RenderLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
120 {
121 if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
122 return CompositingReasonSquashingWouldBreakPaintOrder;
123
124 ASSERT(squashingState.hasMostRecentMapping);
125 const RenderLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer();
126
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.
132 //
133 // compositing/video/video-controls-layer-creation.html
134 if (layer->renderer()->isVideo() || squashingLayer.renderer()->isVideo())
135 return CompositingReasonSquashingVideoIsDisallowed;
136
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;
141
142 if (layer->reflectionInfo())
143 return CompositingReasonSquashingReflectionIsDisallowed;
144
145 if (squashingWouldExceedSparsityTolerance(layer, squashingState))
146 return CompositingReasonSquashingSparsityExceeded;
147
148 if (layer->renderer()->hasBlendMode())
149 return CompositingReasonSquashingBlendingIsDisallowed;
150
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;
154
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;
159
160 if (layer->scrollsWithRespectTo(&squashingLayer))
161 return CompositingReasonScrollsWithRespectToSquashingLayer;
162
163 const RenderLayer::AncestorDependentCompositingInputs& compositingInputs = layer->ancestorDependentCompositingInputs();
164 const RenderLayer::AncestorDependentCompositingInputs& squashingLayerCompositingInputs = squashingLayer.ancestorDependentCompositingInputs();
165
166 if (compositingInputs.opacityAncestor != squashingLayerCompositingInputs.opacityAncestor)
167 return CompositingReasonSquashingOpacityAncestorMismatch;
168
169 if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor)
170 return CompositingReasonSquashingTransformAncestorMismatch;
171
172 if (layer->hasFilter() || compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
173 return CompositingReasonSquashingFilterMismatch;
174
175 return CompositingReasonNone;
176 }
177
updateSquashingAssignment(RenderLayer * layer,SquashingState & squashingState,const CompositingStateTransitionType compositedLayerUpdate,Vector<RenderLayer * > & layersNeedingPaintInvalidation)178 void CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate,
179 Vector<RenderLayer*>& layersNeedingPaintInvalidation)
180 {
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);
189
190 bool changedSquashingLayer =
191 squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex);
192 if (!changedSquashingLayer)
193 return;
194
195 // If we've modified the collection of squashed layers, we must update
196 // the graphics layer geometry.
197 squashingState.mostRecentMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
198
199 layer->clipper().clearClipRectsIncludingDescendants();
200
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);
211 }
212
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;
217
218 layer->setLostGroupedMapping(false);
219 }
220 }
221
assignLayersToBackingsForReflectionLayer(RenderLayer * reflectionLayer,Vector<RenderLayer * > & layersNeedingPaintInvalidation)222 void CompositingLayerAssigner::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
223 {
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);
230 }
231 m_compositor->updateDirectCompositingReasons(reflectionLayer);
232
233 // FIXME: Why do we updateGraphicsLayerConfiguration here instead of in the GraphicsLayerUpdater?
234 if (reflectionLayer->hasCompositedLayerMapping())
235 reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration();
236 }
237
assignLayersToBackingsInternal(RenderLayer * layer,SquashingState & squashingState,Vector<RenderLayer * > & layersNeedingPaintInvalidation)238 void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, Vector<RenderLayer*>& layersNeedingPaintInvalidation)
239 {
240 if (m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons())) {
241 CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
242 if (reasonsPreventingSquashing)
243 layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing);
244 }
245
246 CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer);
247
248 if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) {
249 TRACE_LAYER_INVALIDATION(layer, InspectorLayerInvalidationTrackingEvent::NewCompositedLayer);
250 layersNeedingPaintInvalidation.append(layer);
251 m_layersChanged = true;
252 }
253
254 // FIXME: special-casing reflection layers here is not right.
255 if (layer->reflectionInfo())
256 assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersNeedingPaintInvalidation);
257
258 // Add this layer to a squashing backing if needed.
259 if (m_layerSquashingEnabled) {
260 updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingPaintInvalidation);
261
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);
268 }
269 }
270
271 if (layer->stackingNode()->isStackingContext()) {
272 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
273 while (RenderLayerStackingNode* curNode = iterator.next())
274 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
275 }
276
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 || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) {
280 ASSERT(!requiresSquashing(layer->compositingReasons()));
281 squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping());
282 }
283 }
284
285 if (layer->scrollParent())
286 layer->scrollParent()->scrollableArea()->setTopmostScrollChild(layer);
287
288 if (layer->needsCompositedScrolling())
289 layer->scrollableArea()->setTopmostScrollChild(0);
290
291 RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
292 while (RenderLayerStackingNode* curNode = iterator.next())
293 assignLayersToBackingsInternal(curNode->layer(), squashingState, layersNeedingPaintInvalidation);
294
295 if (squashingState.hasMostRecentMapping && &squashingState.mostRecentMapping->owningLayer() == layer)
296 squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree = true;
297 }
298
299 }
300