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