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/CompositingRequirementsUpdater.h"
29
30#include "core/rendering/RenderLayerStackingNode.h"
31#include "core/rendering/RenderLayerStackingNodeIterator.h"
32#include "core/rendering/RenderView.h"
33#include "core/rendering/compositing/RenderLayerCompositor.h"
34#include "platform/TraceEvent.h"
35
36namespace blink {
37
38class OverlapMapContainer {
39public:
40    void add(const IntRect& bounds)
41    {
42        m_layerRects.append(bounds);
43        m_boundingBox.unite(bounds);
44    }
45
46    bool overlapsLayers(const IntRect& bounds) const
47    {
48        // Checking with the bounding box will quickly reject cases when
49        // layers are created for lists of items going in one direction and
50        // never overlap with each other.
51        if (!bounds.intersects(m_boundingBox))
52            return false;
53        for (unsigned i = 0; i < m_layerRects.size(); i++) {
54            if (m_layerRects[i].intersects(bounds))
55                return true;
56        }
57        return false;
58    }
59
60    void unite(const OverlapMapContainer& otherContainer)
61    {
62        m_layerRects.appendVector(otherContainer.m_layerRects);
63        m_boundingBox.unite(otherContainer.m_boundingBox);
64    }
65private:
66    Vector<IntRect, 64> m_layerRects;
67    IntRect m_boundingBox;
68};
69
70class CompositingRequirementsUpdater::OverlapMap {
71    WTF_MAKE_NONCOPYABLE(OverlapMap);
72public:
73    OverlapMap()
74    {
75        // Begin by assuming the root layer will be composited so that there
76        // is something on the stack. The root layer should also never get a
77        // finishCurrentOverlapTestingContext() call.
78        beginNewOverlapTestingContext();
79    }
80
81    void add(RenderLayer* layer, const IntRect& bounds)
82    {
83        ASSERT(!layer->isRootLayer());
84        if (bounds.isEmpty())
85            return;
86
87        // Layers do not contribute to overlap immediately--instead, they will
88        // contribute to overlap as soon as they have been recursively processed
89        // and popped off the stack.
90        ASSERT(m_overlapStack.size() >= 2);
91        m_overlapStack[m_overlapStack.size() - 2].add(bounds);
92    }
93
94    bool overlapsLayers(const IntRect& bounds) const
95    {
96        return m_overlapStack.last().overlapsLayers(bounds);
97    }
98
99    void beginNewOverlapTestingContext()
100    {
101        // This effectively creates a new "clean slate" for overlap state.
102        // This is used when we know that a subtree or remaining set of
103        // siblings does not need to check overlap with things behind it.
104        m_overlapStack.append(OverlapMapContainer());
105    }
106
107    void finishCurrentOverlapTestingContext()
108    {
109        // The overlap information on the top of the stack is still necessary
110        // for checking overlap of any layers outside this context that may
111        // overlap things from inside this context. Therefore, we must merge
112        // the information from the top of the stack before popping the stack.
113        //
114        // FIXME: we may be able to avoid this deep copy by rearranging how
115        //        overlapMap state is managed.
116        m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last());
117        m_overlapStack.removeLast();
118    }
119
120private:
121    Vector<OverlapMapContainer> m_overlapStack;
122};
123
124class CompositingRequirementsUpdater::RecursionData {
125public:
126    explicit RecursionData(RenderLayer* compositingAncestor)
127        : m_compositingAncestor(compositingAncestor)
128        , m_subtreeIsCompositing(false)
129        , m_hasUnisolatedCompositedBlendingDescendant(false)
130        , m_testingOverlap(true)
131    {
132    }
133
134    RenderLayer* m_compositingAncestor;
135    bool m_subtreeIsCompositing;
136    bool m_hasUnisolatedCompositedBlendingDescendant;
137    bool m_testingOverlap;
138};
139
140static bool requiresCompositingOrSquashing(CompositingReasons reasons)
141{
142#if ENABLE(ASSERT)
143    bool fastAnswer = reasons != CompositingReasonNone;
144    bool slowAnswer = requiresCompositing(reasons) || requiresSquashing(reasons);
145    ASSERT(fastAnswer == slowAnswer);
146#endif
147    return reasons != CompositingReasonNone;
148}
149
150static CompositingReasons subtreeReasonsForCompositing(RenderLayer* layer, bool hasCompositedDescendants, bool has3DTransformedDescendants)
151{
152    CompositingReasons subtreeReasons = CompositingReasonNone;
153
154    // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented
155    // via compositing so that they also apply to those composited descdendants.
156    if (hasCompositedDescendants) {
157        subtreeReasons |= layer->potentialCompositingReasonsFromStyle() & CompositingReasonComboCompositedDescendants;
158
159        if (layer->shouldIsolateCompositedDescendants()) {
160            ASSERT(layer->stackingNode()->isStackingContext());
161            subtreeReasons |= CompositingReasonIsolateCompositedDescendants;
162        }
163
164        // FIXME: This should move into CompositingReasonFinder::potentialCompositingReasonsFromStyle, but
165        // theres a poor interaction with RenderTextControlSingleLine, which sets this hasOverflowClip directly.
166        if (layer->renderer()->hasClipOrOverflowClip())
167            subtreeReasons |= CompositingReasonClipsCompositingDescendants;
168    }
169
170    // A layer with preserve-3d or perspective only needs to be composited if there are descendant layers that
171    // will be affected by the preserve-3d or perspective.
172    if (has3DTransformedDescendants)
173        subtreeReasons |= layer->potentialCompositingReasonsFromStyle() & CompositingReasonCombo3DDescendants;
174
175    return subtreeReasons;
176}
177
178CompositingRequirementsUpdater::CompositingRequirementsUpdater(RenderView& renderView, CompositingReasonFinder& compositingReasonFinder)
179    : m_renderView(renderView)
180    , m_compositingReasonFinder(compositingReasonFinder)
181{
182}
183
184CompositingRequirementsUpdater::~CompositingRequirementsUpdater()
185{
186}
187
188void CompositingRequirementsUpdater::update(RenderLayer* root)
189{
190    TRACE_EVENT0("blink", "CompositingRequirementsUpdater::updateRecursive");
191
192    // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
193    // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
194    RecursionData recursionData(root);
195    OverlapMap overlapTestRequestMap;
196    bool saw3DTransform = false;
197
198    // FIXME: Passing these unclippedDescendants down and keeping track
199    // of them dynamically, we are requiring a full tree walk. This
200    // should be removed as soon as proper overlap testing based on
201    // scrolling and animation bounds is implemented (crbug.com/252472).
202    Vector<RenderLayer*> unclippedDescendants;
203    IntRect absoluteDecendantBoundingBox;
204    updateRecursive(0, root, overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants, absoluteDecendantBoundingBox);
205}
206
207void CompositingRequirementsUpdater::updateRecursive(RenderLayer* ancestorLayer, RenderLayer* layer, OverlapMap& overlapMap, RecursionData& currentRecursionData, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants, IntRect& absoluteDecendantBoundingBox)
208{
209    RenderLayerCompositor* compositor = m_renderView.compositor();
210
211    layer->stackingNode()->updateLayerListsIfNeeded();
212
213    CompositingReasons reasonsToComposite = CompositingReasonNone;
214    CompositingReasons directReasons = m_compositingReasonFinder.directReasons(layer);
215
216    // Video is special. It's the only RenderLayer type that can both have
217    // RenderLayer children and whose children can't use its backing to render
218    // into. These children (the controls) always need to be promoted into their
219    // own layers to draw on top of the accelerated video.
220    if (currentRecursionData.m_compositingAncestor && currentRecursionData.m_compositingAncestor->renderer()->isVideo())
221        directReasons |= CompositingReasonVideoOverlay;
222
223    if (compositor->canBeComposited(layer))
224        reasonsToComposite |= directReasons;
225
226    // Next, accumulate reasons related to overlap.
227    // If overlap testing is used, this reason will be overridden. If overlap testing is not
228    // used, we must assume we overlap if there is anything composited behind us in paint-order.
229    CompositingReasons overlapCompositingReason = currentRecursionData.m_subtreeIsCompositing ? CompositingReasonAssumedOverlap : CompositingReasonNone;
230
231    if (m_renderView.compositor()->preferCompositingToLCDTextEnabled()) {
232        Vector<size_t> unclippedDescendantsToRemove;
233        for (size_t i = 0; i < unclippedDescendants.size(); i++) {
234            RenderLayer* unclippedDescendant = unclippedDescendants.at(i);
235            // If we've reached the containing block of one of the unclipped
236            // descendants, that element is no longer relevant to whether or not we
237            // should opt in. Unfortunately we can't easily remove from the list
238            // while we're iterating, so we have to store it for later removal.
239            if (unclippedDescendant->renderer()->containingBlock() == layer->renderer()) {
240                unclippedDescendantsToRemove.append(i);
241                continue;
242            }
243            if (layer->scrollsWithRespectTo(unclippedDescendant))
244                reasonsToComposite |= CompositingReasonAssumedOverlap;
245        }
246
247        // Remove irrelevant unclipped descendants in reverse order so our stored
248        // indices remain valid.
249        for (size_t i = 0; i < unclippedDescendantsToRemove.size(); i++)
250            unclippedDescendants.remove(unclippedDescendantsToRemove.at(unclippedDescendantsToRemove.size() - i - 1));
251
252        if (reasonsToComposite & CompositingReasonOutOfFlowClipping)
253            unclippedDescendants.append(layer);
254    }
255
256    const IntRect& absBounds = layer->clippedAbsoluteBoundingBox();
257    absoluteDecendantBoundingBox = absBounds;
258
259    if (currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons))
260        overlapCompositingReason = overlapMap.overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone;
261
262    reasonsToComposite |= overlapCompositingReason;
263
264    // The children of this layer don't need to composite, unless there is
265    // a compositing layer among them, so start by inheriting the compositing
266    // ancestor with m_subtreeIsCompositing set to false.
267    RecursionData childRecursionData = currentRecursionData;
268    childRecursionData.m_subtreeIsCompositing = false;
269
270    bool willBeCompositedOrSquashed = compositor->canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite);
271    if (willBeCompositedOrSquashed) {
272        // Tell the parent it has compositing descendants.
273        currentRecursionData.m_subtreeIsCompositing = true;
274        // This layer now acts as the ancestor for kids.
275        childRecursionData.m_compositingAncestor = layer;
276
277        // Here we know that all children and the layer's own contents can blindly paint into
278        // this layer's backing, until a descendant is composited. So, we don't need to check
279        // for overlap with anything behind this layer.
280        overlapMap.beginNewOverlapTestingContext();
281        // This layer is going to be composited, so children can safely ignore the fact that there's an
282        // animation running behind this layer, meaning they can rely on the overlap map testing again.
283        childRecursionData.m_testingOverlap = true;
284    }
285
286#if ENABLE(ASSERT)
287    LayerListMutationDetector mutationChecker(layer->stackingNode());
288#endif
289
290    bool anyDescendantHas3DTransform = false;
291    bool willHaveForegroundLayer = false;
292
293    if (layer->stackingNode()->isStackingContext()) {
294        RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
295        while (RenderLayerStackingNode* curNode = iterator.next()) {
296            IntRect absoluteChildDecendantBoundingBox;
297            updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox);
298            absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox);
299
300            // If we have to make a layer for this child, make one now so we can have a contents layer
301            // (since we need to ensure that the -ve z-order child renders underneath our contents).
302            if (childRecursionData.m_subtreeIsCompositing) {
303                reasonsToComposite |= CompositingReasonNegativeZIndexChildren;
304
305                if (!willBeCompositedOrSquashed) {
306                    // make layer compositing
307                    childRecursionData.m_compositingAncestor = layer;
308                    overlapMap.beginNewOverlapTestingContext();
309                    willBeCompositedOrSquashed = true;
310                    willHaveForegroundLayer = true;
311
312                    // FIXME: temporary solution for the first negative z-index composited child:
313                    //        re-compute the absBounds for the child so that we can add the
314                    //        negative z-index child's bounds to the new overlap context.
315                    overlapMap.beginNewOverlapTestingContext();
316                    overlapMap.add(curNode->layer(), curNode->layer()->clippedAbsoluteBoundingBox());
317                    overlapMap.finishCurrentOverlapTestingContext();
318                }
319            }
320        }
321    }
322
323    if (willHaveForegroundLayer) {
324        ASSERT(willBeCompositedOrSquashed);
325        // A foreground layer effectively is a new backing for all subsequent children, so
326        // we don't need to test for overlap with anything behind this. So, we can finish
327        // the previous context that was accumulating rects for the negative z-index
328        // children, and start with a fresh new empty context.
329        overlapMap.finishCurrentOverlapTestingContext();
330        overlapMap.beginNewOverlapTestingContext();
331        // This layer is going to be composited, so children can safely ignore the fact that there's an
332        // animation running behind this layer, meaning they can rely on the overlap map testing again
333        childRecursionData.m_testingOverlap = true;
334    }
335
336    RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
337    while (RenderLayerStackingNode* curNode = iterator.next()) {
338        IntRect absoluteChildDecendantBoundingBox;
339        updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox);
340        absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox);
341    }
342
343    // Now that the subtree has been traversed, we can check for compositing reasons that depended on the state of the subtree.
344
345    if (layer->stackingNode()->isStackingContext()) {
346        layer->setShouldIsolateCompositedDescendants(childRecursionData.m_hasUnisolatedCompositedBlendingDescendant);
347    } else {
348        layer->setShouldIsolateCompositedDescendants(false);
349        currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = childRecursionData.m_hasUnisolatedCompositedBlendingDescendant;
350    }
351
352    // Subsequent layers in the parent's stacking context may also need to composite.
353    if (childRecursionData.m_subtreeIsCompositing)
354        currentRecursionData.m_subtreeIsCompositing = true;
355
356    // Set the flag to say that this SC has compositing children.
357    layer->setHasCompositingDescendant(childRecursionData.m_subtreeIsCompositing);
358
359    if (layer->isRootLayer()) {
360        // The root layer needs to be composited if anything else in the tree is composited.
361        // Otherwise, we can disable compositing entirely.
362        if (childRecursionData.m_subtreeIsCompositing || requiresCompositingOrSquashing(reasonsToComposite) || compositor->rootShouldAlwaysComposite()) {
363            reasonsToComposite |= CompositingReasonRoot;
364        } else {
365            compositor->setCompositingModeEnabled(false);
366            reasonsToComposite = CompositingReasonNone;
367        }
368    } else {
369        // All layers (even ones that aren't being composited) need to get added to
370        // the overlap map. Layers that are not separately composited will paint into their
371        // compositing ancestor's backing, and so are still considered for overlap.
372        if (childRecursionData.m_compositingAncestor && !childRecursionData.m_compositingAncestor->isRootLayer())
373            overlapMap.add(layer, absBounds);
374
375        // Now check for reasons to become composited that depend on the state of descendant layers.
376        CompositingReasons subtreeCompositingReasons = subtreeReasonsForCompositing(layer, childRecursionData.m_subtreeIsCompositing, anyDescendantHas3DTransform);
377        reasonsToComposite |= subtreeCompositingReasons;
378        if (!willBeCompositedOrSquashed && compositor->canBeComposited(layer) && requiresCompositingOrSquashing(subtreeCompositingReasons)) {
379            childRecursionData.m_compositingAncestor = layer;
380            // FIXME: this context push is effectively a no-op but needs to exist for
381            // now, because the code is designed to push overlap information to the
382            // second-from-top context of the stack.
383            overlapMap.beginNewOverlapTestingContext();
384            overlapMap.add(layer, absoluteDecendantBoundingBox);
385            willBeCompositedOrSquashed = true;
386        }
387
388        if (willBeCompositedOrSquashed)
389            reasonsToComposite |= layer->potentialCompositingReasonsFromStyle() & CompositingReasonInlineTransform;
390
391        // If the original layer is composited, the reflection needs to be, too.
392        if (layer->reflectionInfo()) {
393            // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer?
394            RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer();
395            CompositingReasons reflectionCompositingReason = willBeCompositedOrSquashed ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone;
396            reflectionLayer->setCompositingReasons(reflectionCompositingReason, CompositingReasonReflectionOfCompositedParent);
397        }
398
399        if (willBeCompositedOrSquashed && layer->renderer()->hasBlendMode())
400            currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = true;
401
402        // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
403        // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
404        // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
405        bool isCompositedClippingLayer = compositor->canBeComposited(layer) && (reasonsToComposite & CompositingReasonClipsCompositingDescendants);
406        bool isCompositedWithInlineTransform = reasonsToComposite & CompositingReasonInlineTransform;
407        if ((!childRecursionData.m_testingOverlap && !isCompositedClippingLayer) || layer->renderer()->style()->hasCurrentTransformAnimation() || isCompositedWithInlineTransform)
408            currentRecursionData.m_testingOverlap = false;
409
410        if (childRecursionData.m_compositingAncestor == layer)
411            overlapMap.finishCurrentOverlapTestingContext();
412
413        descendantHas3DTransform |= anyDescendantHas3DTransform || layer->has3DTransform();
414    }
415
416    // At this point we have finished collecting all reasons to composite this layer.
417    layer->setCompositingReasons(reasonsToComposite);
418
419}
420
421} // namespace blink
422