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/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 
     40 CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
     41     : m_compositor(compositor)
     42     , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
     43     , m_layersChanged(false)
     44 {
     45 }
     46 
     47 CompositingLayerAssigner::~CompositingLayerAssigner()
     48 {
     49 }
     50 
     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 
     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 
     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 
     84 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 
     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 
    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 
    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 
    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 
    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