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