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