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" |
(...skipping 27 matching lines...) Expand all Loading... |
38 DocumentLifecycle::InPrePaint); | 38 DocumentLifecycle::InPrePaint); |
39 | 39 |
40 PrePaintTreeWalkContext initialContext; | 40 PrePaintTreeWalkContext initialContext; |
41 initialContext.treeBuilderContext = | 41 initialContext.treeBuilderContext = |
42 m_propertyTreeBuilder.setupInitialContext(); | 42 m_propertyTreeBuilder.setupInitialContext(); |
43 walk(rootFrame, initialContext); | 43 walk(rootFrame, initialContext); |
44 m_paintInvalidator.processPendingDelayedPaintInvalidations(); | 44 m_paintInvalidator.processPendingDelayedPaintInvalidations(); |
45 } | 45 } |
46 | 46 |
47 bool PrePaintTreeWalk::walk(FrameView& frameView, | 47 bool PrePaintTreeWalk::walk(FrameView& frameView, |
48 const PrePaintTreeWalkContext& context) { | 48 const PrePaintTreeWalkContext& parentContext) { |
49 if (frameView.shouldThrottleRendering()) { | 49 if (frameView.shouldThrottleRendering()) { |
50 // The walk was interrupted by throttled rendering so this subtree was not | 50 // The walk was interrupted by throttled rendering so this subtree was not |
51 // fully updated. | 51 // fully updated. |
52 return false; | 52 return false; |
53 } | 53 } |
54 | 54 |
55 PrePaintTreeWalkContext localContext(context); | 55 PrePaintTreeWalkContext context(parentContext); |
56 | 56 |
57 if (frameView.shouldInvalidateAllPaintAndPaintProperties()) { | 57 if (frameView.shouldInvalidateAllPaintAndPaintProperties()) { |
58 localContext.treeBuilderContext.forceSubtreeUpdate = true; | 58 context.treeBuilderContext.forceSubtreeUpdate = true; |
59 localContext.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= | 59 context.paintInvalidatorContext.forcedSubtreeInvalidationFlags |= |
60 PaintInvalidatorContext::ForcedWholeTreeFullInvalidation; | 60 PaintInvalidatorContext::ForcedWholeTreeFullInvalidation; |
61 frameView.clearShouldInvalidateAllPaintAndPaintProperties(); | 61 frameView.clearShouldInvalidateAllPaintAndPaintProperties(); |
62 } | 62 } |
63 | 63 |
64 m_propertyTreeBuilder.updateProperties(frameView, | 64 m_propertyTreeBuilder.updateProperties(frameView, context.treeBuilderContext); |
65 localContext.treeBuilderContext); | 65 m_paintInvalidator.invalidatePaintIfNeeded(frameView, |
66 m_paintInvalidator.invalidatePaintIfNeeded( | 66 context.paintInvalidatorContext); |
67 frameView, localContext.paintInvalidatorContext); | |
68 | 67 |
69 LayoutView* view = frameView.layoutView(); | 68 LayoutView* view = frameView.layoutView(); |
70 bool descendantsFullyUpdated = view ? walk(*view, localContext) : true; | 69 bool descendantsFullyUpdated = view ? walk(*view, context) : true; |
71 if (descendantsFullyUpdated) { | 70 if (descendantsFullyUpdated) { |
72 #if DCHECK_IS_ON() | 71 #if DCHECK_IS_ON() |
73 frameView.layoutView()->assertSubtreeClearedPaintInvalidationFlags(); | 72 frameView.layoutView()->assertSubtreeClearedPaintInvalidationFlags(); |
74 #endif | 73 #endif |
75 // If descendants were not fully updated, do not clear flags. During the | 74 // If descendants were not fully updated, do not clear flags. During the |
76 // next PrePaintTreeWalk, these flags will be used again. | 75 // next PrePaintTreeWalk, these flags will be used again. |
77 frameView.clearNeedsPaintPropertyUpdate(); | 76 frameView.clearNeedsPaintPropertyUpdate(); |
78 } | 77 } |
79 return descendantsFullyUpdated; | 78 return descendantsFullyUpdated; |
80 } | 79 } |
81 | 80 |
82 static void updateAuxiliaryObjectProperties( | 81 static void updateAuxiliaryObjectProperties(const LayoutObject& object, |
83 const LayoutObject& object, | 82 PrePaintTreeWalkContext& context) { |
84 PrePaintTreeWalkContext& localContext) { | |
85 PaintLayer* paintLayer = nullptr; | 83 PaintLayer* paintLayer = nullptr; |
86 | 84 |
87 if (object.isBoxModelObject() && object.hasLayer()) | 85 if (object.isBoxModelObject() && object.hasLayer()) |
88 paintLayer = object.enclosingLayer(); | 86 paintLayer = object.enclosingLayer(); |
89 | 87 |
90 if (paintLayer) { | 88 if (paintLayer) { |
91 paintLayer->updateAncestorOverflowLayer( | 89 paintLayer->updateAncestorOverflowLayer(context.ancestorOverflowPaintLayer); |
92 localContext.ancestorOverflowPaintLayer); | |
93 } | 90 } |
94 | 91 |
95 if (object.styleRef().position() == StickyPosition && paintLayer) { | 92 if (object.styleRef().position() == StickyPosition && paintLayer) { |
96 paintLayer->layoutObject()->updateStickyPositionConstraints(); | 93 paintLayer->layoutObject()->updateStickyPositionConstraints(); |
97 | 94 |
98 // Sticky position constraints and ancestor overflow scroller affect | 95 // Sticky position constraints and ancestor overflow scroller affect |
99 // the sticky layer position, so we need to update it again here. | 96 // the sticky layer position, so we need to update it again here. |
100 // TODO(flackr): This should be refactored in the future to be clearer | 97 // TODO(flackr): This should be refactored in the future to be clearer |
101 // (i.e. update layer position and ancestor inputs updates in the | 98 // (i.e. update layer position and ancestor inputs updates in the |
102 // same walk) | 99 // same walk) |
103 paintLayer->updateLayerPosition(); | 100 paintLayer->updateLayerPosition(); |
104 } | 101 } |
105 | 102 |
106 if (object.hasOverflowClip() || (paintLayer && paintLayer->isRootLayer())) { | 103 if (object.hasOverflowClip() || (paintLayer && paintLayer->isRootLayer())) { |
107 DCHECK(paintLayer); | 104 DCHECK(paintLayer); |
108 localContext.ancestorOverflowPaintLayer = paintLayer; | 105 context.ancestorOverflowPaintLayer = paintLayer; |
109 } | 106 } |
110 } | 107 } |
111 | 108 |
112 bool PrePaintTreeWalk::walk(const LayoutObject& object, | 109 bool PrePaintTreeWalk::walk(const LayoutObject& object, |
113 const PrePaintTreeWalkContext& context) { | 110 const PrePaintTreeWalkContext& parentContext) { |
114 PrePaintTreeWalkContext localContext(context); | 111 PrePaintTreeWalkContext context(parentContext); |
115 | 112 |
116 // TODO(pdr): Ensure multi column works with incremental property tree | 113 // TODO(pdr): Ensure multi column works with incremental property tree |
117 // construction. | 114 // construction. |
118 if (object.isLayoutMultiColumnSpannerPlaceholder()) { | 115 if (object.isLayoutMultiColumnSpannerPlaceholder()) { |
119 // Walk multi-column spanner as if it replaces the placeholder. | 116 // Walk multi-column spanner as if it replaces the placeholder. |
120 // Set the flag so that the tree builder can specially handle out-of-flow | 117 // Set the flag so that the tree builder can specially handle out-of-flow |
121 // positioned descendants if their containers are between the multi-column | 118 // positioned descendants if their containers are between the multi-column |
122 // container and the spanner. See PaintPropertyTreeBuilder for details. | 119 // container and the spanner. See PaintPropertyTreeBuilder for details. |
123 localContext.treeBuilderContext.isUnderMultiColumnSpanner = true; | 120 context.treeBuilderContext.isUnderMultiColumnSpanner = true; |
124 const auto& placeholder = toLayoutMultiColumnSpannerPlaceholder(object); | 121 const auto& placeholder = toLayoutMultiColumnSpannerPlaceholder(object); |
125 bool descendantsFullyUpdated = | 122 bool descendantsFullyUpdated = |
126 walk(*placeholder.layoutObjectInFlowThread(), localContext); | 123 walk(*placeholder.layoutObjectInFlowThread(), context); |
127 if (descendantsFullyUpdated) { | 124 if (descendantsFullyUpdated) { |
128 // If descendants were not fully updated, do not clear flags. During the | 125 // If descendants were not fully updated, do not clear flags. During the |
129 // next PrePaintTreeWalk, these flags will be used again. | 126 // next PrePaintTreeWalk, these flags will be used again. |
130 object.getMutableForPainting().clearPaintFlags(); | 127 object.getMutableForPainting().clearPaintFlags(); |
131 } | 128 } |
132 return descendantsFullyUpdated; | 129 return descendantsFullyUpdated; |
133 } | 130 } |
134 | 131 |
135 // This must happen before updateContextForBoxPosition, because the | 132 // This must happen before updateContextForBoxPosition, because the |
136 // latter reads some of the state computed uere. | 133 // latter reads some of the state computed uere. |
137 updateAuxiliaryObjectProperties(object, localContext); | 134 updateAuxiliaryObjectProperties(object, context); |
138 | 135 |
139 // Ensure the current context takes into account the box position. This can | 136 // Ensure the current context takes into account the box's position. This can |
140 // change the current context's paint offset so it must precede the paint | 137 // force a subtree update due to paint offset changes and must precede any |
141 // offset property update check. | 138 // early out from the treewalk. |
142 m_propertyTreeBuilder.updateContextForBoxPosition( | 139 m_propertyTreeBuilder.updateContextForBoxPosition(object, |
143 object, localContext.treeBuilderContext); | 140 context.treeBuilderContext); |
144 // Many paint properties depend on paint offset so we force an update of | |
145 // properties if the paint offset changes. | |
146 if (object.previousPaintOffset() != | |
147 localContext.treeBuilderContext.current.paintOffset) { | |
148 object.getMutableForPainting().setNeedsPaintPropertyUpdate(); | |
149 } | |
150 | 141 |
151 // Early out from the treewalk if possible. | 142 // Early out from the treewalk if possible. |
152 if (!object.needsPaintPropertyUpdate() && | 143 if (!object.needsPaintPropertyUpdate() && |
153 !object.descendantNeedsPaintPropertyUpdate() && | 144 !object.descendantNeedsPaintPropertyUpdate() && |
154 !localContext.treeBuilderContext.forceSubtreeUpdate && | 145 !context.treeBuilderContext.forceSubtreeUpdate && |
155 !localContext.paintInvalidatorContext.forcedSubtreeInvalidationFlags && | 146 !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && |
156 !object | 147 !object |
157 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState())
{ | 148 .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState())
{ |
158 // Even though the subtree was not walked, we know that a walk will not | 149 // Even though the subtree was not walked, we know that a walk will not |
159 // change anything and can return true as if the subtree was fully updated. | 150 // change anything and can return true as if the subtree was fully updated. |
160 return true; | 151 return true; |
161 } | 152 } |
162 | 153 |
163 m_propertyTreeBuilder.updatePropertiesForSelf( | 154 m_propertyTreeBuilder.updatePropertiesForSelf(object, |
164 object, localContext.treeBuilderContext); | 155 context.treeBuilderContext); |
165 m_paintInvalidator.invalidatePaintIfNeeded( | 156 m_paintInvalidator.invalidatePaintIfNeeded(object, |
166 object, localContext.paintInvalidatorContext); | 157 context.paintInvalidatorContext); |
167 m_propertyTreeBuilder.updatePropertiesForChildren( | 158 m_propertyTreeBuilder.updatePropertiesForChildren(object, |
168 object, localContext.treeBuilderContext); | 159 context.treeBuilderContext); |
169 | 160 |
170 bool descendantsFullyUpdated = true; | 161 bool descendantsFullyUpdated = true; |
171 for (const LayoutObject* child = object.slowFirstChild(); child; | 162 for (const LayoutObject* child = object.slowFirstChild(); child; |
172 child = child->nextSibling()) { | 163 child = child->nextSibling()) { |
173 // Column spanners are walked through their placeholders. See above. | 164 // Column spanners are walked through their placeholders. See above. |
174 if (child->isColumnSpanAll()) | 165 if (child->isColumnSpanAll()) |
175 continue; | 166 continue; |
176 bool childFullyUpdated = walk(*child, localContext); | 167 bool childFullyUpdated = walk(*child, context); |
177 if (!childFullyUpdated) | 168 if (!childFullyUpdated) |
178 descendantsFullyUpdated = false; | 169 descendantsFullyUpdated = false; |
179 } | 170 } |
180 | 171 |
181 if (object.isLayoutPart()) { | 172 if (object.isLayoutPart()) { |
182 const LayoutPart& layoutPart = toLayoutPart(object); | 173 const LayoutPart& layoutPart = toLayoutPart(object); |
183 Widget* widget = layoutPart.widget(); | 174 Widget* widget = layoutPart.widget(); |
184 if (widget && widget->isFrameView()) { | 175 if (widget && widget->isFrameView()) { |
185 localContext.treeBuilderContext.current.paintOffset += | 176 context.treeBuilderContext.current.paintOffset += |
186 layoutPart.replacedContentRect().location() - | 177 layoutPart.replacedContentRect().location() - |
187 widget->frameRect().location(); | 178 widget->frameRect().location(); |
188 localContext.treeBuilderContext.current.paintOffset = | 179 context.treeBuilderContext.current.paintOffset = |
189 roundedIntPoint(localContext.treeBuilderContext.current.paintOffset); | 180 roundedIntPoint(context.treeBuilderContext.current.paintOffset); |
190 bool frameFullyUpdated = walk(*toFrameView(widget), localContext); | 181 bool frameFullyUpdated = walk(*toFrameView(widget), context); |
191 if (!frameFullyUpdated) | 182 if (!frameFullyUpdated) |
192 descendantsFullyUpdated = false; | 183 descendantsFullyUpdated = false; |
193 } | 184 } |
194 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). | 185 // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). |
195 } | 186 } |
196 | 187 |
197 if (descendantsFullyUpdated) { | 188 if (descendantsFullyUpdated) { |
198 // If descendants were not updated, do not clear flags. During the next | 189 // If descendants were not updated, do not clear flags. During the next |
199 // PrePaintTreeWalk, these flags will be used again. | 190 // PrePaintTreeWalk, these flags will be used again. |
200 object.getMutableForPainting().clearPaintFlags(); | 191 object.getMutableForPainting().clearPaintFlags(); |
201 } | 192 } |
202 return descendantsFullyUpdated; | 193 return descendantsFullyUpdated; |
203 } | 194 } |
204 | 195 |
205 } // namespace blink | 196 } // namespace blink |
OLD | NEW |