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