Chromium Code Reviews| 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 PrePaintTreeWalkContext() | 18 PrePaintTreeWalkContext() |
| 19 : paintInvalidatorContext(treeBuilderContext), | 19 : treeBuilderContext( |
| 20 WTF::wrapUnique(new PaintPropertyTreeBuilderContext)), | |
| 21 paintInvalidatorContext(*treeBuilderContext), | |
| 20 ancestorOverflowPaintLayer(nullptr), | 22 ancestorOverflowPaintLayer(nullptr), |
| 21 ancestorTransformedOrRootPaintLayer(nullptr) {} | 23 ancestorTransformedOrRootPaintLayer(nullptr) {} |
| 22 PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) | 24 PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) |
| 23 : treeBuilderContext(parentContext.treeBuilderContext), | 25 : treeBuilderContext(WTF::wrapUnique(new PaintPropertyTreeBuilderContext( |
| 24 paintInvalidatorContext(treeBuilderContext, | 26 *parentContext.treeBuilderContext))), |
| 27 paintInvalidatorContext(*treeBuilderContext, | |
| 25 parentContext.paintInvalidatorContext), | 28 parentContext.paintInvalidatorContext), |
| 26 ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer), | 29 ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer), |
| 27 ancestorTransformedOrRootPaintLayer( | 30 ancestorTransformedOrRootPaintLayer( |
| 28 parentContext.ancestorTransformedOrRootPaintLayer) {} | 31 parentContext.ancestorTransformedOrRootPaintLayer) {} |
| 29 | 32 |
| 30 PaintPropertyTreeBuilderContext treeBuilderContext; | 33 // PaintPropertyTreeBuilderContext is large and can lead to stack overflows |
|
pdr.
2017/03/10 20:52:39
I think we may still have the issues in https://cr
Xianzhu
2017/03/10 21:54:48
I think 96 bytes is already small enough. It's sma
| |
| 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 | |
| 31 PaintInvalidatorContext paintInvalidatorContext; | 38 PaintInvalidatorContext paintInvalidatorContext; |
| 32 | 39 |
| 33 // The ancestor in the PaintLayer tree which has overflow clip, or | 40 // The ancestor in the PaintLayer tree which has overflow clip, or |
| 34 // is the root layer. Note that it is tree ancestor, not containing | 41 // is the root layer. Note that it is tree ancestor, not containing |
| 35 // block or stacking ancestor. | 42 // block or stacking ancestor. |
| 36 PaintLayer* ancestorOverflowPaintLayer; | 43 PaintLayer* ancestorOverflowPaintLayer; |
| 37 PaintLayer* ancestorTransformedOrRootPaintLayer; | 44 PaintLayer* ancestorTransformedOrRootPaintLayer; |
| 38 }; | 45 }; |
| 39 | 46 |
| 40 void PrePaintTreeWalk::walk(FrameView& rootFrame) { | 47 void PrePaintTreeWalk::walk(FrameView& rootFrame) { |
| 41 DCHECK(rootFrame.frame().document()->lifecycle().state() == | 48 DCHECK(rootFrame.frame().document()->lifecycle().state() == |
| 42 DocumentLifecycle::InPrePaint); | 49 DocumentLifecycle::InPrePaint); |
| 43 | 50 |
| 44 PrePaintTreeWalkContext initialContext; | 51 PrePaintTreeWalkContext initialContext; |
| 45 initialContext.treeBuilderContext = | 52 m_propertyTreeBuilder.setupInitialContext(*initialContext.treeBuilderContext); |
| 46 m_propertyTreeBuilder.setupInitialContext(); | |
| 47 initialContext.ancestorTransformedOrRootPaintLayer = | 53 initialContext.ancestorTransformedOrRootPaintLayer = |
| 48 rootFrame.layoutView()->layer(); | 54 rootFrame.layoutView()->layer(); |
| 49 | 55 |
| 50 // GeometryMapper depends on paint properties. | 56 // GeometryMapper depends on paint properties. |
| 51 if (rootFrame.needsPaintPropertyUpdate() || | 57 if (rootFrame.needsPaintPropertyUpdate() || |
| 52 (rootFrame.layoutView() && | 58 (rootFrame.layoutView() && |
| 53 !shouldEndWalkBefore(*rootFrame.layoutView(), initialContext))) | 59 !shouldEndWalkBefore(*rootFrame.layoutView(), initialContext))) |
| 54 m_geometryMapper.clearCache(); | 60 m_geometryMapper.clearCache(); |
| 55 | 61 |
| 56 walk(rootFrame, initialContext); | 62 walk(rootFrame, initialContext); |
| 57 m_paintInvalidator.processPendingDelayedPaintInvalidations(); | 63 m_paintInvalidator.processPendingDelayedPaintInvalidations(); |
| 58 } | 64 } |
| 59 | 65 |
| 60 void PrePaintTreeWalk::walk(FrameView& frameView, | 66 void PrePaintTreeWalk::walk(FrameView& frameView, |
| 61 const PrePaintTreeWalkContext& parentContext) { | 67 const PrePaintTreeWalkContext& parentContext) { |
| 62 if (frameView.shouldThrottleRendering()) { | 68 if (frameView.shouldThrottleRendering()) { |
| 63 // Skip the throttled frame. Will update it when it becomes unthrottled. | 69 // Skip the throttled frame. Will update it when it becomes unthrottled. |
| 64 return; | 70 return; |
| 65 } | 71 } |
| 66 | 72 |
| 67 PrePaintTreeWalkContext context(parentContext); | 73 PrePaintTreeWalkContext context(parentContext); |
| 68 // ancestorOverflowLayer does not cross frame boundaries. | 74 // ancestorOverflowLayer does not cross frame boundaries. |
| 69 context.ancestorOverflowPaintLayer = nullptr; | 75 context.ancestorOverflowPaintLayer = nullptr; |
| 70 m_propertyTreeBuilder.updateProperties(frameView, context.treeBuilderContext); | 76 m_propertyTreeBuilder.updateProperties(frameView, |
| 77 *context.treeBuilderContext); | |
| 71 m_paintInvalidator.invalidatePaintIfNeeded(frameView, | 78 m_paintInvalidator.invalidatePaintIfNeeded(frameView, |
| 72 context.paintInvalidatorContext); | 79 context.paintInvalidatorContext); |
| 73 | 80 |
| 74 if (LayoutView* view = frameView.layoutView()) { | 81 if (LayoutView* view = frameView.layoutView()) { |
| 75 walk(*view, context); | 82 walk(*view, context); |
| 76 #if DCHECK_IS_ON() | 83 #if DCHECK_IS_ON() |
| 77 view->assertSubtreeClearedPaintInvalidationFlags(); | 84 view->assertSubtreeClearedPaintInvalidationFlags(); |
| 78 #endif | 85 #endif |
| 79 } | 86 } |
| 80 frameView.clearNeedsPaintPropertyUpdate(); | 87 frameView.clearNeedsPaintPropertyUpdate(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 if (object.styleRef().hasTransform() || | 152 if (object.styleRef().hasTransform() || |
| 146 &object == context.paintInvalidatorContext.paintInvalidationContainer) { | 153 &object == context.paintInvalidatorContext.paintInvalidationContainer) { |
| 147 context.ancestorTransformedOrRootPaintLayer = &paintLayer; | 154 context.ancestorTransformedOrRootPaintLayer = &paintLayer; |
| 148 } | 155 } |
| 149 | 156 |
| 150 const ObjectPaintProperties& ancestorPaintProperties = | 157 const ObjectPaintProperties& ancestorPaintProperties = |
| 151 *context.ancestorTransformedOrRootPaintLayer->layoutObject() | 158 *context.ancestorTransformedOrRootPaintLayer->layoutObject() |
| 152 .paintProperties(); | 159 .paintProperties(); |
| 153 PropertyTreeState ancestorState = | 160 PropertyTreeState ancestorState = |
| 154 *ancestorPaintProperties.localBorderBoxProperties(); | 161 *ancestorPaintProperties.localBorderBoxProperties(); |
| 155 const EffectPaintPropertyNode* effect = | |
| 156 context.treeBuilderContext.currentEffect; | |
| 157 | 162 |
| 158 #ifdef CHECK_CLIP_RECTS | 163 #ifdef CHECK_CLIP_RECTS |
| 159 ShouldRespectOverflowClipType respectOverflowClip = RespectOverflowClip; | 164 ShouldRespectOverflowClipType respectOverflowClip = RespectOverflowClip; |
| 160 #endif | 165 #endif |
| 161 if (context.ancestorTransformedOrRootPaintLayer->compositingState() == | 166 if (context.ancestorTransformedOrRootPaintLayer->compositingState() == |
| 162 PaintsIntoOwnBacking && | 167 PaintsIntoOwnBacking && |
| 163 ancestorPaintProperties.overflowClip()) { | 168 ancestorPaintProperties.overflowClip()) { |
| 164 ancestorState.setClip(ancestorPaintProperties.overflowClip()); | 169 ancestorState.setClip(ancestorPaintProperties.overflowClip()); |
| 165 #ifdef CHECK_CLIP_RECTS | 170 #ifdef CHECK_CLIP_RECTS |
| 166 respectOverflowClip = IgnoreOverflowClip; | 171 respectOverflowClip = IgnoreOverflowClip; |
| 167 #endif | 172 #endif |
| 168 } | 173 } |
| 169 | 174 |
| 170 #ifdef CHECK_CLIP_RECTS | 175 #ifdef CHECK_CLIP_RECTS |
| 171 ClipRects& oldClipRects = | 176 ClipRects& oldClipRects = |
| 172 paintLayer.clipper(PaintLayer::DoNotUseGeometryMapper) | 177 paintLayer.clipper(PaintLayer::DoNotUseGeometryMapper) |
| 173 .paintingClipRects(&ancestorTransformedOrRootPaintLayer, | 178 .paintingClipRects(&ancestorTransformedOrRootPaintLayer, |
| 174 respectOverflowClip, LayoutSize()); | 179 respectOverflowClip, LayoutSize()); |
| 175 #endif | 180 #endif |
| 176 | 181 |
| 177 bool hasClip = false; | 182 bool hasClip = false; |
| 178 RefPtr<ClipRects> clipRects = ClipRects::create(); | 183 RefPtr<ClipRects> clipRects = ClipRects::create(); |
| 179 const LayoutPoint& ancestorPaintOffset = | 184 const LayoutPoint& ancestorPaintOffset = |
| 180 context.ancestorTransformedOrRootPaintLayer->layoutObject().paintOffset(); | 185 context.ancestorTransformedOrRootPaintLayer->layoutObject().paintOffset(); |
| 181 | 186 |
| 182 FloatClipRect clipRect; | 187 FloatClipRect clipRect; |
| 183 computeClipRectForContext(context.treeBuilderContext.current, effect, | 188 const EffectPaintPropertyNode* effect = |
| 189 context.treeBuilderContext->currentEffect; | |
| 190 computeClipRectForContext(context.treeBuilderContext->current, effect, | |
| 184 ancestorState, ancestorPaintOffset, hasClip, | 191 ancestorState, ancestorPaintOffset, hasClip, |
| 185 clipRect); | 192 clipRect); |
| 186 clipRects->setOverflowClipRect(clipRect); | 193 clipRects->setOverflowClipRect(clipRect); |
| 187 #ifdef CHECK_CLIP_RECTS | 194 #ifdef CHECK_CLIP_RECTS |
| 188 CHECK(!hasClip || | 195 CHECK(!hasClip || |
| 189 clipRects->overflowClipRect() == oldClipRects.overflowClipRect()) | 196 clipRects->overflowClipRect() == oldClipRects.overflowClipRect()) |
| 190 << "rect= " << clipRects->overflowClipRect().toString(); | 197 << "rect= " << clipRects->overflowClipRect().toString(); |
| 191 #endif | 198 #endif |
| 192 | 199 |
| 193 computeClipRectForContext(context.treeBuilderContext.fixedPosition, effect, | 200 computeClipRectForContext(context.treeBuilderContext->fixedPosition, effect, |
| 194 ancestorState, ancestorPaintOffset, hasClip, | 201 ancestorState, ancestorPaintOffset, hasClip, |
| 195 clipRect); | 202 clipRect); |
| 196 clipRects->setFixedClipRect(clipRect); | 203 clipRects->setFixedClipRect(clipRect); |
| 197 #ifdef CHECK_CLIP_RECTS | 204 #ifdef CHECK_CLIP_RECTS |
| 198 CHECK(hasClip || clipRects->fixedClipRect() == oldClipRects.fixedClipRect()) | 205 CHECK(hasClip || clipRects->fixedClipRect() == oldClipRects.fixedClipRect()) |
| 199 << " fixed=" << clipRects->fixedClipRect().toString(); | 206 << " fixed=" << clipRects->fixedClipRect().toString(); |
| 200 #endif | 207 #endif |
| 201 | 208 |
| 202 computeClipRectForContext(context.treeBuilderContext.absolutePosition, effect, | 209 computeClipRectForContext(context.treeBuilderContext->absolutePosition, |
| 203 ancestorState, ancestorPaintOffset, hasClip, | 210 effect, ancestorState, ancestorPaintOffset, hasClip, |
| 204 clipRect); | 211 clipRect); |
| 205 clipRects->setPosClipRect(clipRect); | 212 clipRects->setPosClipRect(clipRect); |
| 206 #ifdef CHECK_CLIP_RECTS | 213 #ifdef CHECK_CLIP_RECTS |
| 207 CHECK(!hasClip || clipRects->posClipRect() == oldClipRects.posClipRect()) | 214 CHECK(!hasClip || clipRects->posClipRect() == oldClipRects.posClipRect()) |
| 208 << " abs=" << clipRects->posClipRect().toString(); | 215 << " abs=" << clipRects->posClipRect().toString(); |
| 209 #endif | 216 #endif |
| 210 | 217 |
| 211 ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); | 218 ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); |
| 212 | 219 |
| 213 if (!previousClipRects || *clipRects != *previousClipRects) { | 220 if (!previousClipRects || *clipRects != *previousClipRects) { |
| 214 paintLayer.setNeedsRepaint(); | 221 paintLayer.setNeedsRepaint(); |
| 215 paintLayer.setPreviousPaintPhaseDescendantOutlinesEmpty(false); | 222 paintLayer.setPreviousPaintPhaseDescendantOutlinesEmpty(false); |
| 216 paintLayer.setPreviousPaintPhaseFloatEmpty(false); | 223 paintLayer.setPreviousPaintPhaseFloatEmpty(false); |
| 217 paintLayer.setPreviousPaintPhaseDescendantBlockBackgroundsEmpty(false); | 224 paintLayer.setPreviousPaintPhaseDescendantBlockBackgroundsEmpty(false); |
| 218 // All subsequences which are contained below this paintLayer must also | 225 // All subsequences which are contained below this paintLayer must also |
| 219 // be checked. | 226 // be checked. |
| 220 context.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= | 227 context.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= |
| 221 PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate; | 228 PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate; |
| 222 } | 229 } |
| 223 | 230 |
| 224 paintLayer.setPreviousPaintingClipRects(*clipRects); | 231 paintLayer.setPreviousPaintingClipRects(*clipRects); |
| 225 } | 232 } |
| 226 | 233 |
| 227 bool PrePaintTreeWalk::shouldEndWalkBefore( | 234 bool PrePaintTreeWalk::shouldEndWalkBefore( |
| 228 const LayoutObject& object, | 235 const LayoutObject& object, |
| 229 const PrePaintTreeWalkContext& context) { | 236 const PrePaintTreeWalkContext& context) { |
| 230 return ( | 237 return ( |
| 231 !object.needsPaintPropertyUpdate() && | 238 !object.needsPaintPropertyUpdate() && |
| 232 !object.descendantNeedsPaintPropertyUpdate() && | 239 !object.descendantNeedsPaintPropertyUpdate() && |
| 233 !context.treeBuilderContext.forceSubtreeUpdate && | 240 !context.treeBuilderContext->forceSubtreeUpdate && |
| 234 !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && | 241 !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && |
| 235 !object | 242 !object |
| 236 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState()) ; | 243 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState()) ; |
| 237 } | 244 } |
| 238 | 245 |
| 239 void PrePaintTreeWalk::walk(const LayoutObject& object, | 246 void PrePaintTreeWalk::walk(const LayoutObject& object, |
| 240 const PrePaintTreeWalkContext& parentContext) { | 247 const PrePaintTreeWalkContext& parentContext) { |
| 241 if (shouldEndWalkBefore(object, parentContext)) | 248 if (shouldEndWalkBefore(object, parentContext)) |
| 242 return; | 249 return; |
| 243 | 250 |
| 244 // PrePaintTreeWalkContext is large and can lead to stack overflows when | 251 PrePaintTreeWalkContext context(parentContext); |
| 245 // recursion is deep so this context object is allocated on the heap. | |
| 246 // See: https://crbug.com/698653. | |
| 247 std::unique_ptr<PrePaintTreeWalkContext> context = | |
| 248 WTF::wrapUnique(new PrePaintTreeWalkContext(parentContext)); | |
| 249 | 252 |
| 250 // This must happen before updatePropertiesForSelf, because the latter reads | 253 // This must happen before updatePropertiesForSelf, because the latter reads |
| 251 // some of the state computed here. | 254 // some of the state computed here. |
| 252 updateAuxiliaryObjectProperties(object, *context); | 255 updateAuxiliaryObjectProperties(object, context); |
| 253 | 256 |
| 254 m_propertyTreeBuilder.updatePropertiesForSelf(object, | 257 m_propertyTreeBuilder.updatePropertiesForSelf(object, |
| 255 context->treeBuilderContext); | 258 *context.treeBuilderContext); |
| 256 m_paintInvalidator.invalidatePaintIfNeeded(object, | 259 m_paintInvalidator.invalidatePaintIfNeeded(object, |
| 257 context->paintInvalidatorContext); | 260 context.paintInvalidatorContext); |
| 258 m_propertyTreeBuilder.updatePropertiesForChildren( | 261 m_propertyTreeBuilder.updatePropertiesForChildren( |
| 259 object, context->treeBuilderContext); | 262 object, *context.treeBuilderContext); |
| 260 | 263 |
| 261 invalidatePaintLayerOptimizationsIfNeeded(object, *context); | 264 invalidatePaintLayerOptimizationsIfNeeded(object, context); |
| 262 | 265 |
| 263 for (const LayoutObject* child = object.slowFirstChild(); child; | 266 for (const LayoutObject* child = object.slowFirstChild(); child; |
| 264 child = child->nextSibling()) { | 267 child = child->nextSibling()) { |
| 265 if (child->isLayoutMultiColumnSpannerPlaceholder()) { | 268 if (child->isLayoutMultiColumnSpannerPlaceholder()) { |
| 266 child->getMutableForPainting().clearPaintFlags(); | 269 child->getMutableForPainting().clearPaintFlags(); |
| 267 continue; | 270 continue; |
| 268 } | 271 } |
| 269 walk(*child, *context); | 272 walk(*child, context); |
| 270 } | 273 } |
| 271 | 274 |
| 272 if (object.isLayoutPart()) { | 275 if (object.isLayoutPart()) { |
| 273 const LayoutPart& layoutPart = toLayoutPart(object); | 276 const LayoutPart& layoutPart = toLayoutPart(object); |
| 274 FrameViewBase* frameViewBase = layoutPart.frameViewBase(); | 277 FrameViewBase* frameViewBase = layoutPart.frameViewBase(); |
| 275 if (frameViewBase && frameViewBase->isFrameView()) { | 278 if (frameViewBase && frameViewBase->isFrameView()) { |
| 276 context->treeBuilderContext.current.paintOffset += | 279 context.treeBuilderContext->current.paintOffset += |
| 277 layoutPart.replacedContentRect().location() - | 280 layoutPart.replacedContentRect().location() - |
| 278 frameViewBase->frameRect().location(); | 281 frameViewBase->frameRect().location(); |
| 279 context->treeBuilderContext.current.paintOffset = | 282 context.treeBuilderContext->current.paintOffset = |
| 280 roundedIntPoint(context->treeBuilderContext.current.paintOffset); | 283 roundedIntPoint(context.treeBuilderContext->current.paintOffset); |
| 281 walk(*toFrameView(frameViewBase), *context); | 284 walk(*toFrameView(frameViewBase), context); |
| 282 } | 285 } |
| 283 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). | 286 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). |
| 284 } | 287 } |
| 285 | 288 |
| 286 object.getMutableForPainting().clearPaintFlags(); | 289 object.getMutableForPainting().clearPaintFlags(); |
| 287 } | 290 } |
| 288 | 291 |
| 289 } // namespace blink | 292 } // namespace blink |
| OLD | NEW |