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

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

Powered by Google App Engine
This is Rietveld 408576698