Home | History | Annotate | Download | only in compositing
      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 
     36 namespace WebCore {
     37 
     38 class OverlapMapContainer {
     39 public:
     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     }
     65 private:
     66     Vector<IntRect, 64> m_layerRects;
     67     IntRect m_boundingBox;
     68 };
     69 
     70 class CompositingRequirementsUpdater::OverlapMap {
     71     WTF_MAKE_NONCOPYABLE(OverlapMap);
     72 public:
     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 
    120 private:
    121     Vector<OverlapMapContainer> m_overlapStack;
    122 };
    123 
    124 class CompositingRequirementsUpdater::RecursionData {
    125 public:
    126     RecursionData(RenderLayer* compAncestor, bool testOverlap)
    127         : m_compositingAncestor(compAncestor)
    128         , m_subtreeIsCompositing(false)
    129         , m_hasUnisolatedCompositedBlendingDescendant(false)
    130         , m_testingOverlap(testOverlap)
    131 #ifndef NDEBUG
    132         , m_depth(0)
    133 #endif
    134     {
    135     }
    136 
    137     RecursionData(const RecursionData& other)
    138         : m_compositingAncestor(other.m_compositingAncestor)
    139         , m_subtreeIsCompositing(other.m_subtreeIsCompositing)
    140         , m_hasUnisolatedCompositedBlendingDescendant(other.m_hasUnisolatedCompositedBlendingDescendant)
    141         , m_testingOverlap(other.m_testingOverlap)
    142 #ifndef NDEBUG
    143         , m_depth(other.m_depth + 1)
    144 #endif
    145     {
    146     }
    147 
    148     RenderLayer* m_compositingAncestor;
    149     bool m_subtreeIsCompositing;
    150     bool m_hasUnisolatedCompositedBlendingDescendant;
    151     bool m_testingOverlap;
    152 #ifndef NDEBUG
    153     int m_depth;
    154 #endif
    155 };
    156 
    157 static bool requiresCompositingOrSquashing(CompositingReasons reasons)
    158 {
    159 #ifndef NDEBUG
    160     bool fastAnswer = reasons != CompositingReasonNone;
    161     bool slowAnswer = requiresCompositing(reasons) || requiresSquashing(reasons);
    162     ASSERT(fastAnswer == slowAnswer);
    163 #endif
    164     return reasons != CompositingReasonNone;
    165 }
    166 
    167 static CompositingReasons subtreeReasonsForCompositing(RenderObject* renderer, bool hasCompositedDescendants, bool has3DTransformedDescendants)
    168 {
    169     CompositingReasons subtreeReasons = CompositingReasonNone;
    170 
    171     // FIXME: this seems to be a potentially different layer than the layer for which this was called. May not be an error, but is very confusing.
    172     RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    173 
    174     // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented
    175     // via compositing so that they also apply to those composited descdendants.
    176     if (hasCompositedDescendants) {
    177         if (layer->transform())
    178             subtreeReasons |= CompositingReasonTransformWithCompositedDescendants;
    179 
    180         if (layer->shouldIsolateCompositedDescendants()) {
    181             ASSERT(layer->stackingNode()->isStackingContext());
    182             subtreeReasons |= CompositingReasonIsolateCompositedDescendants;
    183         }
    184 
    185         // If the implementation of createsGroup changes, we need to be aware of that in this part of code.
    186         ASSERT((renderer->isTransparent() || renderer->hasMask() || renderer->hasFilter() || renderer->hasBlendMode()) == renderer->createsGroup());
    187         if (renderer->isTransparent())
    188             subtreeReasons |= CompositingReasonOpacityWithCompositedDescendants;
    189         if (renderer->hasMask())
    190             subtreeReasons |= CompositingReasonMaskWithCompositedDescendants;
    191         if (renderer->hasFilter())
    192             subtreeReasons |= CompositingReasonFilterWithCompositedDescendants;
    193         if (renderer->hasBlendMode())
    194             subtreeReasons |= CompositingReasonBlendingWithCompositedDescendants;
    195 
    196         if (renderer->hasReflection())
    197             subtreeReasons |= CompositingReasonReflectionWithCompositedDescendants;
    198 
    199         if (renderer->hasClipOrOverflowClip())
    200             subtreeReasons |= CompositingReasonClipsCompositingDescendants;
    201     }
    202 
    203     // A layer with preserve-3d or perspective only needs to be composited if there are descendant layers that
    204     // will be affected by the preserve-3d or perspective.
    205     if (has3DTransformedDescendants) {
    206         if (renderer->style()->transformStyle3D() == TransformStyle3DPreserve3D)
    207             subtreeReasons |= CompositingReasonPreserve3DWith3DDescendants;
    208 
    209         if (renderer->style()->hasPerspective())
    210             subtreeReasons |= CompositingReasonPerspectiveWith3DDescendants;
    211     }
    212 
    213     return subtreeReasons;
    214 }
    215 
    216 CompositingRequirementsUpdater::CompositingRequirementsUpdater(RenderView& renderView, CompositingReasonFinder& compositingReasonFinder)
    217     : m_renderView(renderView)
    218     , m_compositingReasonFinder(compositingReasonFinder)
    219 {
    220 }
    221 
    222 CompositingRequirementsUpdater::~CompositingRequirementsUpdater()
    223 {
    224 }
    225 
    226 void CompositingRequirementsUpdater::update(RenderLayer* root)
    227 {
    228     TRACE_EVENT0("blink_rendering", "CompositingRequirementsUpdater::updateRecursive");
    229 
    230     // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers.
    231     // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex.
    232     RecursionData recursionData(root, true);
    233     OverlapMap overlapTestRequestMap;
    234     bool saw3DTransform = false;
    235 
    236     // FIXME: Passing these unclippedDescendants down and keeping track
    237     // of them dynamically, we are requiring a full tree walk. This
    238     // should be removed as soon as proper overlap testing based on
    239     // scrolling and animation bounds is implemented (crbug.com/252472).
    240     Vector<RenderLayer*> unclippedDescendants;
    241     IntRect absoluteDecendantBoundingBox;
    242     updateRecursive(0, root, overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants, absoluteDecendantBoundingBox);
    243 }
    244 
    245 void CompositingRequirementsUpdater::updateRecursive(RenderLayer* ancestorLayer, RenderLayer* layer, OverlapMap& overlapMap, RecursionData& currentRecursionData, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants, IntRect& absoluteDecendantBoundingBox)
    246 {
    247     RenderLayerCompositor* compositor = m_renderView.compositor();
    248 
    249     layer->stackingNode()->updateLayerListsIfNeeded();
    250 
    251     CompositingReasons reasonsToComposite = CompositingReasonNone;
    252     CompositingReasons directReasons = m_compositingReasonFinder.directReasons(layer);
    253 
    254     // Video is special. It's the only RenderLayer type that can both have
    255     // RenderLayer children and whose children can't use its backing to render
    256     // into. These children (the controls) always need to be promoted into their
    257     // own layers to draw on top of the accelerated video.
    258     if (currentRecursionData.m_compositingAncestor && currentRecursionData.m_compositingAncestor->renderer()->isVideo())
    259         directReasons |= CompositingReasonVideoOverlay;
    260 
    261     if (compositor->canBeComposited(layer))
    262         reasonsToComposite |= directReasons;
    263 
    264     // Next, accumulate reasons related to overlap.
    265     // If overlap testing is used, this reason will be overridden. If overlap testing is not
    266     // used, we must assume we overlap if there is anything composited behind us in paint-order.
    267     CompositingReasons overlapCompositingReason = currentRecursionData.m_subtreeIsCompositing ? CompositingReasonAssumedOverlap : CompositingReasonNone;
    268 
    269     if (m_renderView.compositor()->acceleratedCompositingForOverflowScrollEnabled()) {
    270         Vector<size_t> unclippedDescendantsToRemove;
    271         for (size_t i = 0; i < unclippedDescendants.size(); i++) {
    272             RenderLayer* unclippedDescendant = unclippedDescendants.at(i);
    273             // If we've reached the containing block of one of the unclipped
    274             // descendants, that element is no longer relevant to whether or not we
    275             // should opt in. Unfortunately we can't easily remove from the list
    276             // while we're iterating, so we have to store it for later removal.
    277             if (unclippedDescendant->renderer()->containingBlock() == layer->renderer()) {
    278                 unclippedDescendantsToRemove.append(i);
    279                 continue;
    280             }
    281             if (layer->scrollsWithRespectTo(unclippedDescendant))
    282                 reasonsToComposite |= CompositingReasonAssumedOverlap;
    283         }
    284 
    285         // Remove irrelevant unclipped descendants in reverse order so our stored
    286         // indices remain valid.
    287         for (size_t i = 0; i < unclippedDescendantsToRemove.size(); i++)
    288             unclippedDescendants.remove(unclippedDescendantsToRemove.at(unclippedDescendantsToRemove.size() - i - 1));
    289 
    290         if (reasonsToComposite & CompositingReasonOutOfFlowClipping)
    291             unclippedDescendants.append(layer);
    292     }
    293 
    294     const IntRect& absBounds = layer->compositingInputs().clippedAbsoluteBoundingBox;
    295     absoluteDecendantBoundingBox = absBounds;
    296 
    297     if (currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons))
    298         overlapCompositingReason = overlapMap.overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone;
    299 
    300     reasonsToComposite |= overlapCompositingReason;
    301 
    302     // The children of this layer don't need to composite, unless there is
    303     // a compositing layer among them, so start by inheriting the compositing
    304     // ancestor with m_subtreeIsCompositing set to false.
    305     RecursionData childRecursionData(currentRecursionData);
    306     childRecursionData.m_subtreeIsCompositing = false;
    307 
    308     bool willBeCompositedOrSquashed = compositor->canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite);
    309     if (willBeCompositedOrSquashed) {
    310         // Tell the parent it has compositing descendants.
    311         currentRecursionData.m_subtreeIsCompositing = true;
    312         // This layer now acts as the ancestor for kids.
    313         childRecursionData.m_compositingAncestor = layer;
    314 
    315         // Here we know that all children and the layer's own contents can blindly paint into
    316         // this layer's backing, until a descendant is composited. So, we don't need to check
    317         // for overlap with anything behind this layer.
    318         overlapMap.beginNewOverlapTestingContext();
    319         // This layer is going to be composited, so children can safely ignore the fact that there's an
    320         // animation running behind this layer, meaning they can rely on the overlap map testing again.
    321         childRecursionData.m_testingOverlap = true;
    322     }
    323 
    324 #if ASSERT_ENABLED
    325     LayerListMutationDetector mutationChecker(layer->stackingNode());
    326 #endif
    327 
    328     bool anyDescendantHas3DTransform = false;
    329     bool willHaveForegroundLayer = false;
    330 
    331     if (layer->stackingNode()->isStackingContext()) {
    332         RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
    333         while (RenderLayerStackingNode* curNode = iterator.next()) {
    334             IntRect absoluteChildDecendantBoundingBox;
    335             updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox);
    336             absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox);
    337 
    338             // If we have to make a layer for this child, make one now so we can have a contents layer
    339             // (since we need to ensure that the -ve z-order child renders underneath our contents).
    340             if (childRecursionData.m_subtreeIsCompositing) {
    341                 reasonsToComposite |= CompositingReasonNegativeZIndexChildren;
    342 
    343                 if (!willBeCompositedOrSquashed) {
    344                     // make layer compositing
    345                     childRecursionData.m_compositingAncestor = layer;
    346                     overlapMap.beginNewOverlapTestingContext();
    347                     willBeCompositedOrSquashed = true;
    348                     willHaveForegroundLayer = true;
    349 
    350                     // FIXME: temporary solution for the first negative z-index composited child:
    351                     //        re-compute the absBounds for the child so that we can add the
    352                     //        negative z-index child's bounds to the new overlap context.
    353                     overlapMap.beginNewOverlapTestingContext();
    354                     overlapMap.add(curNode->layer(), curNode->layer()->compositingInputs().clippedAbsoluteBoundingBox);
    355                     overlapMap.finishCurrentOverlapTestingContext();
    356                 }
    357             }
    358         }
    359     }
    360 
    361     if (willHaveForegroundLayer) {
    362         ASSERT(willBeCompositedOrSquashed);
    363         // A foreground layer effectively is a new backing for all subsequent children, so
    364         // we don't need to test for overlap with anything behind this. So, we can finish
    365         // the previous context that was accumulating rects for the negative z-index
    366         // children, and start with a fresh new empty context.
    367         overlapMap.finishCurrentOverlapTestingContext();
    368         overlapMap.beginNewOverlapTestingContext();
    369         // This layer is going to be composited, so children can safely ignore the fact that there's an
    370         // animation running behind this layer, meaning they can rely on the overlap map testing again
    371         childRecursionData.m_testingOverlap = true;
    372     }
    373 
    374     RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
    375     while (RenderLayerStackingNode* curNode = iterator.next()) {
    376         IntRect absoluteChildDecendantBoundingBox;
    377         updateRecursive(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox);
    378         absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox);
    379     }
    380 
    381     // Now that the subtree has been traversed, we can check for compositing reasons that depended on the state of the subtree.
    382 
    383     if (layer->stackingNode()->isStackingContext()) {
    384         layer->setShouldIsolateCompositedDescendants(childRecursionData.m_hasUnisolatedCompositedBlendingDescendant);
    385     } else {
    386         layer->setShouldIsolateCompositedDescendants(false);
    387         currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = childRecursionData.m_hasUnisolatedCompositedBlendingDescendant;
    388     }
    389 
    390     // Subsequent layers in the parent's stacking context may also need to composite.
    391     if (childRecursionData.m_subtreeIsCompositing)
    392         currentRecursionData.m_subtreeIsCompositing = true;
    393 
    394     // Set the flag to say that this SC has compositing children.
    395     layer->setHasCompositingDescendant(childRecursionData.m_subtreeIsCompositing);
    396 
    397     if (layer->isRootLayer()) {
    398         // The root layer needs to be composited if anything else in the tree is composited.
    399         // Otherwise, we can disable compositing entirely.
    400         if (childRecursionData.m_subtreeIsCompositing || requiresCompositingOrSquashing(reasonsToComposite) || compositor->rootShouldAlwaysComposite()) {
    401             reasonsToComposite |= CompositingReasonRoot;
    402         } else {
    403             compositor->setCompositingModeEnabled(false);
    404             reasonsToComposite = CompositingReasonNone;
    405         }
    406     } else {
    407         // All layers (even ones that aren't being composited) need to get added to
    408         // the overlap map. Layers that are not separately composited will paint into their
    409         // compositing ancestor's backing, and so are still considered for overlap.
    410         if (childRecursionData.m_compositingAncestor && !childRecursionData.m_compositingAncestor->isRootLayer())
    411             overlapMap.add(layer, absBounds);
    412 
    413         // Now check for reasons to become composited that depend on the state of descendant layers.
    414         CompositingReasons subtreeCompositingReasons = subtreeReasonsForCompositing(layer->renderer(), childRecursionData.m_subtreeIsCompositing, anyDescendantHas3DTransform);
    415         reasonsToComposite |= subtreeCompositingReasons;
    416         if (!willBeCompositedOrSquashed && compositor->canBeComposited(layer) && requiresCompositingOrSquashing(subtreeCompositingReasons)) {
    417             childRecursionData.m_compositingAncestor = layer;
    418             // FIXME: this context push is effectively a no-op but needs to exist for
    419             // now, because the code is designed to push overlap information to the
    420             // second-from-top context of the stack.
    421             overlapMap.beginNewOverlapTestingContext();
    422             overlapMap.add(layer, absoluteDecendantBoundingBox);
    423             willBeCompositedOrSquashed = true;
    424         }
    425 
    426         // If the original layer is composited, the reflection needs to be, too.
    427         if (layer->reflectionInfo()) {
    428             // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer?
    429             RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer();
    430             CompositingReasons reflectionCompositingReason = willBeCompositedOrSquashed ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone;
    431             reflectionLayer->setCompositingReasons(reflectionLayer->compositingReasons() | reflectionCompositingReason);
    432         }
    433 
    434         if (willBeCompositedOrSquashed && layer->blendInfo().hasBlendMode())
    435             currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = true;
    436 
    437         // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
    438         // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
    439         // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
    440         bool isCompositedClippingLayer = compositor->canBeComposited(layer) && (reasonsToComposite & CompositingReasonClipsCompositingDescendants);
    441         if ((!childRecursionData.m_testingOverlap && !isCompositedClippingLayer) || isRunningAcceleratedTransformAnimation(layer->renderer()))
    442             currentRecursionData.m_testingOverlap = false;
    443 
    444         if (childRecursionData.m_compositingAncestor == layer)
    445             overlapMap.finishCurrentOverlapTestingContext();
    446 
    447         descendantHas3DTransform |= anyDescendantHas3DTransform || layer->has3DTransform();
    448     }
    449 
    450     // At this point we have finished collecting all reasons to composite this layer.
    451     layer->setCompositingReasons(reasonsToComposite);
    452 
    453 }
    454 
    455 bool CompositingRequirementsUpdater::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const
    456 {
    457     return renderer->style()->hasCurrentTransformAnimation();
    458 }
    459 
    460 } // namespace WebCore
    461