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

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

Issue 2498823002: Paint invalidation of local attachment backgrounds (Closed)
Patch Set: Update test expectations 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); 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698