• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CompositingInputsUpdater(RenderLayer * rootRenderLayer)16 CompositingInputsUpdater::CompositingInputsUpdater(RenderLayer* rootRenderLayer)
17     : m_geometryMap(UseTransforms)
18     , m_rootRenderLayer(rootRenderLayer)
19 {
20 }
21 
~CompositingInputsUpdater()22 CompositingInputsUpdater::~CompositingInputsUpdater()
23 {
24 }
25 
update()26 void CompositingInputsUpdater::update()
27 {
28     TRACE_EVENT0("blink", "CompositingInputsUpdater::update");
29     updateRecursive(m_rootRenderLayer, DoNotForceUpdate, AncestorInfo());
30 }
31 
findParentLayerOnClippingContainerChain(const RenderLayer * layer)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 
findParentLayerOnContainingBlockChain(const RenderObject * object)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 
hasClippedStackingAncestor(const RenderLayer * layer,const RenderLayer * clippingLayer)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 
updateRecursive(RenderLayer * layer,UpdateType updateType,AncestorInfo info)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 
assertNeedsCompositingInputsUpdateBitsCleared(RenderLayer * layer)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