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

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

Issue 2732573003: Skip paint property update and visual rect update if no geometry change (Closed)
Patch Set: - Created 3 years, 8 months 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/PaintInvalidator.h" 5 #include "core/paint/PaintInvalidator.h"
6 6
7 #include "core/editing/FrameSelection.h" 7 #include "core/editing/FrameSelection.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/frame/Settings.h" 10 #include "core/frame/Settings.h"
11 #include "core/layout/LayoutBlockFlow.h" 11 #include "core/layout/LayoutBlockFlow.h"
12 #include "core/layout/LayoutObject.h"
13 #include "core/layout/LayoutTable.h" 12 #include "core/layout/LayoutTable.h"
14 #include "core/layout/LayoutView.h" 13 #include "core/layout/LayoutView.h"
15 #include "core/layout/svg/SVGLayoutSupport.h" 14 #include "core/layout/svg/SVGLayoutSupport.h"
15 #include "core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h"
16 #include "core/paint/ObjectPaintProperties.h" 16 #include "core/paint/ObjectPaintProperties.h"
17 #include "core/paint/PaintLayer.h" 17 #include "core/paint/PaintLayer.h"
18 #include "core/paint/PaintLayerScrollableArea.h" 18 #include "core/paint/PaintLayerScrollableArea.h"
19 #include "core/paint/PaintPropertyTreeBuilder.h"
20 #include "wtf/Optional.h" 19 #include "wtf/Optional.h"
21 20
22 namespace blink { 21 namespace blink {
23 22
24 template <typename Rect> 23 template <typename Rect>
25 static LayoutRect slowMapToVisualRectInAncestorSpace( 24 static LayoutRect slowMapToVisualRectInAncestorSpace(
26 const LayoutObject& object, 25 const LayoutObject& object,
27 const LayoutBoxModelObject& ancestor, 26 const LayoutBoxModelObject& ancestor,
28 const Rect& rect) { 27 const Rect& rect) {
29 if (object.isSVGChild()) { 28 if (object.isSVGChild()) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 result = LayoutRect(rect); 99 result = LayoutRect(rect);
101 } else { 100 } else {
102 // For non-root SVG, the input rect is in local SVG coordinates in which 101 // For non-root SVG, the input rect is in local SVG coordinates in which
103 // paint offset doesn't apply. 102 // paint offset doesn't apply.
104 if (!isSVGChild) 103 if (!isSVGChild)
105 rect.moveBy(Point(object.paintOffset())); 104 rect.moveBy(Point(object.paintOffset()));
106 105
107 const auto* containerContentsProperties = 106 const auto* containerContentsProperties =
108 context.paintInvalidationContainer->contentsProperties(); 107 context.paintInvalidationContainer->contentsProperties();
109 108
110 if (context.m_treeBuilderContext.current.transform == 109 if (context.m_treeBuilderContext->current.transform ==
111 containerContentsProperties->transform() && 110 containerContentsProperties->transform() &&
112 context.m_treeBuilderContext.current.clip == 111 context.m_treeBuilderContext->current.clip ==
113 containerContentsProperties->clip()) { 112 containerContentsProperties->clip()) {
114 result = LayoutRect(rect); 113 result = LayoutRect(rect);
115 } else { 114 } else {
116 // Use enclosingIntRect to ensure the final visual rect will cover the 115 // Use enclosingIntRect to ensure the final visual rect will cover the
117 // rect in source coordinates no matter if the painting will use pixel 116 // rect in source coordinates no matter if the painting will use pixel
118 // snapping, when transforms are applied. If there is no transform, 117 // snapping, when transforms are applied. If there is no transform,
119 // enclosingIntRect is applied in the last step of paint invalidation 118 // enclosingIntRect is applied in the last step of paint invalidation
120 // (see CompositedLayerMapping::setContentsNeedDisplayInRect()). 119 // (see CompositedLayerMapping::setContentsNeedDisplayInRect()).
121 if (!isSVGChild && context.m_treeBuilderContext.current.transform != 120 if (!isSVGChild && context.m_treeBuilderContext->current.transform !=
122 containerContentsProperties->transform()) 121 containerContentsProperties->transform())
123 rect = Rect(enclosingIntRect(rect)); 122 rect = Rect(enclosingIntRect(rect));
124 123
125 PropertyTreeState currentTreeState( 124 PropertyTreeState currentTreeState(
126 context.m_treeBuilderContext.current.transform, 125 context.m_treeBuilderContext->current.transform,
127 context.m_treeBuilderContext.current.clip, nullptr); 126 context.m_treeBuilderContext->current.clip, nullptr);
128 127
129 FloatRect floatRect(rect); 128 FloatRect floatRect(rect);
130 context.m_geometryMapper.sourceToDestinationVisualRect( 129 context.m_geometryMapper.sourceToDestinationVisualRect(
131 currentTreeState, *containerContentsProperties, floatRect); 130 currentTreeState, *containerContentsProperties, floatRect);
132 result = LayoutRect(floatRect); 131 result = LayoutRect(floatRect);
133 } 132 }
134 133
135 // Convert the result to the container's contents space. 134 // Convert the result to the container's contents space.
136 result.moveBy(-context.paintInvalidationContainer->paintOffset()); 135 result.moveBy(-context.paintInvalidationContainer->paintOffset());
137 } 136 }
138 137
139 object.adjustVisualRectForRasterEffects(result); 138 object.adjustVisualRectForRasterEffects(result);
140 139
141 PaintLayer::mapRectInPaintInvalidationContainerToBacking( 140 PaintLayer::mapRectInPaintInvalidationContainerToBacking(
142 *context.paintInvalidationContainer, result); 141 *context.paintInvalidationContainer, result);
143 142
144 result.move(object.scrollAdjustmentForPaintInvalidation( 143 result.move(object.scrollAdjustmentForPaintInvalidation(
145 *context.paintInvalidationContainer)); 144 *context.paintInvalidationContainer));
146 145
147 return result; 146 return result;
148 } 147 }
149 148
150 void PaintInvalidatorContext::mapLocalRectToVisualRectInBacking( 149 void PaintInvalidatorContext::mapLocalRectToVisualRectInBacking(
151 const LayoutObject& object, 150 const LayoutObject& object,
152 LayoutRect& rect) const { 151 LayoutRect& rect) const {
152 DCHECK(needsVisualRectUpdate(object));
153 std::unique_ptr<GeometryMapper> geometryMapper = GeometryMapper::create();
153 rect = PaintInvalidator::mapLocalRectToVisualRectInBacking<LayoutRect, 154 rect = PaintInvalidator::mapLocalRectToVisualRectInBacking<LayoutRect,
154 LayoutPoint>( 155 LayoutPoint>(
155 object, rect, *this); 156 object, rect, *this);
156 } 157 }
157 158
158 LayoutRect PaintInvalidator::computeVisualRectInBacking( 159 LayoutRect PaintInvalidator::computeVisualRectInBacking(
159 const LayoutObject& object, 160 const LayoutObject& object,
160 const PaintInvalidatorContext& context) { 161 const PaintInvalidatorContext& context) {
161 if (object.isSVGChild()) { 162 if (object.isSVGChild()) {
162 FloatRect localRect = SVGLayoutSupport::localVisualRect(object); 163 FloatRect localRect = SVGLayoutSupport::localVisualRect(object);
(...skipping 10 matching lines...) Expand all
173 // In SPv2, locationInBacking is in the space of their local transform node. 174 // In SPv2, locationInBacking is in the space of their local transform node.
174 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) 175 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
175 return object.paintOffset(); 176 return object.paintOffset();
176 177
177 LayoutPoint point; 178 LayoutPoint point;
178 if (object != context.paintInvalidationContainer) { 179 if (object != context.paintInvalidationContainer) {
179 point.moveBy(object.paintOffset()); 180 point.moveBy(object.paintOffset());
180 181
181 const auto* containerTransform = 182 const auto* containerTransform =
182 context.paintInvalidationContainer->contentsProperties()->transform(); 183 context.paintInvalidationContainer->contentsProperties()->transform();
183 if (context.m_treeBuilderContext.current.transform != containerTransform) { 184 if (context.m_treeBuilderContext->current.transform != containerTransform) {
184 FloatRect rect = FloatRect(FloatPoint(point), FloatSize()); 185 FloatRect rect = FloatRect(FloatPoint(point), FloatSize());
185 context.m_geometryMapper.sourceToDestinationRect( 186 context.m_geometryMapper.sourceToDestinationRect(
186 context.m_treeBuilderContext.current.transform, containerTransform, 187 context.m_treeBuilderContext->current.transform, containerTransform,
187 rect); 188 rect);
188 point = LayoutPoint(rect.location()); 189 point = LayoutPoint(rect.location());
189 } 190 }
190 191
191 // Convert the result to the container's contents space. 192 // Convert the result to the container's contents space.
192 point.moveBy(-context.paintInvalidationContainer->paintOffset()); 193 point.moveBy(-context.paintInvalidationContainer->paintOffset());
193 } 194 }
194 195
195 if (context.paintInvalidationContainer->layer()->groupedMapping()) { 196 if (context.paintInvalidationContainer->layer()->groupedMapping()) {
196 FloatPoint floatPoint(point); 197 FloatPoint floatPoint(point);
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 context.forcedSubtreeInvalidationFlags |= 323 context.forcedSubtreeInvalidationFlags |=
323 PaintInvalidatorContext::ForcedSubtreeFullInvalidation; 324 PaintInvalidatorContext::ForcedSubtreeFullInvalidation;
324 } 325 }
325 326
326 if (object == context.paintInvalidationContainer) { 327 if (object == context.paintInvalidationContainer) {
327 // When we hit a new paint invalidation container, we don't need to 328 // When we hit a new paint invalidation container, we don't need to
328 // continue forcing a check for paint invalidation, since we're 329 // continue forcing a check for paint invalidation, since we're
329 // descending into a different invalidation container. (For instance if 330 // descending into a different invalidation container. (For instance if
330 // our parents were moved, the entire container will just move.) 331 // our parents were moved, the entire container will just move.)
331 if (object != context.paintInvalidationContainerForStackedContents) { 332 if (object != context.paintInvalidationContainerForStackedContents) {
332 // However, we need to keep the 333 // However, we need to keep ForcedSubtreeVisualRectUpdate and
333 // ForcedSubtreeFullInvalidationForStackedContents flag if the current 334 // ForcedSubtreeFullInvalidationForStackedContents flags if the current
334 // object isn't the paint invalidation container of stacked contents. 335 // object isn't the paint invalidation container of stacked contents.
335 context.forcedSubtreeInvalidationFlags &= PaintInvalidatorContext:: 336 context.forcedSubtreeInvalidationFlags &=
336 ForcedSubtreeFullInvalidationForStackedContents; 337 (PaintInvalidatorContext::ForcedSubtreeVisualRectUpdate |
338 PaintInvalidatorContext::
339 ForcedSubtreeFullInvalidationForStackedContents);
337 } else { 340 } else {
338 context.forcedSubtreeInvalidationFlags = 0; 341 context.forcedSubtreeInvalidationFlags = 0;
339 } 342 }
340 } 343 }
341 344
342 DCHECK(context.paintInvalidationContainer == 345 DCHECK(context.paintInvalidationContainer ==
343 object.containerForPaintInvalidation()); 346 object.containerForPaintInvalidation());
344 DCHECK(context.paintingLayer == object.paintingLayer()); 347 DCHECK(context.paintingLayer == object.paintingLayer());
345 } 348 }
346 349
350 void PaintInvalidator::updateVisualRectIfNeeded(
351 const LayoutObject& object,
352 PaintInvalidatorContext& context) {
353 context.oldVisualRect = object.visualRect();
354 context.oldLocation = ObjectPaintInvalidator(object).locationInBacking();
355
356 #if DCHECK_IS_ON()
357 FindObjectVisualRectNeedingUpdateScope finder(object, context);
358 #endif
359
360 if (!context.needsVisualRectUpdate(object)) {
361 context.newLocation = context.oldLocation;
362 return;
363 }
364
365 updateVisualRect(object, context);
366 }
367
347 void PaintInvalidator::updateVisualRect(const LayoutObject& object, 368 void PaintInvalidator::updateVisualRect(const LayoutObject& object,
348 PaintInvalidatorContext& context) { 369 PaintInvalidatorContext& context) {
370 // The paint offset should already be updated through
371 // PaintPropertyTreeBuilder::updatePropertiesForSelf.
372 DCHECK(context.m_treeBuilderContext);
373 DCHECK(context.m_treeBuilderContext->current.paintOffset ==
374 object.paintOffset());
375
349 Optional<ScopedUndoFrameViewContentClipAndScroll> 376 Optional<ScopedUndoFrameViewContentClipAndScroll>
350 undoFrameViewContentClipAndScroll; 377 undoFrameViewContentClipAndScroll;
351 378
352 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() && 379 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
353 object.isLayoutView() && !object.isPaintInvalidationContainer()) { 380 object.isLayoutView() && !object.isPaintInvalidationContainer()) {
354 undoFrameViewContentClipAndScroll.emplace(*toLayoutView(object).frameView(), 381 undoFrameViewContentClipAndScroll.emplace(*toLayoutView(object).frameView(),
355 context.m_treeBuilderContext); 382 *context.m_treeBuilderContext);
356 } 383 }
357 384
358 // TODO(crbug.com/637313): Use GeometryMapper which now supports filter
359 // geometry effects, after skia optimizes filter's mapRect operation.
360 // TODO(crbug.com/648274): This is a workaround for multi-column contents.
361 if (object.hasFilterInducingProperty() || object.isLayoutFlowThread()) {
362 context.forcedSubtreeInvalidationFlags |=
363 PaintInvalidatorContext::ForcedSubtreeSlowPathRect;
364 }
365
366 ObjectPaintInvalidator objectPaintInvalidator(object);
367 context.oldVisualRect = object.visualRect();
368 context.oldLocation = objectPaintInvalidator.locationInBacking();
369
370 LayoutRect newVisualRect = computeVisualRectInBacking(object, context); 385 LayoutRect newVisualRect = computeVisualRectInBacking(object, context);
371 if (object.isBoxModelObject()) { 386 if (object.isBoxModelObject()) {
372 context.newLocation = computeLocationInBacking(object, context); 387 context.newLocation = computeLocationInBacking(object, context);
373
374 // Location of empty visual rect doesn't affect paint invalidation. Set it 388 // Location of empty visual rect doesn't affect paint invalidation. Set it
375 // to newLocation to avoid saving the previous location separately in 389 // to newLocation to avoid saving the previous location separately in
376 // ObjectPaintInvalidator. 390 // ObjectPaintInvalidator.
377 if (newVisualRect.isEmpty()) 391 if (newVisualRect.isEmpty())
378 newVisualRect.setLocation(context.newLocation); 392 newVisualRect.setLocation(context.newLocation);
379 } else { 393 } else {
380 // Use visual rect location for non-LayoutBoxModelObject because it suffices 394 // Use visual rect location for non-LayoutBoxModelObject because it suffices
381 // to check whether a visual rect changes for layout caused invalidation. 395 // to check whether a visual rect changes for layout caused invalidation.
382 context.newLocation = newVisualRect.location(); 396 context.newLocation = newVisualRect.location();
383 } 397 }
384 398
385 object.getMutableForPainting().setVisualRect(newVisualRect); 399 object.getMutableForPainting().setVisualRect(newVisualRect);
386 objectPaintInvalidator.setLocationInBacking(context.newLocation); 400 ObjectPaintInvalidator(object).setLocationInBacking(context.newLocation);
387 } 401 }
388 402
389 void PaintInvalidator::invalidatePaintIfNeeded( 403 void PaintInvalidator::invalidatePaintIfNeeded(
390 FrameView& frameView, 404 FrameView& frameView,
391 PaintInvalidatorContext& context) { 405 PaintInvalidatorContext& context) {
392 LayoutView* layoutView = frameView.layoutView(); 406 LayoutView* layoutView = frameView.layoutView();
393 CHECK(layoutView); 407 CHECK(layoutView);
394 408
395 context.paintInvalidationContainer = 409 context.paintInvalidationContainer =
396 context.paintInvalidationContainerForStackedContents = 410 context.paintInvalidationContainerForStackedContents =
397 &layoutView->containerForPaintInvalidation(); 411 &layoutView->containerForPaintInvalidation();
398 context.paintingLayer = layoutView->layer(); 412 context.paintingLayer = layoutView->layer();
399 413
400 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { 414 if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
401 ScopedUndoFrameViewContentClipAndScroll undo(frameView, 415 Optional<ScopedUndoFrameViewContentClipAndScroll> undo;
402 context.m_treeBuilderContext); 416 if (context.m_treeBuilderContext)
417 undo.emplace(frameView, *context.m_treeBuilderContext);
403 frameView.invalidatePaintOfScrollControlsIfNeeded(context); 418 frameView.invalidatePaintOfScrollControlsIfNeeded(context);
404 } 419 }
405 } 420 }
406 421
407 void PaintInvalidator::invalidatePaintIfNeeded( 422 void PaintInvalidator::invalidatePaintIfNeeded(
408 const LayoutObject& object, 423 const LayoutObject& object,
409 PaintInvalidatorContext& context) { 424 PaintInvalidatorContext& context) {
410 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), 425 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
411 "PaintInvalidator::invalidatePaintIfNeeded()", "object", 426 "PaintInvalidator::invalidatePaintIfNeeded()", "object",
412 object.debugName().ascii()); 427 object.debugName().ascii());
413 428
414 object.getMutableForPainting().ensureIsReadyForPaintInvalidation(); 429 object.getMutableForPainting().ensureIsReadyForPaintInvalidation();
415 430
416 // The paint offset should already be updated through
417 // PaintPropertyTreeBuilder::updatePropertiesForSelf.
418 DCHECK(context.m_treeBuilderContext.current.paintOffset ==
419 object.paintOffset());
420
421 updatePaintingLayer(object, context); 431 updatePaintingLayer(object, context);
422 432
423 if (object.document().printing() && 433 if (object.document().printing() &&
424 !RuntimeEnabledFeatures::printBrowserEnabled()) 434 !RuntimeEnabledFeatures::printBrowserEnabled())
425 return; // Don't invalidate paints if we're printing. 435 return; // Don't invalidate paints if we're printing.
426 436
427 updatePaintInvalidationContainer(object, context); 437 // TODO(crbug.com/637313): Use GeometryMapper which now supports filter
428 438 // geometry effects, after skia optimizes filter's mapRect operation.
429 bool objectShouldCheckForPaintInvalidation = 439 // TODO(crbug.com/648274): This is a workaround for multi-column contents.
430 object.shouldCheckForPaintInvalidation(); 440 if (object.hasFilterInducingProperty() || object.isLayoutFlowThread()) {
431 if (!context.forcedSubtreeInvalidationFlags && 441 context.forcedSubtreeInvalidationFlags |=
432 !objectShouldCheckForPaintInvalidation) { 442 PaintInvalidatorContext::ForcedSubtreeSlowPathRect;
433 #if CHECK_VISUAL_RECT_UPDATE
434 updateVisualRect(object, context);
435 DCHECK(
436 (context.oldVisualRect.isEmpty() && context.newVisualRect.isEmpty()) ||
437 enclosingIntRect(context.oldVisualRect) ==
438 enclosingIntRect(context.newVisualRect))
439 << "Visual rect changed without needing paint invalidation:"
440 << " object=" << object.debugName()
441 << " old=" << context.oldVisualRect.toString()
442 << " new=" << context.newVisualRect.toString();
443 DCHECK(object.isText() || context.oldLocation == context.newLocation)
444 << "Location changed without needing paint invalidation:"
445 << " old=" << context.oldLocation.toString()
446 << " new=" << context.newLocation.toString();
447 #endif
448 return;
449 } 443 }
450 444
451 updateVisualRect(object, context); 445 updatePaintInvalidationContainer(object, context);
446 updateVisualRectIfNeeded(object, context);
452 447
453 if (!objectShouldCheckForPaintInvalidation && 448 if (!object.shouldCheckForPaintInvalidation() &&
454 context.forcedSubtreeInvalidationFlags == 449 !(context.forcedSubtreeInvalidationFlags &
455 PaintInvalidatorContext::ForcedSubtreeInvalidationRectUpdate) { 450 ~PaintInvalidatorContext::ForcedSubtreeVisualRectUpdate)) {
456 // We are done updating the visual rect. No other paint invalidation work to 451 // We are done updating anything needed. No other paint invalidation work to
457 // do for this object. 452 // do for this object.
458 return; 453 return;
459 } 454 }
460 455
461 if (object.isSVGHiddenContainer()) { 456 if (object.isSVGHiddenContainer()) {
462 context.forcedSubtreeInvalidationFlags |= 457 context.forcedSubtreeInvalidationFlags |=
463 PaintInvalidatorContext::ForcedSubtreeNoRasterInvalidation; 458 PaintInvalidatorContext::ForcedSubtreeNoRasterInvalidation;
464 } 459 }
465 460
466 PaintInvalidationReason reason = object.invalidatePaintIfNeeded(context); 461 PaintInvalidationReason reason = object.invalidatePaintIfNeeded(context);
(...skipping 17 matching lines...) Expand all
484 479
485 if (object.mayNeedPaintInvalidationSubtree()) { 480 if (object.mayNeedPaintInvalidationSubtree()) {
486 context.forcedSubtreeInvalidationFlags |= 481 context.forcedSubtreeInvalidationFlags |=
487 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking; 482 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking;
488 } 483 }
489 484
490 if (context.oldLocation != context.newLocation) { 485 if (context.oldLocation != context.newLocation) {
491 context.forcedSubtreeInvalidationFlags |= 486 context.forcedSubtreeInvalidationFlags |=
492 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking; 487 PaintInvalidatorContext::ForcedSubtreeInvalidationChecking;
493 } 488 }
489
490 if (context.forcedSubtreeInvalidationFlags &&
491 context.needsVisualRectUpdate(object)) {
492 // If any subtree flag is set, we also need to pass needsVisualRectUpdate
493 // requirement to the subtree.
494 context.forcedSubtreeInvalidationFlags |=
495 PaintInvalidatorContext::ForcedSubtreeVisualRectUpdate;
496 }
494 } 497 }
495 498
496 void PaintInvalidator::processPendingDelayedPaintInvalidations() { 499 void PaintInvalidator::processPendingDelayedPaintInvalidations() {
497 for (auto target : m_pendingDelayedPaintInvalidations) 500 for (auto target : m_pendingDelayedPaintInvalidations) {
498 target->getMutableForPainting().setShouldDoFullPaintInvalidation( 501 target->getMutableForPainting().setShouldDoFullPaintInvalidation(
499 PaintInvalidationDelayedFull); 502 PaintInvalidationDelayedFull);
503 }
500 } 504 }
501 505
502 } // namespace blink 506 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698