OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/BoxPaintInvalidator.h" | 5 #include "core/paint/BoxPaintInvalidator.h" |
6 | 6 |
7 #include "core/frame/Settings.h" | 7 #include "core/frame/Settings.h" |
8 #include "core/layout/LayoutView.h" | 8 #include "core/layout/LayoutView.h" |
9 #include "core/layout/compositing/CompositedLayerMapping.h" | |
9 #include "core/paint/ObjectPaintInvalidator.h" | 10 #include "core/paint/ObjectPaintInvalidator.h" |
10 #include "core/paint/PaintInvalidator.h" | 11 #include "core/paint/PaintInvalidator.h" |
11 #include "core/paint/PaintLayer.h" | 12 #include "core/paint/PaintLayer.h" |
12 #include "core/paint/PaintLayerScrollableArea.h" | 13 #include "core/paint/PaintLayerScrollableArea.h" |
13 #include "platform/geometry/LayoutRect.h" | 14 #include "platform/geometry/LayoutRect.h" |
14 | 15 |
15 namespace blink { | 16 namespace blink { |
16 | 17 |
17 struct PreviousBoxGeometries { | 18 struct PreviousBoxGeometries { |
18 LayoutSize borderBoxSize; | 19 LayoutSize borderBoxSize; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 newSize.width(), delta + extraHeight); | 62 newSize.width(), delta + extraHeight); |
62 } | 63 } |
63 if (delta < 0) { | 64 if (delta < 0) { |
64 return LayoutRect(location.x(), | 65 return LayoutRect(location.x(), |
65 location.y() + newSize.height() - extraHeight, | 66 location.y() + newSize.height() - extraHeight, |
66 oldSize.width(), -delta + extraHeight); | 67 oldSize.width(), -delta + extraHeight); |
67 } | 68 } |
68 return LayoutRect(); | 69 return LayoutRect(); |
69 } | 70 } |
70 | 71 |
71 bool BoxPaintInvalidator::incrementallyInvalidatePaint() { | 72 bool BoxPaintInvalidator::incrementallyInvalidatePaint( |
72 LayoutRect rightDelta; | 73 PaintInvalidationReason reason, |
73 LayoutRect bottomDelta; | 74 const LayoutRect& oldRect, |
74 if (m_box.isLayoutView() && | 75 const LayoutRect& newRect) { |
75 !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { | 76 DCHECK(oldRect.location() == newRect.location()); |
76 // This corresponds to the special case in computePaintInvalidationReason() | 77 LayoutRect rightDelta = computeRightDelta( |
77 // for LayoutView in non-rootLayerScrolling mode. | 78 newRect.location(), oldRect.size(), newRect.size(), |
78 DCHECK(m_context.oldVisualRect.location() == | 79 reason == PaintInvalidationIncremental ? m_box.borderRight() : 0); |
79 m_context.newVisualRect.location()); | 80 LayoutRect bottomDelta = computeBottomDelta( |
80 rightDelta = computeRightDelta(m_context.newVisualRect.location(), | 81 newRect.location(), oldRect.size(), newRect.size(), |
81 m_context.oldVisualRect.size(), | 82 reason == PaintInvalidationIncremental ? m_box.borderBottom() : 0); |
82 m_context.newVisualRect.size(), 0); | |
83 bottomDelta = computeBottomDelta(m_context.newVisualRect.location(), | |
84 m_context.oldVisualRect.size(), | |
85 m_context.newVisualRect.size(), 0); | |
86 } else { | |
87 LayoutSize oldBorderBoxSize = | |
88 previousBorderBoxSize(m_context.oldVisualRect.size()); | |
89 LayoutSize newBorderBoxSize = m_box.size(); | |
90 DCHECK(m_context.oldLocation == m_context.newLocation); | |
91 rightDelta = computeRightDelta(m_context.newLocation, oldBorderBoxSize, | |
92 newBorderBoxSize, m_box.borderRight()); | |
93 bottomDelta = computeBottomDelta(m_context.newLocation, oldBorderBoxSize, | |
94 newBorderBoxSize, m_box.borderBottom()); | |
95 } | |
96 | 83 |
97 if (rightDelta.isEmpty() && bottomDelta.isEmpty()) | 84 if (rightDelta.isEmpty() && bottomDelta.isEmpty()) |
98 return false; | 85 return false; |
99 | 86 |
100 ObjectPaintInvalidator objectPaintInvalidator(m_box); | 87 ObjectPaintInvalidator objectPaintInvalidator(m_box); |
101 objectPaintInvalidator.invalidatePaintUsingContainer( | 88 objectPaintInvalidator.invalidatePaintUsingContainer( |
102 *m_context.paintInvalidationContainer, rightDelta, | 89 *m_context.paintInvalidationContainer, rightDelta, reason); |
103 PaintInvalidationIncremental); | 90 if (rightDelta != bottomDelta) { |
chrishtr
2016/11/17 00:12:54
Why this new conditional?
Xianzhu
2016/11/17 17:37:52
This is avoid duplicated invalidation if oldRect o
| |
104 objectPaintInvalidator.invalidatePaintUsingContainer( | 91 objectPaintInvalidator.invalidatePaintUsingContainer( |
105 *m_context.paintInvalidationContainer, bottomDelta, | 92 *m_context.paintInvalidationContainer, bottomDelta, reason); |
106 PaintInvalidationIncremental); | 93 } |
107 return true; | 94 return true; |
108 } | 95 } |
109 | 96 |
110 PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { | 97 PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { |
111 PaintInvalidationReason reason = | 98 PaintInvalidationReason reason = |
112 ObjectPaintInvalidatorWithContext(m_box, m_context) | 99 ObjectPaintInvalidatorWithContext(m_box, m_context) |
113 .computePaintInvalidationReason(); | 100 .computePaintInvalidationReason(); |
114 | 101 |
115 if (reason != PaintInvalidationIncremental) | 102 if (reason != PaintInvalidationIncremental) |
116 return reason; | 103 return reason; |
(...skipping 12 matching lines...) Expand all Loading... | |
129 } | 116 } |
130 | 117 |
131 const ComputedStyle& style = m_box.styleRef(); | 118 const ComputedStyle& style = m_box.styleRef(); |
132 | 119 |
133 if ((style.backgroundLayers().thisOrNextLayersUseContentBox() || | 120 if ((style.backgroundLayers().thisOrNextLayersUseContentBox() || |
134 style.maskLayers().thisOrNextLayersUseContentBox() || | 121 style.maskLayers().thisOrNextLayersUseContentBox() || |
135 style.boxSizing() == BoxSizingBorderBox) && | 122 style.boxSizing() == BoxSizingBorderBox) && |
136 previousContentBoxRect() != m_box.contentBoxRect()) | 123 previousContentBoxRect() != m_box.contentBoxRect()) |
137 return PaintInvalidationContentBoxChange; | 124 return PaintInvalidationContentBoxChange; |
138 | 125 |
139 if (style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() && | 126 LayoutSize oldBorderBoxSize = previousBorderBoxSize(); |
140 previousLayoutOverflowRect() != m_box.layoutOverflowRect()) | |
141 return PaintInvalidationLayoutOverflowBoxChange; | |
142 | |
143 LayoutSize oldBorderBoxSize = | |
144 previousBorderBoxSize(m_context.oldVisualRect.size()); | |
145 LayoutSize newBorderBoxSize = m_box.size(); | 127 LayoutSize newBorderBoxSize = m_box.size(); |
146 bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize; | 128 bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize; |
147 | |
148 if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect) | 129 if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect) |
149 return PaintInvalidationNone; | 130 return PaintInvalidationNone; |
150 | 131 |
151 // If either border box changed or bounds changed, and old or new border box | 132 // If either border box changed or bounds changed, and old or new border box |
152 // doesn't equal old or new bounds, incremental invalidation is not | 133 // doesn't equal old or new bounds, incremental invalidation is not |
153 // applicable. This captures the following cases: | 134 // applicable. This captures the following cases: |
154 // - pixel snapping of paint invalidation bounds, | 135 // - pixel snapping of paint invalidation bounds, |
155 // - scale, rotate, skew etc. transforms, | 136 // - scale, rotate, skew etc. transforms, |
156 // - visual overflows. | 137 // - visual overflows. |
157 if (m_context.oldVisualRect != | 138 if (m_context.oldVisualRect != |
(...skipping 17 matching lines...) Expand all Loading... | |
175 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && | 156 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && |
176 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) | 157 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) |
177 return PaintInvalidationBorderBoxChange; | 158 return PaintInvalidationBorderBoxChange; |
178 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && | 159 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && |
179 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) | 160 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) |
180 return PaintInvalidationBorderBoxChange; | 161 return PaintInvalidationBorderBoxChange; |
181 | 162 |
182 return PaintInvalidationIncremental; | 163 return PaintInvalidationIncremental; |
183 } | 164 } |
184 | 165 |
166 // If true, the background geometry will depend on the layout overflow rect, | |
167 // even if it doesn't paint on the scrolling contents layer. | |
168 bool BoxPaintInvalidator::backgroundPositionsInLayoutOverflowRect() { | |
chrishtr
2016/11/17 00:12:54
backgroundGeometryDependsOnLayoutOverflowRect() ?
Xianzhu
2016/11/17 17:37:52
This name is much better. Done.
| |
169 return m_box.styleRef() | |
170 .backgroundLayers() | |
171 .thisOrNextLayersHaveLocalAttachment(); | |
172 } | |
173 | |
174 // Background positioning in layout overflow rect doesn't mean it will | |
175 // paint onto the scrolling contents layer because some conditions prevent | |
176 // it from that. We may also treat non-local solid color backgrounds as local | |
177 // and paint onto the scrolling contents layer. | |
178 // See PaintLayer::canPaintBackgroundOntoScrollingContentsLayer(). | |
179 bool BoxPaintInvalidator::backgroundPaintsOntoScrollingContentsLayer() { | |
180 if (!m_box.hasLayer()) | |
181 return false; | |
182 if (auto* mapping = m_box.layer()->compositedLayerMapping()) | |
183 return mapping->backgroundPaintsOntoScrollingContentsLayer(); | |
184 return false; | |
185 } | |
186 | |
187 bool BoxPaintInvalidator::shouldFullyInvalidateBackgroundOnLayoutOverflowChange( | |
188 const LayoutRect& oldLayoutOverflow, | |
189 const LayoutRect& newLayoutOverflow) { | |
190 DCHECK(oldLayoutOverflow != newLayoutOverflow); | |
191 if (newLayoutOverflow.isEmpty() || oldLayoutOverflow.isEmpty()) | |
192 return true; | |
193 if (newLayoutOverflow.location() != oldLayoutOverflow.location()) | |
194 return true; | |
195 if (newLayoutOverflow.width() != oldLayoutOverflow.width() && | |
196 m_box.mustInvalidateFillLayersPaintOnHeightChange( | |
197 m_box.styleRef().backgroundLayers())) | |
198 return true; | |
199 if (newLayoutOverflow.height() != oldLayoutOverflow.height() && | |
200 m_box.mustInvalidateFillLayersPaintOnHeightChange( | |
201 m_box.styleRef().backgroundLayers())) | |
202 return true; | |
203 return false; | |
204 } | |
205 | |
206 void BoxPaintInvalidator::invalidateScrollingContentsBackgroundIfNeeded() { | |
207 bool paintsOntoScrollingContentsLayer = | |
208 backgroundPaintsOntoScrollingContentsLayer(); | |
209 if (!paintsOntoScrollingContentsLayer && | |
210 !backgroundPositionsInLayoutOverflowRect()) | |
211 return; | |
212 | |
213 const LayoutRect& oldLayoutOverflow = previousLayoutOverflowRect(); | |
214 LayoutRect newLayoutOverflow = m_box.layoutOverflowRect(); | |
215 | |
216 bool shouldFullyInvalidateOnScrollingContentsLayer = false; | |
217 if (m_box.backgroundChangedSinceLastPaintInvalidation()) { | |
218 if (!paintsOntoScrollingContentsLayer) { | |
219 // The box should have been set needing full invalidation on style change. | |
220 DCHECK(m_box.shouldDoFullPaintInvalidation()); | |
221 return; | |
222 } | |
223 shouldFullyInvalidateOnScrollingContentsLayer = true; | |
224 } else { | |
225 // Check change of layout overflow in which the background is positioned. | |
226 if (!m_box.hasPreviousBoxGeometries() || | |
227 newLayoutOverflow == oldLayoutOverflow) | |
228 return; | |
229 if (!paintsOntoScrollingContentsLayer) { | |
230 if (m_box.isLayoutView() && | |
231 !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) | |
232 return; | |
233 if (shouldFullyInvalidateBackgroundOnLayoutOverflowChange( | |
234 oldLayoutOverflow, newLayoutOverflow)) { | |
235 m_box.getMutableForPainting().setShouldDoFullPaintInvalidation( | |
236 PaintInvalidationLayoutOverflowBoxChange); | |
237 } | |
238 return; | |
239 } | |
240 shouldFullyInvalidateOnScrollingContentsLayer = | |
241 shouldFullyInvalidateBackgroundOnLayoutOverflowChange( | |
242 oldLayoutOverflow, newLayoutOverflow); | |
243 } | |
244 | |
245 if (shouldFullyInvalidateOnScrollingContentsLayer) { | |
246 ObjectPaintInvalidatorWithContext(m_box, m_context) | |
247 .fullyInvalidatePaint( | |
248 PaintInvalidationBackgroundOnScrollingContentsLayer, | |
249 oldLayoutOverflow, newLayoutOverflow); | |
250 } else { | |
251 incrementallyInvalidatePaint( | |
252 PaintInvalidationBackgroundOnScrollingContentsLayer, oldLayoutOverflow, | |
253 newLayoutOverflow); | |
254 } | |
255 | |
256 m_context.paintingLayer->setNeedsRepaint(); | |
257 // Currently we use CompositedLayerMapping as the DisplayItemClient to paint | |
258 // background on the scrolling contents layer. | |
259 ObjectPaintInvalidator(m_box).invalidateDisplayItemClient( | |
260 *m_box.layer()->compositedLayerMapping()->scrollingContentsLayer(), | |
261 PaintInvalidationBackgroundOnScrollingContentsLayer); | |
262 } | |
263 | |
185 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { | 264 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { |
265 invalidateScrollingContentsBackgroundIfNeeded(); | |
266 | |
186 PaintInvalidationReason reason = computePaintInvalidationReason(); | 267 PaintInvalidationReason reason = computePaintInvalidationReason(); |
187 if (reason == PaintInvalidationIncremental) { | 268 if (reason == PaintInvalidationIncremental) { |
188 if (incrementallyInvalidatePaint()) { | 269 bool invalidated; |
270 if (m_box.isLayoutView() && | |
271 !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { | |
272 invalidated = incrementallyInvalidatePaint( | |
273 reason, m_context.oldVisualRect, m_context.newVisualRect); | |
274 } else { | |
275 invalidated = incrementallyInvalidatePaint( | |
276 reason, LayoutRect(m_context.oldLocation, previousBorderBoxSize()), | |
277 LayoutRect(m_context.newLocation, m_box.size())); | |
278 } | |
279 if (invalidated) { | |
189 m_context.paintingLayer->setNeedsRepaint(); | 280 m_context.paintingLayer->setNeedsRepaint(); |
190 m_box.invalidateDisplayItemClients(reason); | 281 m_box.invalidateDisplayItemClients(reason); |
191 } else { | 282 } else { |
192 reason = PaintInvalidationNone; | 283 reason = PaintInvalidationNone; |
193 } | 284 } |
285 | |
194 // Though we have done incremental invalidation, we still need to call | 286 // Though we have done incremental invalidation, we still need to call |
195 // ObjectPaintInvalidator with PaintInvalidationNone to do any other | 287 // ObjectPaintInvalidator with PaintInvalidationNone to do any other |
196 // required operations. | 288 // required operations. |
197 reason = std::max( | 289 reason = std::max( |
198 reason, | 290 reason, |
199 ObjectPaintInvalidatorWithContext(m_box, m_context) | 291 ObjectPaintInvalidatorWithContext(m_box, m_context) |
200 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); | 292 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); |
201 } else { | 293 } else { |
202 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) | 294 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) |
203 .invalidatePaintIfNeededWithComputedReason(reason); | 295 .invalidatePaintIfNeededWithComputedReason(reason); |
(...skipping 26 matching lines...) Expand all Loading... | |
230 return true; | 322 return true; |
231 | 323 |
232 // No need to save old border box size if we can use size of the old paint | 324 // No need to save old border box size if we can use size of the old paint |
233 // rect as the old border box size in the next invalidation. | 325 // rect as the old border box size in the next invalidation. |
234 if (paintInvalidationSize != m_box.size()) | 326 if (paintInvalidationSize != m_box.size()) |
235 return true; | 327 return true; |
236 | 328 |
237 // Background and mask layers can depend on other boxes than border box. See | 329 // Background and mask layers can depend on other boxes than border box. See |
238 // crbug.com/490533 | 330 // crbug.com/490533 |
239 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || | 331 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || |
240 style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() || | 332 style.maskLayers().thisOrNextLayersUseContentBox() || |
241 style.maskLayers().thisOrNextLayersUseContentBox()) | 333 backgroundPositionsInLayoutOverflowRect() || |
334 backgroundPaintsOntoScrollingContentsLayer()) | |
242 return true; | 335 return true; |
243 | 336 |
244 return false; | 337 return false; |
245 } | 338 } |
246 | 339 |
247 void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() { | 340 void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() { |
248 DCHECK(m_box.hasPreviousBoxGeometries() == | 341 DCHECK(m_box.hasPreviousBoxGeometries() == |
249 previousBoxGeometriesMap().contains(&m_box)); | 342 previousBoxGeometriesMap().contains(&m_box)); |
250 if (!needsToSavePreviousBoxGeometries()) { | 343 if (!needsToSavePreviousBoxGeometries()) { |
251 if (m_box.hasPreviousBoxGeometries()) { | 344 if (m_box.hasPreviousBoxGeometries()) { |
252 previousBoxGeometriesMap().remove(&m_box); | 345 previousBoxGeometriesMap().remove(&m_box); |
253 m_box.getMutableForPainting().setHasPreviousBoxGeometries(false); | 346 m_box.getMutableForPainting().setHasPreviousBoxGeometries(false); |
254 } | 347 } |
255 return; | 348 return; |
256 } | 349 } |
257 | 350 |
258 PreviousBoxGeometries Geometries = {m_box.size(), m_box.contentBoxRect(), | 351 PreviousBoxGeometries geometries = {m_box.size(), m_box.contentBoxRect(), |
259 m_box.layoutOverflowRect()}; | 352 m_box.layoutOverflowRect()}; |
260 previousBoxGeometriesMap().set(&m_box, Geometries); | 353 previousBoxGeometriesMap().set(&m_box, geometries); |
261 m_box.getMutableForPainting().setHasPreviousBoxGeometries(true); | 354 m_box.getMutableForPainting().setHasPreviousBoxGeometries(true); |
262 } | 355 } |
263 | 356 |
264 LayoutSize BoxPaintInvalidator::previousBorderBoxSize( | 357 LayoutSize BoxPaintInvalidator::previousBorderBoxSize() { |
265 const LayoutSize& previousVisualRectSize) { | |
266 DCHECK(m_box.hasPreviousBoxGeometries() == | 358 DCHECK(m_box.hasPreviousBoxGeometries() == |
267 previousBoxGeometriesMap().contains(&m_box)); | 359 previousBoxGeometriesMap().contains(&m_box)); |
268 if (m_box.hasPreviousBoxGeometries()) | 360 if (m_box.hasPreviousBoxGeometries()) |
269 return previousBoxGeometriesMap().get(&m_box).borderBoxSize; | 361 return previousBoxGeometriesMap().get(&m_box).borderBoxSize; |
270 | 362 |
271 // We didn't save the old border box size because it was the same as the size | 363 // We didn't save the old border box size because it was the same as the size |
272 // of oldVisualRect. | 364 // of oldVisualRect. |
273 return previousVisualRectSize; | 365 return m_context.oldVisualRect.size(); |
274 } | 366 } |
275 | 367 |
276 LayoutRect BoxPaintInvalidator::previousContentBoxRect() { | 368 LayoutRect BoxPaintInvalidator::previousContentBoxRect() { |
277 DCHECK(m_box.hasPreviousBoxGeometries() == | 369 DCHECK(m_box.hasPreviousBoxGeometries() == |
278 previousBoxGeometriesMap().contains(&m_box)); | 370 previousBoxGeometriesMap().contains(&m_box)); |
279 return m_box.hasPreviousBoxGeometries() | 371 return m_box.hasPreviousBoxGeometries() |
280 ? previousBoxGeometriesMap().get(&m_box).contentBoxRect | 372 ? previousBoxGeometriesMap().get(&m_box).contentBoxRect |
281 : LayoutRect(); | 373 : LayoutRect(); |
282 } | 374 } |
283 | 375 |
284 LayoutRect BoxPaintInvalidator::previousLayoutOverflowRect() { | 376 LayoutRect BoxPaintInvalidator::previousLayoutOverflowRect() { |
285 DCHECK(m_box.hasPreviousBoxGeometries() == | 377 DCHECK(m_box.hasPreviousBoxGeometries() == |
286 previousBoxGeometriesMap().contains(&m_box)); | 378 previousBoxGeometriesMap().contains(&m_box)); |
287 return m_box.hasPreviousBoxGeometries() | 379 return m_box.hasPreviousBoxGeometries() |
288 ? previousBoxGeometriesMap().get(&m_box).layoutOverflowRect | 380 ? previousBoxGeometriesMap().get(&m_box).layoutOverflowRect |
289 : LayoutRect(); | 381 : LayoutRect(); |
290 } | 382 } |
291 | 383 |
292 } // namespace blink | 384 } // namespace blink |
OLD | NEW |