OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/paint/PrePaintTreeWalk.h" | 5 #include "core/paint/PrePaintTreeWalk.h" |
6 | 6 |
7 #include "core/dom/DocumentLifecycle.h" | 7 #include "core/dom/DocumentLifecycle.h" |
8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
9 #include "core/frame/LocalFrame.h" | 9 #include "core/frame/LocalFrame.h" |
10 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" | 10 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" |
11 #include "core/layout/LayoutPart.h" | 11 #include "core/layout/LayoutPart.h" |
12 #include "core/layout/LayoutView.h" | 12 #include "core/layout/LayoutView.h" |
13 #include "core/paint/PaintLayer.h" | 13 #include "core/paint/PaintLayer.h" |
14 | 14 |
15 namespace blink { | 15 namespace blink { |
16 | 16 |
17 struct PrePaintTreeWalkContext { | 17 struct PrePaintTreeWalkContext { |
| 18 USING_FAST_MALLOC(PrePaintTreeWalkContext); |
| 19 |
| 20 public: |
18 PrePaintTreeWalkContext() | 21 PrePaintTreeWalkContext() |
19 : treeBuilderContext( | 22 : treeBuilderContext(), |
20 WTF::wrapUnique(new PaintPropertyTreeBuilderContext)), | 23 paintInvalidatorContext(treeBuilderContext), |
21 paintInvalidatorContext(*treeBuilderContext), | |
22 ancestorOverflowPaintLayer(nullptr), | 24 ancestorOverflowPaintLayer(nullptr), |
23 ancestorTransformedOrRootPaintLayer(nullptr) {} | 25 ancestorTransformedOrRootPaintLayer(nullptr) {} |
24 PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) | 26 PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) |
25 : treeBuilderContext(WTF::wrapUnique(new PaintPropertyTreeBuilderContext( | 27 : treeBuilderContext(parentContext.treeBuilderContext), |
26 *parentContext.treeBuilderContext))), | 28 paintInvalidatorContext(treeBuilderContext, |
27 paintInvalidatorContext(*treeBuilderContext, | |
28 parentContext.paintInvalidatorContext), | 29 parentContext.paintInvalidatorContext), |
29 ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer), | 30 ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer), |
30 ancestorTransformedOrRootPaintLayer( | 31 ancestorTransformedOrRootPaintLayer( |
31 parentContext.ancestorTransformedOrRootPaintLayer) {} | 32 parentContext.ancestorTransformedOrRootPaintLayer) {} |
32 | 33 |
33 // PaintPropertyTreeBuilderContext is large and can lead to stack overflows | 34 PaintPropertyTreeBuilderContext treeBuilderContext; |
34 // when recursion is deep so this context object is allocated on the heap. | |
35 // See: https://crbug.com/698653. | |
36 std::unique_ptr<PaintPropertyTreeBuilderContext> treeBuilderContext; | |
37 | 35 |
38 PaintInvalidatorContext paintInvalidatorContext; | 36 PaintInvalidatorContext paintInvalidatorContext; |
39 | 37 |
40 // The ancestor in the PaintLayer tree which has overflow clip, or | 38 // The ancestor in the PaintLayer tree which has overflow clip, or |
41 // is the root layer. Note that it is tree ancestor, not containing | 39 // is the root layer. Note that it is tree ancestor, not containing |
42 // block or stacking ancestor. | 40 // block or stacking ancestor. |
43 PaintLayer* ancestorOverflowPaintLayer; | 41 PaintLayer* ancestorOverflowPaintLayer; |
44 PaintLayer* ancestorTransformedOrRootPaintLayer; | 42 PaintLayer* ancestorTransformedOrRootPaintLayer; |
45 }; | 43 }; |
46 | 44 |
47 void PrePaintTreeWalk::walk(FrameView& rootFrame) { | 45 void PrePaintTreeWalk::walk(FrameView& rootFrame) { |
48 DCHECK(rootFrame.frame().document()->lifecycle().state() == | 46 DCHECK(rootFrame.frame().document()->lifecycle().state() == |
49 DocumentLifecycle::InPrePaint); | 47 DocumentLifecycle::InPrePaint); |
50 | 48 |
51 PrePaintTreeWalkContext initialContext; | 49 PrePaintTreeWalkContext initialContext; |
52 m_propertyTreeBuilder.setupInitialContext(*initialContext.treeBuilderContext); | 50 m_propertyTreeBuilder.setupInitialContext(initialContext.treeBuilderContext); |
53 initialContext.ancestorTransformedOrRootPaintLayer = | 51 initialContext.ancestorTransformedOrRootPaintLayer = |
54 rootFrame.layoutView()->layer(); | 52 rootFrame.layoutView()->layer(); |
55 | 53 |
56 // GeometryMapper depends on paint properties. | 54 // GeometryMapper depends on paint properties. |
57 if (rootFrame.needsPaintPropertyUpdate() || | 55 if (rootFrame.needsPaintPropertyUpdate() || |
58 (rootFrame.layoutView() && | 56 (rootFrame.layoutView() && |
59 !shouldEndWalkBefore(*rootFrame.layoutView(), initialContext))) | 57 !shouldEndWalkBefore(*rootFrame.layoutView(), initialContext))) |
60 m_geometryMapper.clearCache(); | 58 m_geometryMapper.clearCache(); |
61 | 59 |
62 walk(rootFrame, initialContext); | 60 walk(rootFrame, initialContext); |
63 m_paintInvalidator.processPendingDelayedPaintInvalidations(); | 61 m_paintInvalidator.processPendingDelayedPaintInvalidations(); |
64 } | 62 } |
65 | 63 |
66 void PrePaintTreeWalk::walk(FrameView& frameView, | 64 void PrePaintTreeWalk::walk(FrameView& frameView, |
67 const PrePaintTreeWalkContext& parentContext) { | 65 const PrePaintTreeWalkContext& parentContext) { |
68 if (frameView.shouldThrottleRendering()) { | 66 if (frameView.shouldThrottleRendering()) { |
69 // Skip the throttled frame. Will update it when it becomes unthrottled. | 67 // Skip the throttled frame. Will update it when it becomes unthrottled. |
70 return; | 68 return; |
71 } | 69 } |
72 | 70 |
73 PrePaintTreeWalkContext context(parentContext); | 71 PrePaintTreeWalkContext context(parentContext); |
74 // ancestorOverflowLayer does not cross frame boundaries. | 72 // ancestorOverflowLayer does not cross frame boundaries. |
75 context.ancestorOverflowPaintLayer = nullptr; | 73 context.ancestorOverflowPaintLayer = nullptr; |
76 m_propertyTreeBuilder.updateProperties(frameView, | 74 m_propertyTreeBuilder.updateProperties(frameView, context.treeBuilderContext); |
77 *context.treeBuilderContext); | |
78 m_paintInvalidator.invalidatePaintIfNeeded(frameView, | 75 m_paintInvalidator.invalidatePaintIfNeeded(frameView, |
79 context.paintInvalidatorContext); | 76 context.paintInvalidatorContext); |
80 | 77 |
81 if (LayoutView* view = frameView.layoutView()) { | 78 if (LayoutView* view = frameView.layoutView()) { |
82 walk(*view, context); | 79 walk(*view, context); |
83 #if DCHECK_IS_ON() | 80 #if DCHECK_IS_ON() |
84 view->assertSubtreeClearedPaintInvalidationFlags(); | 81 view->assertSubtreeClearedPaintInvalidationFlags(); |
85 #endif | 82 #endif |
86 } | 83 } |
87 frameView.clearNeedsPaintPropertyUpdate(); | 84 frameView.clearNeedsPaintPropertyUpdate(); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 respectOverflowClip, LayoutSize()); | 176 respectOverflowClip, LayoutSize()); |
180 #endif | 177 #endif |
181 | 178 |
182 bool hasClip = false; | 179 bool hasClip = false; |
183 RefPtr<ClipRects> clipRects = ClipRects::create(); | 180 RefPtr<ClipRects> clipRects = ClipRects::create(); |
184 const LayoutPoint& ancestorPaintOffset = | 181 const LayoutPoint& ancestorPaintOffset = |
185 context.ancestorTransformedOrRootPaintLayer->layoutObject().paintOffset(); | 182 context.ancestorTransformedOrRootPaintLayer->layoutObject().paintOffset(); |
186 | 183 |
187 FloatClipRect clipRect; | 184 FloatClipRect clipRect; |
188 const EffectPaintPropertyNode* effect = | 185 const EffectPaintPropertyNode* effect = |
189 context.treeBuilderContext->currentEffect; | 186 context.treeBuilderContext.currentEffect; |
190 computeClipRectForContext(context.treeBuilderContext->current, effect, | 187 computeClipRectForContext(context.treeBuilderContext.current, effect, |
191 ancestorState, ancestorPaintOffset, hasClip, | 188 ancestorState, ancestorPaintOffset, hasClip, |
192 clipRect); | 189 clipRect); |
193 clipRects->setOverflowClipRect(clipRect); | 190 clipRects->setOverflowClipRect(clipRect); |
194 #ifdef CHECK_CLIP_RECTS | 191 #ifdef CHECK_CLIP_RECTS |
195 CHECK(!hasClip || | 192 CHECK(!hasClip || |
196 clipRects->overflowClipRect() == oldClipRects.overflowClipRect()) | 193 clipRects->overflowClipRect() == oldClipRects.overflowClipRect()) |
197 << "rect= " << clipRects->overflowClipRect().toString(); | 194 << "rect= " << clipRects->overflowClipRect().toString(); |
198 #endif | 195 #endif |
199 | 196 |
200 computeClipRectForContext(context.treeBuilderContext->fixedPosition, effect, | 197 computeClipRectForContext(context.treeBuilderContext.fixedPosition, effect, |
201 ancestorState, ancestorPaintOffset, hasClip, | 198 ancestorState, ancestorPaintOffset, hasClip, |
202 clipRect); | 199 clipRect); |
203 clipRects->setFixedClipRect(clipRect); | 200 clipRects->setFixedClipRect(clipRect); |
204 #ifdef CHECK_CLIP_RECTS | 201 #ifdef CHECK_CLIP_RECTS |
205 CHECK(hasClip || clipRects->fixedClipRect() == oldClipRects.fixedClipRect()) | 202 CHECK(hasClip || clipRects->fixedClipRect() == oldClipRects.fixedClipRect()) |
206 << " fixed=" << clipRects->fixedClipRect().toString(); | 203 << " fixed=" << clipRects->fixedClipRect().toString(); |
207 #endif | 204 #endif |
208 | 205 |
209 computeClipRectForContext(context.treeBuilderContext->absolutePosition, | 206 computeClipRectForContext(context.treeBuilderContext.absolutePosition, effect, |
210 effect, ancestorState, ancestorPaintOffset, hasClip, | 207 ancestorState, ancestorPaintOffset, hasClip, |
211 clipRect); | 208 clipRect); |
212 clipRects->setPosClipRect(clipRect); | 209 clipRects->setPosClipRect(clipRect); |
213 #ifdef CHECK_CLIP_RECTS | 210 #ifdef CHECK_CLIP_RECTS |
214 CHECK(!hasClip || clipRects->posClipRect() == oldClipRects.posClipRect()) | 211 CHECK(!hasClip || clipRects->posClipRect() == oldClipRects.posClipRect()) |
215 << " abs=" << clipRects->posClipRect().toString(); | 212 << " abs=" << clipRects->posClipRect().toString(); |
216 #endif | 213 #endif |
217 | 214 |
218 ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); | 215 ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); |
219 | 216 |
220 if (!previousClipRects || *clipRects != *previousClipRects) { | 217 if (!previousClipRects || *clipRects != *previousClipRects) { |
221 paintLayer.setNeedsRepaint(); | 218 paintLayer.setNeedsRepaint(); |
222 paintLayer.setPreviousPaintPhaseDescendantOutlinesEmpty(false); | 219 paintLayer.setPreviousPaintPhaseDescendantOutlinesEmpty(false); |
223 paintLayer.setPreviousPaintPhaseFloatEmpty(false); | 220 paintLayer.setPreviousPaintPhaseFloatEmpty(false); |
224 paintLayer.setPreviousPaintPhaseDescendantBlockBackgroundsEmpty(false); | 221 paintLayer.setPreviousPaintPhaseDescendantBlockBackgroundsEmpty(false); |
225 // All subsequences which are contained below this paintLayer must also | 222 // All subsequences which are contained below this paintLayer must also |
226 // be checked. | 223 // be checked. |
227 context.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= | 224 context.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= |
228 PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate; | 225 PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate; |
229 } | 226 } |
230 | 227 |
231 paintLayer.setPreviousPaintingClipRects(*clipRects); | 228 paintLayer.setPreviousPaintingClipRects(*clipRects); |
232 } | 229 } |
233 | 230 |
234 bool PrePaintTreeWalk::shouldEndWalkBefore( | 231 bool PrePaintTreeWalk::shouldEndWalkBefore( |
235 const LayoutObject& object, | 232 const LayoutObject& object, |
236 const PrePaintTreeWalkContext& context) { | 233 const PrePaintTreeWalkContext& context) { |
237 return ( | 234 return ( |
238 !object.needsPaintPropertyUpdate() && | 235 !object.needsPaintPropertyUpdate() && |
239 !object.descendantNeedsPaintPropertyUpdate() && | 236 !object.descendantNeedsPaintPropertyUpdate() && |
240 !context.treeBuilderContext->forceSubtreeUpdate && | 237 !context.treeBuilderContext.forceSubtreeUpdate && |
241 !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && | 238 !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && |
242 !object | 239 !object |
243 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState())
; | 240 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState())
; |
244 } | 241 } |
245 | 242 |
246 void PrePaintTreeWalk::walk(const LayoutObject& object, | 243 void PrePaintTreeWalk::walk(const LayoutObject& object, |
247 const PrePaintTreeWalkContext& parentContext) { | 244 const PrePaintTreeWalkContext& parentContext) { |
248 if (shouldEndWalkBefore(object, parentContext)) | 245 if (shouldEndWalkBefore(object, parentContext)) |
249 return; | 246 return; |
250 | 247 |
251 PrePaintTreeWalkContext context(parentContext); | 248 PrePaintTreeWalkContext context(parentContext); |
252 | 249 |
253 // This must happen before updatePropertiesForSelf, because the latter reads | 250 // This must happen before updatePropertiesForSelf, because the latter reads |
254 // some of the state computed here. | 251 // some of the state computed here. |
255 updateAuxiliaryObjectProperties(object, context); | 252 updateAuxiliaryObjectProperties(object, context); |
256 | 253 |
257 m_propertyTreeBuilder.updatePropertiesForSelf(object, | 254 m_propertyTreeBuilder.updatePropertiesForSelf(object, |
258 *context.treeBuilderContext); | 255 context.treeBuilderContext); |
259 m_paintInvalidator.invalidatePaintIfNeeded(object, | 256 m_paintInvalidator.invalidatePaintIfNeeded(object, |
260 context.paintInvalidatorContext); | 257 context.paintInvalidatorContext); |
261 m_propertyTreeBuilder.updatePropertiesForChildren( | 258 m_propertyTreeBuilder.updatePropertiesForChildren(object, |
262 object, *context.treeBuilderContext); | 259 context.treeBuilderContext); |
263 | 260 |
264 invalidatePaintLayerOptimizationsIfNeeded(object, context); | 261 invalidatePaintLayerOptimizationsIfNeeded(object, context); |
265 | 262 |
266 for (const LayoutObject* child = object.slowFirstChild(); child; | 263 for (const LayoutObject* child = object.slowFirstChild(); child; |
267 child = child->nextSibling()) { | 264 child = child->nextSibling()) { |
268 if (child->isLayoutMultiColumnSpannerPlaceholder()) { | 265 if (child->isLayoutMultiColumnSpannerPlaceholder()) { |
269 child->getMutableForPainting().clearPaintFlags(); | 266 child->getMutableForPainting().clearPaintFlags(); |
270 continue; | 267 continue; |
271 } | 268 } |
272 walk(*child, context); | 269 walk(*child, context); |
273 } | 270 } |
274 | 271 |
275 if (object.isLayoutPart()) { | 272 if (object.isLayoutPart()) { |
276 const LayoutPart& layoutPart = toLayoutPart(object); | 273 const LayoutPart& layoutPart = toLayoutPart(object); |
277 FrameViewBase* frameViewBase = layoutPart.frameViewBase(); | 274 FrameViewBase* frameViewBase = layoutPart.frameViewBase(); |
278 if (frameViewBase && frameViewBase->isFrameView()) { | 275 if (frameViewBase && frameViewBase->isFrameView()) { |
279 context.treeBuilderContext->current.paintOffset += | 276 context.treeBuilderContext.current.paintOffset += |
280 layoutPart.replacedContentRect().location() - | 277 layoutPart.replacedContentRect().location() - |
281 frameViewBase->frameRect().location(); | 278 frameViewBase->frameRect().location(); |
282 context.treeBuilderContext->current.paintOffset = | 279 context.treeBuilderContext.current.paintOffset = |
283 roundedIntPoint(context.treeBuilderContext->current.paintOffset); | 280 roundedIntPoint(context.treeBuilderContext.current.paintOffset); |
284 walk(*toFrameView(frameViewBase), context); | 281 walk(*toFrameView(frameViewBase), context); |
285 } | 282 } |
286 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). | 283 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). |
287 } | 284 } |
288 | 285 |
289 object.getMutableForPainting().clearPaintFlags(); | 286 object.getMutableForPainting().clearPaintFlags(); |
290 } | 287 } |
291 | 288 |
292 } // namespace blink | 289 } // namespace blink |
OLD | NEW |