Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(305)

Side by Side Diff: third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp

Issue 2498823002: Paint invalidation of local attachment backgrounds (Closed)
Patch Set: - Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698