| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/layout/PaintInvalidationState.h" | 5 #include "core/layout/PaintInvalidationState.h" |
| 6 | 6 |
| 7 #include "core/frame/FrameView.h" | 7 #include "core/frame/FrameView.h" |
| 8 #include "core/frame/LocalFrame.h" | 8 #include "core/frame/LocalFrame.h" |
| 9 #include "core/frame/Settings.h" | 9 #include "core/frame/Settings.h" |
| 10 #include "core/layout/LayoutInline.h" | 10 #include "core/layout/LayoutInline.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 clipped_(false), | 42 clipped_(false), |
| 43 clipped_for_absolute_position_(false), | 43 clipped_for_absolute_position_(false), |
| 44 cached_offsets_enabled_(true), | 44 cached_offsets_enabled_(true), |
| 45 cached_offsets_for_absolute_position_enabled_(true), | 45 cached_offsets_for_absolute_position_enabled_(true), |
| 46 paint_invalidation_container_( | 46 paint_invalidation_container_( |
| 47 &layout_view.ContainerForPaintInvalidation()), | 47 &layout_view.ContainerForPaintInvalidation()), |
| 48 paint_invalidation_container_for_stacked_contents_( | 48 paint_invalidation_container_for_stacked_contents_( |
| 49 paint_invalidation_container_), | 49 paint_invalidation_container_), |
| 50 container_for_absolute_position_(layout_view), | 50 container_for_absolute_position_(layout_view), |
| 51 pending_delayed_paint_invalidations_(pending_delayed_paint_invalidations), | 51 pending_delayed_paint_invalidations_(pending_delayed_paint_invalidations), |
| 52 painting_layer_(*layout_view.Layer()) | 52 painting_layer_(*layout_view.Layer()) { |
| 53 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 54 , | |
| 55 m_canCheckFastPathSlowPathEquality(layoutView == | |
| 56 m_paintInvalidationContainer) | |
| 57 #endif | |
| 58 { | |
| 59 DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); | 53 DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); |
| 60 | 54 |
| 61 if (!SupportsCachedOffsets(layout_view)) { | 55 if (!SupportsCachedOffsets(layout_view)) { |
| 62 cached_offsets_enabled_ = false; | 56 cached_offsets_enabled_ = false; |
| 63 return; | 57 return; |
| 64 } | 58 } |
| 65 | 59 |
| 66 FloatPoint point = layout_view.LocalToAncestorPoint( | 60 FloatPoint point = layout_view.LocalToAncestorPoint( |
| 67 FloatPoint(), paint_invalidation_container_, | 61 FloatPoint(), paint_invalidation_container_, |
| 68 kTraverseDocumentBoundaries | kInputIsInFrameCoordinates); | 62 kTraverseDocumentBoundaries | kInputIsInFrameCoordinates); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 91 paint_invalidation_container_(parent_state.paint_invalidation_container_), | 85 paint_invalidation_container_(parent_state.paint_invalidation_container_), |
| 92 paint_invalidation_container_for_stacked_contents_( | 86 paint_invalidation_container_for_stacked_contents_( |
| 93 parent_state.paint_invalidation_container_for_stacked_contents_), | 87 parent_state.paint_invalidation_container_for_stacked_contents_), |
| 94 container_for_absolute_position_( | 88 container_for_absolute_position_( |
| 95 current_object.CanContainAbsolutePositionObjects() | 89 current_object.CanContainAbsolutePositionObjects() |
| 96 ? current_object | 90 ? current_object |
| 97 : parent_state.container_for_absolute_position_), | 91 : parent_state.container_for_absolute_position_), |
| 98 svg_transform_(parent_state.svg_transform_), | 92 svg_transform_(parent_state.svg_transform_), |
| 99 pending_delayed_paint_invalidations_( | 93 pending_delayed_paint_invalidations_( |
| 100 parent_state.pending_delayed_paint_invalidations_), | 94 parent_state.pending_delayed_paint_invalidations_), |
| 101 painting_layer_(parent_state.ChildPaintingLayer(current_object)) | 95 painting_layer_(parent_state.ChildPaintingLayer(current_object)) { |
| 102 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 103 , | |
| 104 m_canCheckFastPathSlowPathEquality( | |
| 105 parentState.m_canCheckFastPathSlowPathEquality) | |
| 106 #endif | |
| 107 { | |
| 108 DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); | 96 DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()); |
| 109 DCHECK_EQ(&painting_layer_, current_object.PaintingLayer()); | 97 DCHECK_EQ(&painting_layer_, current_object.PaintingLayer()); |
| 110 | 98 |
| 111 if (current_object == parent_state.current_object_) { | 99 if (current_object == parent_state.current_object_) { |
| 112 // Sometimes we create a new PaintInvalidationState from parentState on the same | 100 // Sometimes we create a new PaintInvalidationState from parentState on the same |
| 113 // object (e.g. LayoutView, and the HorriblySlowRectMapping cases in | 101 // object (e.g. LayoutView, and the HorriblySlowRectMapping cases in |
| 114 // LayoutBlock::invalidatePaintOfSubtreesIfNeeded()). | 102 // LayoutBlock::invalidatePaintOfSubtreesIfNeeded()). |
| 115 // TODO(wangxianzhu): Avoid this for | 103 // TODO(wangxianzhu): Avoid this for |
| 116 // RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled(). | 104 // RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled(). |
| 117 #if DCHECK_IS_ON() | 105 #if DCHECK_IS_ON() |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 // offset to adjust m_paintOffsetForAbsolutePosition. | 203 // offset to adjust m_paintOffsetForAbsolutePosition. |
| 216 UpdateForCurrentObject(parent_state); | 204 UpdateForCurrentObject(parent_state); |
| 217 paint_offset_for_absolute_position_ -= paint_offset_; | 205 paint_offset_for_absolute_position_ -= paint_offset_; |
| 218 if (clipped_for_absolute_position_) | 206 if (clipped_for_absolute_position_) |
| 219 clip_rect_for_absolute_position_.Move(-paint_offset_); | 207 clip_rect_for_absolute_position_.Move(-paint_offset_); |
| 220 } | 208 } |
| 221 } | 209 } |
| 222 | 210 |
| 223 clipped_ = false; // Will be updated in updateForChildren(). | 211 clipped_ = false; // Will be updated in updateForChildren(). |
| 224 paint_offset_ = LayoutSize(); | 212 paint_offset_ = LayoutSize(); |
| 225 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 226 m_canCheckFastPathSlowPathEquality = true; | |
| 227 #endif | |
| 228 return; | 213 return; |
| 229 } | 214 } |
| 230 | 215 |
| 231 UpdateForCurrentObject(parent_state); | 216 UpdateForCurrentObject(parent_state); |
| 232 } | 217 } |
| 233 | 218 |
| 234 PaintLayer& PaintInvalidationState::ChildPaintingLayer( | 219 PaintLayer& PaintInvalidationState::ChildPaintingLayer( |
| 235 const LayoutObject& child) const { | 220 const LayoutObject& child) const { |
| 236 if (child.HasLayer() && ToLayoutBoxModelObject(child).HasSelfPaintingLayer()) | 221 if (child.HasLayer() && ToLayoutBoxModelObject(child).HasSelfPaintingLayer()) |
| 237 return *ToLayoutBoxModelObject(child).Layer(); | 222 return *ToLayoutBoxModelObject(child).Layer(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 if (paint_invalidation_container_->IsBox()) { | 254 if (paint_invalidation_container_->IsBox()) { |
| 270 const LayoutBox* box = ToLayoutBox(paint_invalidation_container_); | 255 const LayoutBox* box = ToLayoutBox(paint_invalidation_container_); |
| 271 if (box->HasOverflowClip()) | 256 if (box->HasOverflowClip()) |
| 272 fixed_offset.Move(box->ScrolledContentOffset()); | 257 fixed_offset.Move(box->ScrolledContentOffset()); |
| 273 } | 258 } |
| 274 paint_offset_ = LayoutSize(fixed_offset.X(), fixed_offset.Y()); | 259 paint_offset_ = LayoutSize(fixed_offset.X(), fixed_offset.Y()); |
| 275 // In the above way to get paint offset, we can't get accurate clip rect, so | 260 // In the above way to get paint offset, we can't get accurate clip rect, so |
| 276 // just assume no clip. Clip on fixed-position is rare, in case that | 261 // just assume no clip. Clip on fixed-position is rare, in case that |
| 277 // paintInvalidationContainer crosses frame boundary and the LayoutView is | 262 // paintInvalidationContainer crosses frame boundary and the LayoutView is |
| 278 // clipped by something in owner document. | 263 // clipped by something in owner document. |
| 279 if (clipped_) { | 264 clipped_ = false; |
| 280 clipped_ = false; | |
| 281 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 282 m_canCheckFastPathSlowPathEquality = false; | |
| 283 #endif | |
| 284 } | |
| 285 return; | 265 return; |
| 286 } | 266 } |
| 287 | 267 |
| 288 if (position == EPosition::kAbsolute) { | 268 if (position == EPosition::kAbsolute) { |
| 289 cached_offsets_enabled_ = cached_offsets_for_absolute_position_enabled_; | 269 cached_offsets_enabled_ = cached_offsets_for_absolute_position_enabled_; |
| 290 if (!cached_offsets_enabled_) | 270 if (!cached_offsets_enabled_) |
| 291 return; | 271 return; |
| 292 | 272 |
| 293 paint_offset_ = paint_offset_for_absolute_position_; | 273 paint_offset_ = paint_offset_for_absolute_position_; |
| 294 clipped_ = clipped_for_absolute_position_; | 274 clipped_ = clipped_for_absolute_position_; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 // visual rect change for layout caused invalidation. | 414 // visual rect change for layout caused invalidation. |
| 435 if (current_object_.IsText()) | 415 if (current_object_.IsText()) |
| 436 return visual_rect_location; | 416 return visual_rect_location; |
| 437 | 417 |
| 438 FloatPoint point; | 418 FloatPoint point; |
| 439 if (paint_invalidation_container_ != ¤t_object_) { | 419 if (paint_invalidation_container_ != ¤t_object_) { |
| 440 if (cached_offsets_enabled_) { | 420 if (cached_offsets_enabled_) { |
| 441 if (current_object_.IsSVGChild()) | 421 if (current_object_.IsSVGChild()) |
| 442 point = svg_transform_.MapPoint(point); | 422 point = svg_transform_.MapPoint(point); |
| 443 point += FloatPoint(paint_offset_); | 423 point += FloatPoint(paint_offset_); |
| 444 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 445 DCHECK_EQ(point, slowLocalOriginToAncestorPoint( | |
| 446 m_currentObject, m_paintInvalidationContainer, | |
| 447 FloatPoint())); | |
| 448 #endif | |
| 449 } else { | 424 } else { |
| 450 point = SlowLocalToAncestorPoint( | 425 point = SlowLocalToAncestorPoint( |
| 451 current_object_, *paint_invalidation_container_, FloatPoint()); | 426 current_object_, *paint_invalidation_container_, FloatPoint()); |
| 452 } | 427 } |
| 453 } | 428 } |
| 454 | 429 |
| 455 PaintLayer::MapPointInPaintInvalidationContainerToBacking( | 430 PaintLayer::MapPointInPaintInvalidationContainerToBacking( |
| 456 *paint_invalidation_container_, point); | 431 *paint_invalidation_container_, point); |
| 457 | 432 |
| 458 point.Move(current_object_.ScrollAdjustmentForPaintInvalidation( | 433 point.Move(current_object_.ScrollAdjustmentForPaintInvalidation( |
| (...skipping 17 matching lines...) Expand all Loading... |
| 476 | 451 |
| 477 LayoutRect PaintInvalidationState::ComputeVisualRectInBackingForSVG() const { | 452 LayoutRect PaintInvalidationState::ComputeVisualRectInBackingForSVG() const { |
| 478 LayoutRect rect; | 453 LayoutRect rect; |
| 479 if (cached_offsets_enabled_) { | 454 if (cached_offsets_enabled_) { |
| 480 FloatRect svg_rect = SVGLayoutSupport::LocalVisualRect(current_object_); | 455 FloatRect svg_rect = SVGLayoutSupport::LocalVisualRect(current_object_); |
| 481 rect = SVGLayoutSupport::TransformVisualRect(current_object_, | 456 rect = SVGLayoutSupport::TransformVisualRect(current_object_, |
| 482 svg_transform_, svg_rect); | 457 svg_transform_, svg_rect); |
| 483 rect.Move(paint_offset_); | 458 rect.Move(paint_offset_); |
| 484 if (clipped_) | 459 if (clipped_) |
| 485 rect.Intersect(clip_rect_); | 460 rect.Intersect(clip_rect_); |
| 486 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 487 LayoutRect slowPathRect = SVGLayoutSupport::visualRectInAncestorSpace( | |
| 488 m_currentObject, *m_paintInvalidationContainer); | |
| 489 assertFastPathAndSlowPathRectsEqual(rect, slowPathRect); | |
| 490 #endif | |
| 491 } else { | 461 } else { |
| 492 // TODO(wangxianzhu): Sometimes m_cachedOffsetsEnabled==false doesn't mean | 462 // TODO(wangxianzhu): Sometimes m_cachedOffsetsEnabled==false doesn't mean |
| 493 // we can't use cached m_svgTransform. We can use hybrid fast path (for SVG) | 463 // we can't use cached m_svgTransform. We can use hybrid fast path (for SVG) |
| 494 // and slow path (for things above the SVGRoot). | 464 // and slow path (for things above the SVGRoot). |
| 495 rect = SVGLayoutSupport::VisualRectInAncestorSpace( | 465 rect = SVGLayoutSupport::VisualRectInAncestorSpace( |
| 496 current_object_, *paint_invalidation_container_); | 466 current_object_, *paint_invalidation_container_); |
| 497 } | 467 } |
| 498 | 468 |
| 499 PaintLayer::MapRectInPaintInvalidationContainerToBacking( | 469 PaintLayer::MapRectInPaintInvalidationContainerToBacking( |
| 500 *paint_invalidation_container_, rect); | 470 *paint_invalidation_container_, rect); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 526 } | 496 } |
| 527 } | 497 } |
| 528 | 498 |
| 529 void PaintInvalidationState::MapLocalRectToPaintInvalidationContainer( | 499 void PaintInvalidationState::MapLocalRectToPaintInvalidationContainer( |
| 530 LayoutRect& rect) const { | 500 LayoutRect& rect) const { |
| 531 #if DCHECK_IS_ON() | 501 #if DCHECK_IS_ON() |
| 532 DCHECK(!did_update_for_children_); | 502 DCHECK(!did_update_for_children_); |
| 533 #endif | 503 #endif |
| 534 | 504 |
| 535 if (cached_offsets_enabled_) { | 505 if (cached_offsets_enabled_) { |
| 536 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 537 LayoutRect slowPathRect(rect); | |
| 538 slowMapToVisualRectInAncestorSpace( | |
| 539 m_currentObject, *m_paintInvalidationContainer, slowPathRect); | |
| 540 #endif | |
| 541 rect.Move(paint_offset_); | 506 rect.Move(paint_offset_); |
| 542 if (clipped_) | 507 if (clipped_) |
| 543 rect.Intersect(clip_rect_); | 508 rect.Intersect(clip_rect_); |
| 544 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 545 assertFastPathAndSlowPathRectsEqual(rect, slowPathRect); | |
| 546 #endif | |
| 547 } else { | 509 } else { |
| 548 SlowMapToVisualRectInAncestorSpace(current_object_, | 510 SlowMapToVisualRectInAncestorSpace(current_object_, |
| 549 *paint_invalidation_container_, rect); | 511 *paint_invalidation_container_, rect); |
| 550 } | 512 } |
| 551 } | 513 } |
| 552 | 514 |
| 553 void PaintInvalidationState::MapLocalRectToVisualRectInBacking( | 515 void PaintInvalidationState::MapLocalRectToVisualRectInBacking( |
| 554 LayoutRect& rect) const { | 516 LayoutRect& rect) const { |
| 555 MapLocalRectToPaintInvalidationContainer(rect); | 517 MapLocalRectToPaintInvalidationContainer(rect); |
| 556 | 518 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 573 clip_rect_ = clip_rect; | 535 clip_rect_ = clip_rect; |
| 574 clipped_ = true; | 536 clipped_ = true; |
| 575 } | 537 } |
| 576 } | 538 } |
| 577 | 539 |
| 578 PaintLayer& PaintInvalidationState::PaintingLayer() const { | 540 PaintLayer& PaintInvalidationState::PaintingLayer() const { |
| 579 DCHECK_EQ(&painting_layer_, current_object_.PaintingLayer()); | 541 DCHECK_EQ(&painting_layer_, current_object_.PaintingLayer()); |
| 580 return painting_layer_; | 542 return painting_layer_; |
| 581 } | 543 } |
| 582 | 544 |
| 583 #ifdef CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 584 | |
| 585 static bool mayHaveBeenSaturated(LayoutUnit value) { | |
| 586 // This is not accurate, just to avoid too big values. | |
| 587 return value.abs() >= LayoutUnit::max() / 2; | |
| 588 } | |
| 589 | |
| 590 static bool mayHaveBeenSaturated(const LayoutRect& rect) { | |
| 591 return mayHaveBeenSaturated(rect.x()) || mayHaveBeenSaturated(rect.y()) || | |
| 592 mayHaveBeenSaturated(rect.width()) || | |
| 593 mayHaveBeenSaturated(rect.height()); | |
| 594 } | |
| 595 | |
| 596 void PaintInvalidationState::assertFastPathAndSlowPathRectsEqual( | |
| 597 const LayoutRect& fastPathRect, | |
| 598 const LayoutRect& slowPathRect) const { | |
| 599 if (!m_canCheckFastPathSlowPathEquality) | |
| 600 return; | |
| 601 | |
| 602 // TODO(crbug.com/597903): Fast path and slow path should generate equal empty | |
| 603 // rects. | |
| 604 if (fastPathRect.isEmpty() && slowPathRect.isEmpty()) | |
| 605 return; | |
| 606 | |
| 607 if (fastPathRect == slowPathRect) | |
| 608 return; | |
| 609 | |
| 610 // LayoutUnit uses saturated arithmetic operations. If any interim or final | |
| 611 // result is saturated, the same operations in different order produce | |
| 612 // different results. Don't compare results if any of them may have been | |
| 613 // saturated. | |
| 614 if (mayHaveBeenSaturated(fastPathRect) || mayHaveBeenSaturated(slowPathRect)) | |
| 615 return; | |
| 616 | |
| 617 // Tolerate the difference between the two paths when crossing frame | |
| 618 // boundaries. | |
| 619 if (m_currentObject.view() != m_paintInvalidationContainer->view()) { | |
| 620 LayoutRect inflatedFastPathRect = fastPathRect; | |
| 621 inflatedFastPathRect.inflate(1); | |
| 622 if (inflatedFastPathRect.contains(slowPathRect)) | |
| 623 return; | |
| 624 LayoutRect inflatedSlowPathRect = slowPathRect; | |
| 625 inflatedSlowPathRect.inflate(1); | |
| 626 if (inflatedSlowPathRect.contains(fastPathRect)) | |
| 627 return; | |
| 628 } | |
| 629 | |
| 630 LOG(ERROR) << "Fast path visual rect differs from slow path: fast: " | |
| 631 << fastPathRect.toString() | |
| 632 << " vs slow: " << slowPathRect.toString(); | |
| 633 showLayoutTree(&m_currentObject); | |
| 634 | |
| 635 NOTREACHED(); | |
| 636 } | |
| 637 | |
| 638 #endif // CHECK_FAST_PATH_SLOW_PATH_EQUALITY | |
| 639 | |
| 640 PaintInvalidatorContextAdapter::PaintInvalidatorContextAdapter( | 545 PaintInvalidatorContextAdapter::PaintInvalidatorContextAdapter( |
| 641 const PaintInvalidationState& paint_invalidation_state) | 546 const PaintInvalidationState& paint_invalidation_state) |
| 642 : PaintInvalidatorContext(nullptr), | 547 : PaintInvalidatorContext(nullptr), |
| 643 paint_invalidation_state_(paint_invalidation_state) { | 548 paint_invalidation_state_(paint_invalidation_state) { |
| 644 forced_subtree_invalidation_flags = | 549 forced_subtree_invalidation_flags = |
| 645 paint_invalidation_state.forced_subtree_invalidation_flags_; | 550 paint_invalidation_state.forced_subtree_invalidation_flags_; |
| 646 paint_invalidation_container = | 551 paint_invalidation_container = |
| 647 &paint_invalidation_state.PaintInvalidationContainer(); | 552 &paint_invalidation_state.PaintInvalidationContainer(); |
| 648 painting_layer = &paint_invalidation_state.PaintingLayer(); | 553 painting_layer = &paint_invalidation_state.PaintingLayer(); |
| 649 } | 554 } |
| 650 | 555 |
| 651 void PaintInvalidatorContextAdapter::MapLocalRectToVisualRectInBacking( | 556 void PaintInvalidatorContextAdapter::MapLocalRectToVisualRectInBacking( |
| 652 const LayoutObject& object, | 557 const LayoutObject& object, |
| 653 LayoutRect& rect) const { | 558 LayoutRect& rect) const { |
| 654 DCHECK_EQ(&object, &paint_invalidation_state_.CurrentObject()); | 559 DCHECK_EQ(&object, &paint_invalidation_state_.CurrentObject()); |
| 655 paint_invalidation_state_.MapLocalRectToVisualRectInBacking(rect); | 560 paint_invalidation_state_.MapLocalRectToVisualRectInBacking(rect); |
| 656 } | 561 } |
| 657 | 562 |
| 658 } // namespace blink | 563 } // namespace blink |
| OLD | NEW |