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); | |
104 objectPaintInvalidator.invalidatePaintUsingContainer( | 90 objectPaintInvalidator.invalidatePaintUsingContainer( |
105 *m_context.paintInvalidationContainer, bottomDelta, | 91 *m_context.paintInvalidationContainer, bottomDelta, reason); |
106 PaintInvalidationIncremental); | |
107 return true; | 92 return true; |
108 } | 93 } |
109 | 94 |
110 PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { | 95 PaintInvalidationReason BoxPaintInvalidator::computePaintInvalidationReason() { |
111 PaintInvalidationReason reason = | 96 PaintInvalidationReason reason = |
112 ObjectPaintInvalidatorWithContext(m_box, m_context) | 97 ObjectPaintInvalidatorWithContext(m_box, m_context) |
113 .computePaintInvalidationReason(); | 98 .computePaintInvalidationReason(); |
114 | 99 |
115 if (reason != PaintInvalidationIncremental) | 100 if (reason != PaintInvalidationIncremental) |
116 return reason; | 101 return reason; |
(...skipping 12 matching lines...) Expand all Loading... |
129 } | 114 } |
130 | 115 |
131 const ComputedStyle& style = m_box.styleRef(); | 116 const ComputedStyle& style = m_box.styleRef(); |
132 | 117 |
133 if ((style.backgroundLayers().thisOrNextLayersUseContentBox() || | 118 if ((style.backgroundLayers().thisOrNextLayersUseContentBox() || |
134 style.maskLayers().thisOrNextLayersUseContentBox() || | 119 style.maskLayers().thisOrNextLayersUseContentBox() || |
135 style.boxSizing() == BoxSizingBorderBox) && | 120 style.boxSizing() == BoxSizingBorderBox) && |
136 previousContentBoxRect() != m_box.contentBoxRect()) | 121 previousContentBoxRect() != m_box.contentBoxRect()) |
137 return PaintInvalidationContentBoxChange; | 122 return PaintInvalidationContentBoxChange; |
138 | 123 |
139 if (style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() && | 124 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(); | 125 LayoutSize newBorderBoxSize = m_box.size(); |
146 bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize; | 126 bool borderBoxChanged = oldBorderBoxSize != newBorderBoxSize; |
147 | |
148 if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect) | 127 if (!borderBoxChanged && m_context.oldVisualRect == m_context.newVisualRect) |
149 return PaintInvalidationNone; | 128 return PaintInvalidationNone; |
150 | 129 |
151 // If either border box changed or bounds changed, and old or new border box | 130 // 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 | 131 // doesn't equal old or new bounds, incremental invalidation is not |
153 // applicable. This captures the following cases: | 132 // applicable. This captures the following cases: |
154 // - pixel snapping of paint invalidation bounds, | 133 // - pixel snapping of paint invalidation bounds, |
155 // - scale, rotate, skew etc. transforms, | 134 // - scale, rotate, skew etc. transforms, |
156 // - visual overflows. | 135 // - visual overflows. |
157 if (m_context.oldVisualRect != | 136 if (m_context.oldVisualRect != |
(...skipping 17 matching lines...) Expand all Loading... |
175 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && | 154 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && |
176 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) | 155 m_box.mustInvalidateBackgroundOrBorderPaintOnWidthChange()) |
177 return PaintInvalidationBorderBoxChange; | 156 return PaintInvalidationBorderBoxChange; |
178 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && | 157 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && |
179 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) | 158 m_box.mustInvalidateBackgroundOrBorderPaintOnHeightChange()) |
180 return PaintInvalidationBorderBoxChange; | 159 return PaintInvalidationBorderBoxChange; |
181 | 160 |
182 return PaintInvalidationIncremental; | 161 return PaintInvalidationIncremental; |
183 } | 162 } |
184 | 163 |
| 164 bool BoxPaintInvalidator::backgroundGeometryDependsOnLayoutOverflowRect() { |
| 165 return !m_box.isDocumentElement() && !m_box.backgroundStolenForBeingBody() && |
| 166 m_box.styleRef() |
| 167 .backgroundLayers() |
| 168 .thisOrNextLayersHaveLocalAttachment(); |
| 169 } |
| 170 |
| 171 // Background positioning in layout overflow rect doesn't mean it will |
| 172 // paint onto the scrolling contents layer because some conditions prevent |
| 173 // it from that. We may also treat non-local solid color backgrounds as local |
| 174 // and paint onto the scrolling contents layer. |
| 175 // See PaintLayer::canPaintBackgroundOntoScrollingContentsLayer(). |
| 176 bool BoxPaintInvalidator::backgroundPaintsOntoScrollingContentsLayer() { |
| 177 if (m_box.isDocumentElement() || m_box.backgroundStolenForBeingBody()) |
| 178 return false; |
| 179 if (!m_box.hasLayer()) |
| 180 return false; |
| 181 if (auto* mapping = m_box.layer()->compositedLayerMapping()) |
| 182 return mapping->backgroundPaintsOntoScrollingContentsLayer(); |
| 183 return false; |
| 184 } |
| 185 |
| 186 bool BoxPaintInvalidator::shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| 187 const LayoutRect& oldLayoutOverflow, |
| 188 const LayoutRect& newLayoutOverflow) { |
| 189 DCHECK(oldLayoutOverflow != newLayoutOverflow); |
| 190 if (newLayoutOverflow.isEmpty() || oldLayoutOverflow.isEmpty()) |
| 191 return true; |
| 192 if (newLayoutOverflow.location() != oldLayoutOverflow.location()) |
| 193 return true; |
| 194 if (newLayoutOverflow.width() != oldLayoutOverflow.width() && |
| 195 m_box.mustInvalidateFillLayersPaintOnHeightChange( |
| 196 m_box.styleRef().backgroundLayers())) |
| 197 return true; |
| 198 if (newLayoutOverflow.height() != oldLayoutOverflow.height() && |
| 199 m_box.mustInvalidateFillLayersPaintOnHeightChange( |
| 200 m_box.styleRef().backgroundLayers())) |
| 201 return true; |
| 202 return false; |
| 203 } |
| 204 |
| 205 void BoxPaintInvalidator::invalidateScrollingContentsBackgroundIfNeeded() { |
| 206 bool paintsOntoScrollingContentsLayer = |
| 207 backgroundPaintsOntoScrollingContentsLayer(); |
| 208 if (!paintsOntoScrollingContentsLayer && |
| 209 !backgroundGeometryDependsOnLayoutOverflowRect()) |
| 210 return; |
| 211 |
| 212 const LayoutRect& oldLayoutOverflow = previousLayoutOverflowRect(); |
| 213 LayoutRect newLayoutOverflow = m_box.layoutOverflowRect(); |
| 214 |
| 215 bool shouldFullyInvalidateOnScrollingContentsLayer = false; |
| 216 if (m_box.backgroundChangedSinceLastPaintInvalidation()) { |
| 217 if (!paintsOntoScrollingContentsLayer) { |
| 218 // The box should have been set needing full invalidation on style change. |
| 219 DCHECK(m_box.shouldDoFullPaintInvalidation()); |
| 220 return; |
| 221 } |
| 222 shouldFullyInvalidateOnScrollingContentsLayer = true; |
| 223 } else { |
| 224 // Check change of layout overflow for incremental invalidation. |
| 225 if (!m_box.hasPreviousBoxGeometries() || |
| 226 newLayoutOverflow == oldLayoutOverflow) |
| 227 return; |
| 228 if (!paintsOntoScrollingContentsLayer) { |
| 229 if (shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| 230 oldLayoutOverflow, newLayoutOverflow)) { |
| 231 m_box.getMutableForPainting().setShouldDoFullPaintInvalidation( |
| 232 PaintInvalidationLayoutOverflowBoxChange); |
| 233 } |
| 234 return; |
| 235 } |
| 236 shouldFullyInvalidateOnScrollingContentsLayer = |
| 237 shouldFullyInvalidateBackgroundOnLayoutOverflowChange( |
| 238 oldLayoutOverflow, newLayoutOverflow); |
| 239 } |
| 240 |
| 241 if (shouldFullyInvalidateOnScrollingContentsLayer) { |
| 242 ObjectPaintInvalidatorWithContext(m_box, m_context) |
| 243 .fullyInvalidatePaint( |
| 244 PaintInvalidationBackgroundOnScrollingContentsLayer, |
| 245 oldLayoutOverflow, newLayoutOverflow); |
| 246 } else { |
| 247 incrementallyInvalidatePaint( |
| 248 PaintInvalidationBackgroundOnScrollingContentsLayer, oldLayoutOverflow, |
| 249 newLayoutOverflow); |
| 250 } |
| 251 |
| 252 m_context.paintingLayer->setNeedsRepaint(); |
| 253 // Currently we use CompositedLayerMapping as the DisplayItemClient to paint |
| 254 // background on the scrolling contents layer. |
| 255 ObjectPaintInvalidator(m_box).invalidateDisplayItemClient( |
| 256 *m_box.layer()->compositedLayerMapping()->scrollingContentsLayer(), |
| 257 PaintInvalidationBackgroundOnScrollingContentsLayer); |
| 258 } |
| 259 |
185 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { | 260 PaintInvalidationReason BoxPaintInvalidator::invalidatePaintIfNeeded() { |
| 261 invalidateScrollingContentsBackgroundIfNeeded(); |
| 262 |
186 PaintInvalidationReason reason = computePaintInvalidationReason(); | 263 PaintInvalidationReason reason = computePaintInvalidationReason(); |
187 if (reason == PaintInvalidationIncremental) { | 264 if (reason == PaintInvalidationIncremental) { |
188 if (incrementallyInvalidatePaint()) { | 265 bool invalidated; |
| 266 if (m_box.isLayoutView() && |
| 267 !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { |
| 268 invalidated = incrementallyInvalidatePaint( |
| 269 reason, m_context.oldVisualRect, m_context.newVisualRect); |
| 270 } else { |
| 271 invalidated = incrementallyInvalidatePaint( |
| 272 reason, LayoutRect(m_context.oldLocation, previousBorderBoxSize()), |
| 273 LayoutRect(m_context.newLocation, m_box.size())); |
| 274 } |
| 275 if (invalidated) { |
189 m_context.paintingLayer->setNeedsRepaint(); | 276 m_context.paintingLayer->setNeedsRepaint(); |
190 m_box.invalidateDisplayItemClients(reason); | 277 m_box.invalidateDisplayItemClients(reason); |
191 } else { | 278 } else { |
192 reason = PaintInvalidationNone; | 279 reason = PaintInvalidationNone; |
193 } | 280 } |
| 281 |
194 // Though we have done incremental invalidation, we still need to call | 282 // Though we have done incremental invalidation, we still need to call |
195 // ObjectPaintInvalidator with PaintInvalidationNone to do any other | 283 // ObjectPaintInvalidator with PaintInvalidationNone to do any other |
196 // required operations. | 284 // required operations. |
197 reason = std::max( | 285 reason = std::max( |
198 reason, | 286 reason, |
199 ObjectPaintInvalidatorWithContext(m_box, m_context) | 287 ObjectPaintInvalidatorWithContext(m_box, m_context) |
200 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); | 288 .invalidatePaintIfNeededWithComputedReason(PaintInvalidationNone)); |
201 } else { | 289 } else { |
202 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) | 290 reason = ObjectPaintInvalidatorWithContext(m_box, m_context) |
203 .invalidatePaintIfNeededWithComputedReason(reason); | 291 .invalidatePaintIfNeededWithComputedReason(reason); |
(...skipping 26 matching lines...) Expand all Loading... |
230 return true; | 318 return true; |
231 | 319 |
232 // No need to save old border box size if we can use size of the old paint | 320 // 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. | 321 // rect as the old border box size in the next invalidation. |
234 if (paintInvalidationSize != m_box.size()) | 322 if (paintInvalidationSize != m_box.size()) |
235 return true; | 323 return true; |
236 | 324 |
237 // Background and mask layers can depend on other boxes than border box. See | 325 // Background and mask layers can depend on other boxes than border box. See |
238 // crbug.com/490533 | 326 // crbug.com/490533 |
239 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || | 327 if (style.backgroundLayers().thisOrNextLayersUseContentBox() || |
240 style.backgroundLayers().thisOrNextLayersHaveLocalAttachment() || | 328 style.maskLayers().thisOrNextLayersUseContentBox() || |
241 style.maskLayers().thisOrNextLayersUseContentBox()) | 329 backgroundGeometryDependsOnLayoutOverflowRect() || |
| 330 backgroundPaintsOntoScrollingContentsLayer()) |
242 return true; | 331 return true; |
243 | 332 |
244 return false; | 333 return false; |
245 } | 334 } |
246 | 335 |
247 void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() { | 336 void BoxPaintInvalidator::savePreviousBoxGeometriesIfNeeded() { |
248 DCHECK(m_box.hasPreviousBoxGeometries() == | 337 DCHECK(m_box.hasPreviousBoxGeometries() == |
249 previousBoxGeometriesMap().contains(&m_box)); | 338 previousBoxGeometriesMap().contains(&m_box)); |
250 if (!needsToSavePreviousBoxGeometries()) { | 339 if (!needsToSavePreviousBoxGeometries()) { |
251 if (m_box.hasPreviousBoxGeometries()) { | 340 if (m_box.hasPreviousBoxGeometries()) { |
252 previousBoxGeometriesMap().remove(&m_box); | 341 previousBoxGeometriesMap().remove(&m_box); |
253 m_box.getMutableForPainting().setHasPreviousBoxGeometries(false); | 342 m_box.getMutableForPainting().setHasPreviousBoxGeometries(false); |
254 } | 343 } |
255 return; | 344 return; |
256 } | 345 } |
257 | 346 |
258 PreviousBoxGeometries Geometries = {m_box.size(), m_box.contentBoxRect(), | 347 PreviousBoxGeometries geometries = {m_box.size(), m_box.contentBoxRect(), |
259 m_box.layoutOverflowRect()}; | 348 m_box.layoutOverflowRect()}; |
260 previousBoxGeometriesMap().set(&m_box, Geometries); | 349 previousBoxGeometriesMap().set(&m_box, geometries); |
261 m_box.getMutableForPainting().setHasPreviousBoxGeometries(true); | 350 m_box.getMutableForPainting().setHasPreviousBoxGeometries(true); |
262 } | 351 } |
263 | 352 |
264 LayoutSize BoxPaintInvalidator::previousBorderBoxSize( | 353 LayoutSize BoxPaintInvalidator::previousBorderBoxSize() { |
265 const LayoutSize& previousVisualRectSize) { | |
266 DCHECK(m_box.hasPreviousBoxGeometries() == | 354 DCHECK(m_box.hasPreviousBoxGeometries() == |
267 previousBoxGeometriesMap().contains(&m_box)); | 355 previousBoxGeometriesMap().contains(&m_box)); |
268 if (m_box.hasPreviousBoxGeometries()) | 356 if (m_box.hasPreviousBoxGeometries()) |
269 return previousBoxGeometriesMap().get(&m_box).borderBoxSize; | 357 return previousBoxGeometriesMap().get(&m_box).borderBoxSize; |
270 | 358 |
271 // We didn't save the old border box size because it was the same as the size | 359 // We didn't save the old border box size because it was the same as the size |
272 // of oldVisualRect. | 360 // of oldVisualRect. |
273 return previousVisualRectSize; | 361 return m_context.oldVisualRect.size(); |
274 } | 362 } |
275 | 363 |
276 LayoutRect BoxPaintInvalidator::previousContentBoxRect() { | 364 LayoutRect BoxPaintInvalidator::previousContentBoxRect() { |
277 DCHECK(m_box.hasPreviousBoxGeometries() == | 365 DCHECK(m_box.hasPreviousBoxGeometries() == |
278 previousBoxGeometriesMap().contains(&m_box)); | 366 previousBoxGeometriesMap().contains(&m_box)); |
279 return m_box.hasPreviousBoxGeometries() | 367 return m_box.hasPreviousBoxGeometries() |
280 ? previousBoxGeometriesMap().get(&m_box).contentBoxRect | 368 ? previousBoxGeometriesMap().get(&m_box).contentBoxRect |
281 : LayoutRect(); | 369 : LayoutRect(); |
282 } | 370 } |
283 | 371 |
284 LayoutRect BoxPaintInvalidator::previousLayoutOverflowRect() { | 372 LayoutRect BoxPaintInvalidator::previousLayoutOverflowRect() { |
285 DCHECK(m_box.hasPreviousBoxGeometries() == | 373 DCHECK(m_box.hasPreviousBoxGeometries() == |
286 previousBoxGeometriesMap().contains(&m_box)); | 374 previousBoxGeometriesMap().contains(&m_box)); |
287 return m_box.hasPreviousBoxGeometries() | 375 return m_box.hasPreviousBoxGeometries() |
288 ? previousBoxGeometriesMap().get(&m_box).layoutOverflowRect | 376 ? previousBoxGeometriesMap().get(&m_box).layoutOverflowRect |
289 : LayoutRect(); | 377 : LayoutRect(); |
290 } | 378 } |
291 | 379 |
292 } // namespace blink | 380 } // namespace blink |
OLD | NEW |