1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "core/rendering/compositing/CompositingInputsUpdater.h" 7 8 #include "core/rendering/RenderBlock.h" 9 #include "core/rendering/RenderLayer.h" 10 #include "core/rendering/compositing/CompositedLayerMapping.h" 11 #include "core/rendering/compositing/RenderLayerCompositor.h" 12 #include "platform/TraceEvent.h" 13 14 namespace blink { 15 16 CompositingInputsUpdater::CompositingInputsUpdater(RenderLayer* rootRenderLayer) 17 : m_geometryMap(UseTransforms) 18 , m_rootRenderLayer(rootRenderLayer) 19 { 20 } 21 22 CompositingInputsUpdater::~CompositingInputsUpdater() 23 { 24 } 25 26 void CompositingInputsUpdater::update() 27 { 28 TRACE_EVENT0("blink", "CompositingInputsUpdater::update"); 29 updateRecursive(m_rootRenderLayer, DoNotForceUpdate, AncestorInfo()); 30 } 31 32 static const RenderLayer* findParentLayerOnClippingContainerChain(const RenderLayer* layer) 33 { 34 RenderObject* current = layer->renderer(); 35 while (current) { 36 if (current->style()->position() == FixedPosition) { 37 for (current = current->parent(); current && !current->canContainFixedPositionObjects(); current = current->parent()) { 38 // All types of clips apply to fixed-position descendants of other fixed-position elements. 39 // Note: it's unclear whether this is what the spec says. Firefox does not clip, but Chrome does. 40 if (current->style()->position() == FixedPosition && current->hasClipOrOverflowClip()) { 41 ASSERT(current->hasLayer()); 42 return static_cast<const RenderLayerModelObject*>(current)->layer(); 43 } 44 45 // CSS clip applies to fixed position elements even for ancestors that are not what the 46 // fixed element is positioned with respect to. 47 if (current->hasClip()) { 48 ASSERT(current->hasLayer()); 49 return static_cast<const RenderLayerModelObject*>(current)->layer(); 50 } 51 } 52 } else { 53 current = current->containingBlock(); 54 } 55 56 if (current->hasLayer()) 57 return static_cast<const RenderLayerModelObject*>(current)->layer(); 58 // Having clip or overflow clip forces the RenderObject to become a layer. 59 ASSERT(!current->hasClipOrOverflowClip()); 60 } 61 ASSERT_NOT_REACHED(); 62 return 0; 63 } 64 65 static const RenderLayer* findParentLayerOnContainingBlockChain(const RenderObject* object) 66 { 67 for (const RenderObject* current = object; current; current = current->containingBlock()) { 68 if (current->hasLayer()) 69 return static_cast<const RenderLayerModelObject*>(current)->layer(); 70 } 71 ASSERT_NOT_REACHED(); 72 return 0; 73 } 74 75 static bool hasClippedStackingAncestor(const RenderLayer* layer, const RenderLayer* clippingLayer) 76 { 77 if (layer == clippingLayer) 78 return false; 79 const RenderObject* clippingRenderer = clippingLayer->renderer(); 80 for (const RenderLayer* current = layer->compositingContainer(); current && current != clippingLayer; current = current->compositingContainer()) { 81 if (current->renderer()->hasClipOrOverflowClip() && !clippingRenderer->isDescendantOf(current->renderer())) 82 return true; 83 84 if (const RenderObject* container = current->clippingContainer()) { 85 if (clippingRenderer != container && !clippingRenderer->isDescendantOf(container)) 86 return true; 87 } 88 } 89 return false; 90 } 91 92 void CompositingInputsUpdater::updateRecursive(RenderLayer* layer, UpdateType updateType, AncestorInfo info) 93 { 94 if (!layer->childNeedsCompositingInputsUpdate() && updateType != ForceUpdate) 95 return; 96 97 m_geometryMap.pushMappingsToAncestor(layer, layer->parent()); 98 99 if (layer->hasCompositedLayerMapping()) 100 info.enclosingCompositedLayer = layer; 101 102 if (layer->needsCompositingInputsUpdate()) { 103 if (info.enclosingCompositedLayer) 104 info.enclosingCompositedLayer->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree); 105 updateType = ForceUpdate; 106 } 107 108 if (updateType == ForceUpdate) { 109 RenderLayer::AncestorDependentCompositingInputs properties; 110 111 if (!layer->isRootLayer()) { 112 properties.clippedAbsoluteBoundingBox = enclosingIntRect(m_geometryMap.absoluteRect(layer->boundingBoxForCompositingOverlapTest())); 113 // FIXME: Setting the absBounds to 1x1 instead of 0x0 makes very little sense, 114 // but removing this code will make JSGameBench sad. 115 // See https://codereview.chromium.org/13912020/ 116 if (properties.clippedAbsoluteBoundingBox.isEmpty()) 117 properties.clippedAbsoluteBoundingBox.setSize(IntSize(1, 1)); 118 119 IntRect clipRect = pixelSnappedIntRect(layer->clipper().backgroundClipRect(ClipRectsContext(m_rootRenderLayer, AbsoluteClipRects)).rect()); 120 properties.clippedAbsoluteBoundingBox.intersect(clipRect); 121 122 const RenderLayer* parent = layer->parent(); 123 properties.opacityAncestor = parent->isTransparent() ? parent : parent->opacityAncestor(); 124 properties.transformAncestor = parent->hasTransform() ? parent : parent->transformAncestor(); 125 properties.filterAncestor = parent->hasFilter() ? parent : parent->filterAncestor(); 126 127 if (info.hasAncestorWithClipOrOverflowClip) { 128 const RenderLayer* parentLayerOnClippingContainerChain = findParentLayerOnClippingContainerChain(layer); 129 const bool parentHasClipOrOverflowClip = parentLayerOnClippingContainerChain->renderer()->hasClipOrOverflowClip(); 130 properties.clippingContainer = parentHasClipOrOverflowClip ? parentLayerOnClippingContainerChain->renderer() : parentLayerOnClippingContainerChain->clippingContainer(); 131 } 132 133 if (info.lastScrollingAncestor) { 134 const RenderObject* containingBlock = layer->renderer()->containingBlock(); 135 const RenderLayer* parentLayerOnContainingBlockChain = findParentLayerOnContainingBlockChain(containingBlock); 136 137 properties.ancestorScrollingLayer = parentLayerOnContainingBlockChain->ancestorScrollingLayer(); 138 if (parentLayerOnContainingBlockChain->scrollsOverflow()) 139 properties.ancestorScrollingLayer = parentLayerOnContainingBlockChain; 140 141 if (layer->renderer()->isOutOfFlowPositioned() && !layer->subtreeIsInvisible()) { 142 const RenderObject* lastScroller = info.lastScrollingAncestor->renderer(); 143 const RenderLayer* clippingLayer = properties.clippingContainer ? properties.clippingContainer->enclosingLayer() : layer->compositor()->rootRenderLayer(); 144 properties.isUnclippedDescendant = lastScroller != containingBlock && lastScroller->isDescendantOf(containingBlock); 145 if (hasClippedStackingAncestor(layer, clippingLayer)) 146 properties.clipParent = clippingLayer; 147 } 148 149 if (!layer->stackingNode()->isNormalFlowOnly() 150 && properties.ancestorScrollingLayer 151 && !info.ancestorStackingContext->renderer()->isDescendantOf(properties.ancestorScrollingLayer->renderer())) 152 properties.scrollParent = properties.ancestorScrollingLayer; 153 } 154 } 155 156 properties.hasAncestorWithClipPath = info.hasAncestorWithClipPath; 157 layer->updateAncestorDependentCompositingInputs(properties); 158 } 159 160 if (layer->stackingNode()->isStackingContext()) 161 info.ancestorStackingContext = layer; 162 163 if (layer->scrollsOverflow()) 164 info.lastScrollingAncestor = layer; 165 166 if (layer->renderer()->hasClipOrOverflowClip()) 167 info.hasAncestorWithClipOrOverflowClip = true; 168 169 if (layer->renderer()->hasClipPath()) 170 info.hasAncestorWithClipPath = true; 171 172 RenderLayer::DescendantDependentCompositingInputs descendantProperties; 173 for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) { 174 updateRecursive(child, updateType, info); 175 176 descendantProperties.hasDescendantWithClipPath |= child->hasDescendantWithClipPath() || child->renderer()->hasClipPath(); 177 descendantProperties.hasDescendantWithBlendMode |= child->hasDescendantWithBlendMode() || child->renderer()->hasBlendMode(); 178 } 179 180 layer->updateDescendantDependentCompositingInputs(descendantProperties); 181 layer->didUpdateCompositingInputs(); 182 183 m_geometryMap.popMappingsToAncestor(layer->parent()); 184 } 185 186 #if ENABLE(ASSERT) 187 188 void CompositingInputsUpdater::assertNeedsCompositingInputsUpdateBitsCleared(RenderLayer* layer) 189 { 190 ASSERT(!layer->childNeedsCompositingInputsUpdate()); 191 ASSERT(!layer->needsCompositingInputsUpdate()); 192 193 for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) 194 assertNeedsCompositingInputsUpdateBitsCleared(child); 195 } 196 197 #endif 198 199 } // namespace blink 200