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/rendering/compositing/CompositedLayerMapping.h"
     31 
     32 namespace WebCore {
     33 
     34 // We will only allow squashing if the bbox-area:squashed-area doesn't exceed
     35 // the ratio |gSquashingSparsityTolerance|:1.
     36 static uint64_t gSquashingSparsityTolerance = 6;
     37 
     38 CompositingLayerAssigner::CompositingLayerAssigner(RenderLayerCompositor* compositor)
     39     : m_compositor(compositor)
     40     , m_layerSquashingEnabled(compositor->layerSquashingEnabled())
     41 {
     42 }
     43 
     44 CompositingLayerAssigner::~CompositingLayerAssigner()
     45 {
     46 }
     47 
     48 void CompositingLayerAssigner::assign(RenderLayer* updateRoot, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint)
     49 {
     50     SquashingState squashingState;
     51     assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged, layersNeedingRepaint);
     52     if (squashingState.hasMostRecentMapping)
     53         squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex);
     54 }
     55 
     56 void CompositingLayerAssigner::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMappingPtr newCompositedLayerMapping, bool hasNewCompositedLayerMapping)
     57 {
     58     // The most recent backing is done accumulating any more squashing layers.
     59     if (hasMostRecentMapping)
     60         mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex);
     61 
     62     nextSquashedLayerIndex = 0;
     63     boundingRect = IntRect();
     64     mostRecentMapping = newCompositedLayerMapping;
     65     hasMostRecentMapping = hasNewCompositedLayerMapping;
     66     haveAssignedBackingsToEntireSquashingLayerSubtree = false;
     67 }
     68 
     69 bool CompositingLayerAssigner::squashingWouldExceedSparsityTolerance(const RenderLayer* candidate, const CompositingLayerAssigner::SquashingState& squashingState)
     70 {
     71     IntRect bounds = candidate->compositingInputs().clippedAbsoluteBoundingBox;
     72     IntRect newBoundingRect = squashingState.boundingRect;
     73     newBoundingRect.unite(bounds);
     74     const uint64_t newBoundingRectArea = newBoundingRect.size().area();
     75     const uint64_t newSquashedArea = squashingState.totalAreaOfSquashedRects + bounds.size().area();
     76     return newBoundingRectArea > gSquashingSparsityTolerance * newSquashedArea;
     77 }
     78 
     79 bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const
     80 {
     81     if (!m_compositor->canBeComposited(layer))
     82         return false;
     83 
     84     // If squashing is disabled, then layers that would have been squashed should just be separately composited.
     85     bool needsOwnBackingForDisabledSquashing = !m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons());
     86 
     87     return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer());
     88 }
     89 
     90 CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer)
     91 {
     92     CompositingStateTransitionType update = NoCompositingStateChange;
     93     if (needsOwnBacking(layer)) {
     94         if (!layer->hasCompositedLayerMapping()) {
     95             update = AllocateOwnCompositedLayerMapping;
     96         }
     97     } else {
     98         if (layer->hasCompositedLayerMapping())
     99             update = RemoveOwnCompositedLayerMapping;
    100 
    101         if (m_layerSquashingEnabled) {
    102             if (!layer->subtreeIsInvisible() && requiresSquashing(layer->compositingReasons())) {
    103                 // We can't compute at this time whether the squashing layer update is a no-op,
    104                 // since that requires walking the render layer tree.
    105                 update = PutInSquashingLayer;
    106             } else if (layer->groupedMapping() || layer->lostGroupedMapping()) {
    107                 update = RemoveFromSquashingLayer;
    108             }
    109         }
    110     }
    111     return update;
    112 }
    113 
    114 CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const RenderLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
    115 {
    116     if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
    117         return CompositingReasonSquashingWouldBreakPaintOrder;
    118 
    119     // FIXME: this special case for video exists only to deal with corner cases
    120     // where a RenderVideo does not report that it needs to be directly composited.
    121     // Video does not currently support sharing a backing, but this could be
    122     // generalized in the future. The following layout tests fail if we permit the
    123     // video to share a backing with other layers.
    124     //
    125     // compositing/video/video-controls-layer-creation.html
    126     // virtual/softwarecompositing/video/video-controls-layer-creation.html
    127     if (layer->renderer()->isVideo())
    128         return CompositingReasonSquashingVideoIsDisallowed;
    129 
    130     if (squashingWouldExceedSparsityTolerance(layer, squashingState))
    131         return CompositingReasonSquashingSparsityExceeded;
    132 
    133     // FIXME: this is not efficient, since it walks up the tree . We should store these values on the CompositingInputsCache.
    134     ASSERT(squashingState.hasMostRecentMapping);
    135     const RenderLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer();
    136 
    137     if (layer->renderer()->clippingContainer() != squashingLayer.renderer()->clippingContainer()) {
    138         if (!squashingLayer.compositedLayerMapping()->containingSquashedLayer(layer->renderer()->clippingContainer()))
    139             return CompositingReasonSquashingClippingContainerMismatch;
    140     }
    141 
    142     // Composited descendants need to be clipped by a child containment graphics layer, which would not be available if the layer is
    143     // squashed (and therefore has no CLM nor a child containment graphics layer).
    144     if (m_compositor->clipsCompositingDescendants(layer))
    145         return CompositingReasonSquashedLayerClipsCompositingDescendants;
    146 
    147     if (layer->scrollsWithRespectTo(&squashingLayer))
    148         return CompositingReasonScrollsWithRespectToSquashingLayer;
    149 
    150     const RenderLayer::CompositingInputs& compositingInputs = layer->compositingInputs();
    151     const RenderLayer::CompositingInputs& squashingLayerCompositingInputs = squashingLayer.compositingInputs();
    152 
    153     if (compositingInputs.opacityAncestor != squashingLayerCompositingInputs.opacityAncestor)
    154         return CompositingReasonSquashingOpacityAncestorMismatch;
    155 
    156     if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor)
    157         return CompositingReasonSquashingTransformAncestorMismatch;
    158 
    159     if (compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
    160         return CompositingReasonSquashingFilterAncestorMismatch;
    161 
    162     return CompositingReasonNone;
    163 }
    164 
    165 bool CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate,
    166     Vector<RenderLayer*>& layersNeedingRepaint)
    167 {
    168     // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than
    169     // the squashed RenderLayer's own primary contents. This would happen when we have a composited negative z-index element that needs
    170     // to paint on top of the background, but below the layer's main contents. For now, because we always composite layers
    171     // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue.
    172     if (compositedLayerUpdate == PutInSquashingLayer) {
    173         // A layer that is squashed with other layers cannot have its own CompositedLayerMapping.
    174         ASSERT(!layer->hasCompositedLayerMapping());
    175         ASSERT(squashingState.hasMostRecentMapping);
    176 
    177         bool changedSquashingLayer =
    178             squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex);
    179         if (!changedSquashingLayer)
    180             return true;
    181 
    182         // If we've modified the collection of squashed layers, we must update
    183         // the graphics layer geometry.
    184         squashingState.mostRecentMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
    185 
    186         layer->clipper().clearClipRectsIncludingDescendants();
    187 
    188         // Issue a repaint, since |layer| may have been added to an already-existing squashing layer.
    189         layersNeedingRepaint.append(layer);
    190 
    191         return true;
    192     }
    193     if (compositedLayerUpdate == RemoveFromSquashingLayer) {
    194         if (layer->groupedMapping()) {
    195             // Before removing |layer| from an already-existing squashing layer that may have other content, issue a repaint.
    196             m_compositor->repaintOnCompositingChange(layer);
    197             layer->groupedMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
    198             layer->setGroupedMapping(0);
    199         }
    200 
    201         // If we need to repaint, do so now that we've removed it from a squashed layer.
    202         layersNeedingRepaint.append(layer);
    203 
    204         layer->setLostGroupedMapping(false);
    205         return true;
    206     }
    207 
    208     return false;
    209 }
    210 
    211 void CompositingLayerAssigner::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint)
    212 {
    213     CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(reflectionLayer);
    214     if (compositedLayerUpdate != NoCompositingStateChange) {
    215         layersNeedingRepaint.append(reflectionLayer);
    216         layersChanged = true;
    217         m_compositor->allocateOrClearCompositedLayerMapping(reflectionLayer, compositedLayerUpdate);
    218     }
    219     m_compositor->updateDirectCompositingReasons(reflectionLayer);
    220     if (reflectionLayer->hasCompositedLayerMapping())
    221         reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration(GraphicsLayerUpdater::ForceUpdate);
    222 }
    223 
    224 void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint)
    225 {
    226     if (m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons())) {
    227         CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
    228         if (reasonsPreventingSquashing)
    229             layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing);
    230     }
    231 
    232     CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer);
    233 
    234     if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) {
    235         layersNeedingRepaint.append(layer);
    236         layersChanged = true;
    237     }
    238 
    239     // FIXME: special-casing reflection layers here is not right.
    240     if (layer->reflectionInfo())
    241         assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersChanged, layersNeedingRepaint);
    242 
    243     // Add this layer to a squashing backing if needed.
    244     if (m_layerSquashingEnabled) {
    245         if (updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingRepaint))
    246             layersChanged = true;
    247 
    248         const bool layerIsSquashed = compositedLayerUpdate == PutInSquashingLayer || (compositedLayerUpdate == NoCompositingStateChange && layer->groupedMapping());
    249         if (layerIsSquashed) {
    250             squashingState.nextSquashedLayerIndex++;
    251             IntRect layerBounds = layer->compositingInputs().clippedAbsoluteBoundingBox;
    252             squashingState.totalAreaOfSquashedRects += layerBounds.size().area();
    253             squashingState.boundingRect.unite(layerBounds);
    254         }
    255     }
    256 
    257     if (layer->stackingNode()->isStackingContext()) {
    258         RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren);
    259         while (RenderLayerStackingNode* curNode = iterator.next())
    260             assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint);
    261     }
    262 
    263     if (m_layerSquashingEnabled) {
    264         // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order.
    265         if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) {
    266             ASSERT(!requiresSquashing(layer->compositingReasons()));
    267             squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping());
    268         }
    269     }
    270 
    271     RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren);
    272     while (RenderLayerStackingNode* curNode = iterator.next())
    273         assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint);
    274 
    275     if (squashingState.hasMostRecentMapping && &squashingState.mostRecentMapping->owningLayer() == layer)
    276         squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree = true;
    277 }
    278 
    279 }
    280