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
34namespace blink {
35
36// We will only allow squashing if the bbox-area:squashed-area doesn't exceed
37// the ratio |gSquashingSparsityTolerance|:1.
38static uint64_t gSquashingSparsityTolerance = 6;
39
40CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
41    : m_compositor(compositor)
42    , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
43    , m_layersChanged(false)
44{
45}
46
47CompositingLayerAssigner::~CompositingLayerAssigner()
48{
49}
50
51void 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
61void 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
74bool 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
84bool 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
95CompositingStateTransitionType 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
119CompositingReasons 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
178void 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
222void 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
238void 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