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 |