diff --git a/third_party/blink/renderer/core/frame/frame_view.cc b/third_party/blink/renderer/core/frame/frame_view.cc index 614d4e23327815..bdd3820baa2b66 100644 --- a/third_party/blink/renderer/core/frame/frame_view.cc +++ b/third_party/blink/renderer/core/frame/frame_view.cc @@ -60,19 +60,17 @@ bool FrameView::DisplayLockedInParentFrame() { return DisplayLockUtilities::LockedInclusiveAncestorPreventingPaint(*owner); } -gfx::Vector2dF FrameView::UpdateViewportIntersection( - unsigned flags, - bool needs_occlusion_tracking) { - if (!(flags & - IntersectionObservation::kFrameViewportIntersectionNeedsUpdate)) { - return min_scroll_delta_to_update_viewport_intersection_; +void FrameView::UpdateViewportIntersection(unsigned flags, + bool needs_occlusion_tracking) { + if (!(flags & IntersectionObservation::kImplicitRootObserversNeedUpdate)) { + return; } // This should only run in child frames. Frame& frame = GetFrame(); HTMLFrameOwnerElement* owner_element = frame.DeprecatedLocalOwner(); if (!owner_element) { - return gfx::Vector2dF(); + return; } Document& owner_document = owner_element->GetDocument(); @@ -98,8 +96,6 @@ gfx::Vector2dF FrameView::UpdateViewportIntersection( // zero size, or it's display locked in parent frame; leave // viewport_intersection empty, and signal the frame as occluded if // necessary. - min_scroll_delta_to_update_viewport_intersection_ = - IntersectionGeometry::kInfiniteScrollDelta; occlusion_state = mojom::blink::FrameOcclusionState::kPossiblyOccluded; } else if (parent_lifecycle_state >= DocumentLifecycle::kLayoutClean && !owner_document.View()->NeedsLayout()) { @@ -117,8 +113,6 @@ gfx::Vector2dF FrameView::UpdateViewportIntersection( /* target_margin */ {}, /* scroll_margin */ {}, geometry_flags, root_geometry); - min_scroll_delta_to_update_viewport_intersection_ = - geometry.MinScrollDeltaToUpdate(); PhysicalRect new_rect_in_parent = geometry.IntersectionRect(); // Convert to DIP @@ -295,7 +289,6 @@ gfx::Vector2dF FrameView::UpdateViewportIntersection( } UpdateRenderThrottlingStatus(should_throttle, subtree_throttled, display_locked_in_parent_frame); - return min_scroll_delta_to_update_viewport_intersection_; } void FrameView::UpdateFrameVisibility(bool intersects_viewport) { diff --git a/third_party/blink/renderer/core/frame/frame_view.h b/third_party/blink/renderer/core/frame/frame_view.h index 83bd881737f24d..5f5ed527eff32a 100644 --- a/third_party/blink/renderer/core/frame/frame_view.h +++ b/third_party/blink/renderer/core/frame/frame_view.h @@ -17,7 +17,6 @@ namespace blink { class Frame; -struct IntersectionUpdateResult; struct IntrinsicSizingInfo; class CORE_EXPORT FrameView : public EmbeddedContentView { @@ -28,7 +27,9 @@ class CORE_EXPORT FrameView : public EmbeddedContentView { // parent_flags is the result of calling GetIntersectionObservationFlags on // the LocalFrameView parent of this FrameView (if any). It contains dirty // bits based on whether geometry may have changed in the parent frame. - virtual IntersectionUpdateResult UpdateViewportIntersectionsForSubtree( + // Returns true if the frame needs occlusion tracking (i.e. trackVisibility() + // is true for any tracked observer in the frame subtree). + virtual bool UpdateViewportIntersectionsForSubtree( unsigned parent_flags, absl::optional& monotonic_time) = 0; @@ -78,17 +79,8 @@ class CORE_EXPORT FrameView : public EmbeddedContentView { const mojom::blink::ViewportIntersectionState& intersection_state) = 0; virtual void VisibilityForThrottlingChanged() = 0; virtual bool LifecycleUpdatesThrottled() const { return false; } - - // Returns the minimum scroll delta in the parent frame to update - // implicit-root intersection observers in this frame. This only affects - // when the parent frame propagates the kImplicitRootObserversNeedUpdate flag - // to this frame during UpdateViewportIntersectionForSubtree(), but doesn't - // affect the kFrameViewportIntersectionNeedsUpdate flag. The return value - // is only based on the intersection relationship between this frame's - // content rect and the viewport. The caller may disregard the result due to - // other constraints. - gfx::Vector2dF UpdateViewportIntersection(unsigned flags, - bool needs_occlusion_tracking); + void UpdateViewportIntersection(unsigned flags, + bool needs_occlusion_tracking); // FrameVisibility is tracked by the browser process, which may suppress // lifecycle updates for a frame outside the viewport. @@ -104,8 +96,6 @@ class CORE_EXPORT FrameView : public EmbeddedContentView { base::TimeTicks rect_in_parent_stable_since_; base::TimeTicks rect_in_parent_stable_since_for_iov2_; blink::mojom::FrameVisibility frame_visibility_; - // Caches the result of UpdateVIewportIntersection(). - gfx::Vector2dF min_scroll_delta_to_update_viewport_intersection_; bool hidden_for_throttling_ = false; bool subtree_throttled_ = false; bool display_locked_ = false; diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc index b078edea36d51c..60c432611f2164 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc @@ -12,6 +12,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/metrics/document_update_reason.h" #include "third_party/blink/renderer/bindings/core/v8/v8_intersection_observer_init.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_union_document_element.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" #include "third_party/blink/renderer/core/paint/timing/paint_timing.h" #include "third_party/blink/renderer/core/testing/intersection_observer_test_helper.h" @@ -691,6 +692,8 @@ class LocalFrameUkmAggregatorSimTest : public SimTest { // Create internal observer IntersectionObserverInit* observer_init = IntersectionObserverInit::Create(); + observer_init->setRoot( + MakeGarbageCollected(&document)); TestIntersectionObserverDelegate* internal_delegate = MakeGarbageCollected( document, LocalFrameUkmAggregator::kLazyLoadIntersectionObserver); @@ -720,7 +723,7 @@ class LocalFrameUkmAggregatorSimTest : public SimTest { EXPECT_EQ( histogram_tester.GetTotalSum( "Blink.IntersectionObservationInternalCount.UpdateTime.PreFCP"), - 4); + RuntimeEnabledFeatures::IntersectionOptimizationEnabled() ? 2 : 4); EXPECT_EQ( histogram_tester.GetTotalSum( "Blink.IntersectionObservationJavascriptCount.UpdateTime.PreFCP"), @@ -734,12 +737,12 @@ class LocalFrameUkmAggregatorSimTest : public SimTest { base::TimeTicks(), base::TimeTicks() + base::Microseconds(10), 0, root_document->UkmSourceID(), root_document->UkmRecorder()); - target1->setAttribute(html_names::kStyleAttr, AtomicString("width: 60px")); + target1->setAttribute(html_names::kStyleAttr, AtomicString("height: 60px")); Compositor().BeginFrame(); EXPECT_EQ( histogram_tester.GetTotalSum( "Blink.IntersectionObservationInternalCount.UpdateTime.PreFCP"), - 4); + RuntimeEnabledFeatures::IntersectionOptimizationEnabled() ? 2 : 4); EXPECT_EQ( histogram_tester.GetTotalSum( "Blink.IntersectionObservationJavascriptCount.UpdateTime.PreFCP"), diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 31c71c0263418c..31c862b5af613a 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc @@ -1048,10 +1048,10 @@ void LocalFrameView::RunIntersectionObserverSteps() { // Populating monotonic_time may be expensive, and may be unnecessary, so // allow it to be populated on demand. absl::optional monotonic_time; - IntersectionUpdateResult result = + bool needs_occlusion_tracking = UpdateViewportIntersectionsForSubtree(0, monotonic_time); if (FrameOwner* owner = frame_->Owner()) - owner->SetNeedsOcclusionTracking(result.needs_occlusion_tracking); + owner->SetNeedsOcclusionTracking(needs_occlusion_tracking); #if DCHECK_IS_ON() DCHECK(was_dirty || !NeedsLayout()); #endif @@ -1067,8 +1067,7 @@ void LocalFrameView::ForceUpdateViewportIntersections() { DocumentUpdateReason::kIntersectionObservation); absl::optional monotonic_time; UpdateViewportIntersectionsForSubtree( - IntersectionObservation::kFrameViewportIntersectionNeedsUpdate | - IntersectionObservation::kImplicitRootObserversNeedUpdate | + IntersectionObservation::kImplicitRootObserversNeedUpdate | IntersectionObservation::kIgnoreDelay, monotonic_time); } @@ -1413,7 +1412,10 @@ void LocalFrameView::ComputePostLayoutIntersections( if (auto* controller = GetFrame().GetDocument()->GetIntersectionObserverController()) { - controller->ComputeIntersections(flags, GetUkmAggregator(), monotonic_time); + controller->ComputeIntersections( + flags, GetUkmAggregator(), monotonic_time, + accumulated_scroll_delta_since_last_intersection_update_); + accumulated_scroll_delta_since_last_intersection_update_ = gfx::Vector2dF(); } for (Frame* child = frame_->Tree().FirstChild(); child; @@ -4175,7 +4177,7 @@ void LocalFrameView::CollectAnnotatedRegions( CollectAnnotatedRegions(*curr, regions); } -IntersectionUpdateResult LocalFrameView::UpdateViewportIntersectionsForSubtree( +bool LocalFrameView::UpdateViewportIntersectionsForSubtree( unsigned parent_flags, absl::optional& monotonic_time) { // TODO(dcheng): Since LocalFrameView tree updates are deferred, FrameViews @@ -4184,41 +4186,20 @@ IntersectionUpdateResult LocalFrameView::UpdateViewportIntersectionsForSubtree( // in lifecycle updates are still needed when there are no more deferred // LocalFrameView updates: https://crbug.com/561683 if (!GetFrame().GetDocument()->IsActive()) { - return IntersectionUpdateResult(); + return false; } unsigned flags = GetIntersectionObservationFlags(parent_flags); - IntersectionUpdateResult result; - if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { - min_scroll_delta_to_update_intersection_ = - IntersectionGeometry::kInfiniteScrollDelta; - } else { - DCHECK_EQ(min_scroll_delta_to_update_intersection_, gfx::Vector2dF()); - } - - bool fully_updated = false; + bool needs_occlusion_tracking = false; if (!NeedsLayout() || IsDisplayLocked()) { // Notify javascript IntersectionObservers if (IntersectionObserverController* controller = GetFrame().GetDocument()->GetIntersectionObserverController()) { - IntersectionUpdateResult observers_result = - controller->ComputeIntersections(flags, GetUkmAggregator(), - monotonic_time); - result.needs_occlusion_tracking = - observers_result.needs_occlusion_tracking; - result.has_implicit_root_observer_with_margin = - observers_result.has_implicit_root_observer_with_margin; - // min_scroll_delta_to_update_intersection_ on this frame is composed - // from the result of updating the IntersectionObservers tracked by this - // frame, and the result of recursive calls to this method for subframes. - // The final value of result.min_scroll_delta_to_update which will be - // returned to the caller is based only on the call to - // UpdateViewportIntersection for this frame. - if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { - min_scroll_delta_to_update_intersection_ = - observers_result.min_scroll_delta_to_update; - } - fully_updated = intersection_observation_state_ >= kDesired; + needs_occlusion_tracking = controller->ComputeIntersections( + flags, GetUkmAggregator(), monotonic_time, + accumulated_scroll_delta_since_last_intersection_update_); + accumulated_scroll_delta_since_last_intersection_update_ = + gfx::Vector2dF(); } intersection_observation_state_ = kNotNeeded; } @@ -4227,40 +4208,22 @@ IntersectionUpdateResult LocalFrameView::UpdateViewportIntersectionsForSubtree( SCOPED_UMA_AND_UKM_TIMER( GetUkmAggregator(), LocalFrameUkmAggregator::kUpdateViewportIntersection); - // The result is the minimum scroll delta in the parent frame to update - // viewport intersection of this frame. - result.min_scroll_delta_to_update = - UpdateViewportIntersection(flags, result.needs_occlusion_tracking); - } - - auto update_result_from_subframe = - [this, &result](const IntersectionUpdateResult& subframe_result) { - result.needs_occlusion_tracking |= - subframe_result.needs_occlusion_tracking; - if (subframe_result.has_implicit_root_observer_with_margin) { - result.has_implicit_root_observer_with_margin = true; - // An implicit-root observer with margin in a subframe requires this - // frame to update intersection observers on every scroll. - min_scroll_delta_to_update_intersection_ = gfx::Vector2dF(); - } else { - min_scroll_delta_to_update_intersection_.SetToMin( - subframe_result.min_scroll_delta_to_update); - } - }; + UpdateViewportIntersection(flags, needs_occlusion_tracking); + } for (Frame* child = frame_->Tree().FirstChild(); child; child = child->Tree().NextSibling()) { - update_result_from_subframe( + needs_occlusion_tracking |= child->View()->UpdateViewportIntersectionsForSubtree(flags, - monotonic_time)); + monotonic_time); } if (DocumentPortals* portals = DocumentPortals::Get(*frame_->GetDocument())) { for (PortalContents* portal : portals->GetPortals()) { if (Frame* frame = portal->GetFrame()) { - update_result_from_subframe( + needs_occlusion_tracking |= frame->View()->UpdateViewportIntersectionsForSubtree( - flags, monotonic_time)); + flags, monotonic_time); } } } @@ -4270,19 +4233,14 @@ IntersectionUpdateResult LocalFrameView::UpdateViewportIntersectionsForSubtree( for (HTMLFencedFrameElement* fenced_frame : fenced_frames->GetFencedFrames()) { if (Frame* frame = fenced_frame->ContentFrame()) { - update_result_from_subframe( + needs_occlusion_tracking |= frame->View()->UpdateViewportIntersectionsForSubtree( - flags, monotonic_time)); + flags, monotonic_time); } } } - if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled() && - fully_updated) { - accumulated_scroll_delta_since_last_intersection_update_ = gfx::Vector2dF(); - } - - return result; + return needs_occlusion_tracking; } void LocalFrameView::DeliverSynchronousIntersectionObservations() { @@ -4412,27 +4370,7 @@ void LocalFrameView::UpdateIntersectionObservationStateOnScroll( gfx::Vector2dF scroll_delta) { accumulated_scroll_delta_since_last_intersection_update_ += gfx::Vector2dF(std::abs(scroll_delta.x()), std::abs(scroll_delta.y())); - if (intersection_observation_state_ >= kDesired) { - return; - } - if (min_scroll_delta_to_update_intersection_.x() <= - accumulated_scroll_delta_since_last_intersection_update_.x() || - min_scroll_delta_to_update_intersection_.y() <= - accumulated_scroll_delta_since_last_intersection_update_.y()) { - // The accumulated scroll delta from all scrollers in this frame has - // exceeded min_scroll_delta_to_update_intersection_ since the last - // intersection observer update, which may change intersection status. - SetIntersectionObservationState(kDesired); - } else { - DCHECK(RuntimeEnabledFeatures::IntersectionOptimizationEnabled()); - // Frame viewport intersection is always updated on scroll, regardless of - // scroll_delta. Situations such as viewport and main frame intersection - // reporting and implicit-root intersection observers with margins in - // remote frames make the optimization not feasible. Nevertheless, frame - // viewport intersection updates are much faster than intersection - // observer updates, based on UMA data. - SetIntersectionObservationState(kFrameViewportIntersectionOnly); - } + SetIntersectionObservationState(kDesired); } void LocalFrameView::InvalidateIntersectionObservations() { @@ -4488,9 +4426,6 @@ unsigned LocalFrameView::GetIntersectionObservationFlags( // Observers with explicit roots only need to be checked on the same frame, // since in this case target and root must be in the same document. if (intersection_observation_state_ != kNotNeeded) { - flags |= IntersectionObservation::kFrameViewportIntersectionNeedsUpdate; - } - if (intersection_observation_state_ >= kDesired) { flags |= (IntersectionObservation::kExplicitRootObserversNeedUpdate | IntersectionObservation::kImplicitRootObserversNeedUpdate); } @@ -4498,8 +4433,7 @@ unsigned LocalFrameView::GetIntersectionObservationFlags( // For observers with implicit roots, we need to check state on the whole // local frame tree, as passed down from the parent. flags |= (parent_flags & - (IntersectionObservation::kFrameViewportIntersectionNeedsUpdate | - IntersectionObservation::kImplicitRootObserversNeedUpdate)); + IntersectionObservation::kImplicitRootObserversNeedUpdate); // The kIgnoreDelay parameter is used to force computation in an OOPIF which // is hidden in the parent document, thus not running lifecycle updates. It diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 0153d84acbb1fc..316f5b9e30c5c9 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h @@ -215,16 +215,11 @@ class CORE_EXPORT LocalFrameView final enum IntersectionObservationState { // The next painting frame does not need an intersection observation. kNotNeeded = 0, - // The next painting frame only needs to update frame viewport intersection, - // not intersection observations. Note that intersection observations in - // child remote frames happen during the parent frame's viewport - // intersection update, with kDesired or kRequired set on the child frames. - kFrameViewportIntersectionOnly = 1, // The next painting frame needs an intersection observation. - kDesired = 2, + kDesired = 1, // The next painting frame must be generated up to intersection observation // (even if frame is throttled). - kRequired = 3 + kRequired = 2 }; // Sets the internal IntersectionObservationState to the max of the @@ -243,10 +238,6 @@ class CORE_EXPORT LocalFrameView final void ForceUpdateViewportIntersections(); - gfx::Vector2dF MinScrollDeltaToUpdateIntersectionForTesting() const { - return min_scroll_delta_to_update_intersection_; - } - void SetPaintArtifactCompositorNeedsUpdate(); // Methods for getting/setting the size Blink should use to layout the @@ -956,7 +947,7 @@ class CORE_EXPORT LocalFrameView final void ForAllRemoteFrameViews(base::FunctionRef); - IntersectionUpdateResult UpdateViewportIntersectionsForSubtree( + bool UpdateViewportIntersectionsForSubtree( unsigned parent_flags, absl::optional& monotonic_time) override; void DeliverSynchronousIntersectionObservations(); @@ -1112,7 +1103,6 @@ class CORE_EXPORT LocalFrameView final #endif IntersectionObservationState intersection_observation_state_; - gfx::Vector2dF min_scroll_delta_to_update_intersection_; gfx::Vector2dF accumulated_scroll_delta_since_last_intersection_update_; mojom::blink::ViewportIntersectionState last_intersection_state_; diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc index 496c327407bd67..2816c041c0f7f5 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_view.cc +++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc @@ -15,7 +15,6 @@ #include "third_party/blink/renderer/core/frame/remote_frame.h" #include "third_party/blink/renderer/core/frame/remote_frame_client.h" #include "third_party/blink/renderer/core/html/html_frame_owner_element.h" -#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/page/page.h" @@ -99,11 +98,11 @@ void RemoteFrameView::DetachFromLayout() { SetAttached(false); } -IntersectionUpdateResult RemoteFrameView::UpdateViewportIntersectionsForSubtree( +bool RemoteFrameView::UpdateViewportIntersectionsForSubtree( unsigned parent_flags, absl::optional&) { UpdateViewportIntersection(parent_flags, needs_occlusion_tracking_); - return IntersectionUpdateResult{needs_occlusion_tracking_}; + return needs_occlusion_tracking_; } void RemoteFrameView::SetViewportIntersection( diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.h b/third_party/blink/renderer/core/frame/remote_frame_view.h index 38ee57658b0a1f..6b442d8de47ecf 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_view.h +++ b/third_party/blink/renderer/core/frame/remote_frame_view.h @@ -59,7 +59,7 @@ class RemoteFrameView final : public GarbageCollected, void Hide() override; void Show() override; - IntersectionUpdateResult UpdateViewportIntersectionsForSubtree( + bool UpdateViewportIntersectionsForSubtree( unsigned parent_flags, absl::optional&) override; void SetNeedsOcclusionTracking(bool); diff --git a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.cc b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.cc index 914369ab935272..021aff12637d03 100644 --- a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.cc +++ b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.cc @@ -66,7 +66,9 @@ bool ElementIntersectionObserverData::ComputeIntersectionsForTarget( absl::optional root_geometry; for (auto& entry : observations_) { needs_occlusion_tracking |= entry.key->NeedsOcclusionTracking(); - entry.value->ComputeIntersection(flags, monotonic_time, root_geometry); + entry.value->ComputeIntersection(flags, + IntersectionGeometry::kInfiniteScrollDelta, + monotonic_time, root_geometry); } return needs_occlusion_tracking; } diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc index ac7c8201e30a01..ce277b93050b98 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc @@ -222,7 +222,7 @@ IntersectionGeometry::IntersectionGeometry( } RootAndTarget root_and_target(root_node, target_element, - !scroll_margin.empty()); + !target_margin.empty(), !scroll_margin.empty()); UpdateShouldUseCachedRects(root_and_target, cached_rects); if (root_and_target.relationship == RootAndTarget::kInvalid) { return; @@ -241,10 +241,11 @@ IntersectionGeometry::IntersectionGeometry( IntersectionGeometry::RootAndTarget::RootAndTarget( const Node* root_node, const Element& target_element, + bool has_target_margin, bool has_scroll_margin) : target(GetTargetLayoutObject(target_element)), root(target ? GetRootLayoutObject(root_node) : nullptr) { - ComputeRelationship(!root_node, has_scroll_margin); + ComputeRelationship(!root_node, has_target_margin, has_scroll_margin); } bool IsAllowedLayoutObjectType(const LayoutObject& target) { @@ -294,6 +295,7 @@ const LayoutObject* IntersectionGeometry::RootAndTarget::GetRootLayoutObject( void IntersectionGeometry::RootAndTarget::ComputeRelationship( bool root_is_implicit, + bool has_target_margin, bool has_scroll_margin) { if (!root || !target || root == target) { relationship = kInvalid; @@ -329,9 +331,9 @@ void IntersectionGeometry::RootAndTarget::ComputeRelationship( relationship = kInvalid; return; } - if (container != root && container->HasNonVisibleOverflow() && - // Non-scrollable scrollers are ignored. - To(container)->HasLayoutOverflow()) { + if (container != root && container->ShouldClipOverflowAlongEitherAxis() && + // Clippers that don't actually clip anything are ignored. + (To(container)->HasLayoutOverflow() || has_target_margin)) { has_intermediate_clippers = true; } if (container != root && has_scroll_margin && @@ -340,7 +342,7 @@ void IntersectionGeometry::RootAndTarget::ComputeRelationship( } } if (has_intermediate_clippers) { - relationship = kScrollableWithIntermediateClippers; + relationship = kHasIntermediateClippers; } else if (root->IsScrollContainer() && To(root)->HasLayoutOverflow()) { relationship = kScrollableByRootOnly; @@ -588,11 +590,10 @@ void IntersectionGeometry::ComputeGeometry(const RootGeometry& root_geometry, root_rect_ = PhysicalRect::EnclosingRect(root_float_rect); } - min_scroll_delta_to_update_ = ComputeMinScrollDeltaToUpdate( - root_and_target, target_to_document_transform, - root_geometry.root_to_document_transform, thresholds, scroll_margin); if (cached_rects) { - cached_rects->min_scroll_delta_to_update = min_scroll_delta_to_update_; + cached_rects->min_scroll_delta_to_update = ComputeMinScrollDeltaToUpdate( + root_and_target, target_to_document_transform, + root_geometry.root_to_document_transform, thresholds, scroll_margin); cached_rects->valid = true; } } @@ -808,7 +809,7 @@ gfx::Vector2dF IntersectionGeometry::ComputeMinScrollDeltaToUpdate( } if (target_rect_.Contains(root_rect_) && root_and_target.relationship == - RootAndTarget::kScrollableWithIntermediateClippers) { + RootAndTarget::kHasIntermediateClippers) { // When target_rect_ fully contains root_rect_, whether the intersection // rect fully covers root_rect_ depends on intermediate clips, so there // is no minimum scroll delta. @@ -823,7 +824,7 @@ gfx::Vector2dF IntersectionGeometry::ComputeMinScrollDeltaToUpdate( } if (root_rect_.Contains(target_rect_) && root_and_target.relationship == - RootAndTarget::kScrollableWithIntermediateClippers) { + RootAndTarget::kHasIntermediateClippers) { // When root_rect_ fully contains target_rect_, whether target_rect_ // is fully visible depends on intermediate clips, so there is no // minimum scroll delta. @@ -846,7 +847,7 @@ gfx::Vector2dF IntersectionGeometry::ComputeMinScrollDeltaToUpdate( if (root_rect_.IntersectsInclusively(target_rect_) && (thresholds.size() != 1 || thresholds[0] > kMinimumThreshold || root_and_target.relationship == - RootAndTarget::kScrollableWithIntermediateClippers || + RootAndTarget::kHasIntermediateClippers || IsForFrameViewportIntersection())) { return gfx::Vector2dF(); } diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h index c8b2338b68fbf5..1cda23a2dbf929 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.h @@ -73,8 +73,10 @@ class CORE_EXPORT IntersectionGeometry { // Target rect mapped up to the root's space, with intermediate clips // applied, but without applying the root's clip or scroll offset. PhysicalRect unscrolled_unclipped_intersection_rect; - // We only need to update intersection geometry on future scroll if - // the scroll delta >= this value in either direction. + // This is calculated basically based on the distance between the root rect + // and the target rect, when it's applicable. On each scroll, we subtract + // the absolute scroll delta from it, and only need to update intersection + // geometry if it becomes <= 0 along either axis. gfx::Vector2dF min_scroll_delta_to_update; // True iff unscrolled_unclipped_intersection_rect actually intersects the // root, as defined by edge-inclusive intersection rules. @@ -139,10 +141,6 @@ class CORE_EXPORT IntersectionGeometry { bool IsIntersecting() const { return threshold_index_ > 0; } bool IsVisible() const { return flags_ & kIsVisible; } - gfx::Vector2dF MinScrollDeltaToUpdate() const { - return min_scroll_delta_to_update_; - } - bool CanUseCachedRectsForTesting() const { return ShouldUseCachedRects(); } private: @@ -158,6 +156,7 @@ class CORE_EXPORT IntersectionGeometry { public: RootAndTarget(const Node* root_node, const Element& target_element, + bool has_target_margin, bool has_scroll_margin); const LayoutObject* target; const LayoutObject* root; @@ -165,14 +164,15 @@ class CORE_EXPORT IntersectionGeometry { kInvalid, // The target is in a sub-frame of the implicit root. kTargetInSubFrame, - // The target can't be scrolled in the root by any scroller. + // There are intermediate clippers (scroll containers or not) between the + // root and the target. The target is likely to be scrollable in root. + kHasIntermediateClippers, + // The target can't be scrolled in the root by any scroller, without any + // intermediate clippers. kNotScrollable, // The target can be scrolled in the root by the root only, without any - // intermediate clippers (scroll containers or not). + // intermediate clippers. kScrollableByRootOnly, - // The target can be scrolled in the root, with intermediate clippers - // (scroll containers or not). - kScrollableWithIntermediateClippers, }; Relationship relationship = kInvalid; // This is used only when relationship is kScrollable*. @@ -182,7 +182,9 @@ class CORE_EXPORT IntersectionGeometry { private: const LayoutObject* GetRootLayoutObject(const Node* root_node) const; - void ComputeRelationship(bool root_is_implicit, bool has_scroll_margin); + void ComputeRelationship(bool root_is_implicit, + bool has_target_margin, + bool has_scroll_margin); }; void UpdateShouldUseCachedRects(const RootAndTarget& root_and_target, @@ -226,7 +228,6 @@ class CORE_EXPORT IntersectionGeometry { PhysicalRect intersection_rect_; PhysicalRect unclipped_intersection_rect_; PhysicalRect root_rect_; - gfx::Vector2dF min_scroll_delta_to_update_; unsigned flags_; double intersection_ratio_ = 0; wtf_size_t threshold_index_ = 0; diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc index d549fb93afcda8..6cd2614d7eee3d 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/intersection_observer/intersection_observation.h" +#include "base/debug/stack_trace.h" #include "third_party/blink/renderer/core/dom/element_rare_data_vector.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h" @@ -16,6 +17,8 @@ #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" +#define CHECK_SKIPPED_UPDATE_ON_SCROLL DCHECK_IS_ON() + namespace blink { namespace { @@ -36,9 +39,12 @@ IntersectionObservation::IntersectionObservation(IntersectionObserver& observer, int64_t IntersectionObservation::ComputeIntersection( unsigned compute_flags, + gfx::Vector2dF accumulated_scroll_delta_since_last_update, absl::optional& monotonic_time, absl::optional& root_geometry) { DCHECK(Observer()); + cached_rects_.min_scroll_delta_to_update -= + accumulated_scroll_delta_since_last_update; if (compute_flags & (observer_->RootIsImplicit() ? kImplicitRootObserversNeedUpdate : kExplicitRootObserversNeedUpdate)) { @@ -52,11 +58,35 @@ int64_t IntersectionObservation::ComputeIntersection( if (MaybeDelayAndReschedule(compute_flags, timestamp)) return 0; +#if CHECK_SKIPPED_UPDATE_ON_SCROLL + std::optional cached_rects_backup; +#endif + if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled() && + cached_rects_.valid && cached_rects_.min_scroll_delta_to_update.x() > 0 && + cached_rects_.min_scroll_delta_to_update.y() > 0) { +#if CHECK_SKIPPED_UPDATE_ON_SCROLL + cached_rects_backup.emplace(cached_rects_); +#else + return 0; +#endif + } + unsigned geometry_flags = GetIntersectionGeometryFlags(compute_flags); IntersectionGeometry geometry( observer_->root(), *Target(), observer_->RootMargin(), observer_->thresholds(), observer_->TargetMargin(), observer_->ScrollMargin(), geometry_flags, root_geometry, &cached_rects_); + +#if CHECK_SKIPPED_UPDATE_ON_SCROLL + if (cached_rects_backup) { + // A skipped update on scroll should generate the same result. + cached_rects_ = cached_rects_backup.value(); + CHECK_EQ(last_threshold_index_, geometry.ThresholdIndex()); + CHECK_EQ(last_is_visible_, geometry.IsVisible()); + return 0; + } +#endif + ProcessIntersectionGeometry(geometry, timestamp); last_run_time_ = timestamp; needs_update_ = false; diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.h b/third_party/blink/renderer/core/intersection_observer/intersection_observation.h index d5b32e2f9a8ca0..bb61d7b457f431 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.h @@ -33,36 +33,30 @@ class CORE_EXPORT IntersectionObservation final // root bounds (i.e., size of the top document's viewport) should be // included in any IntersectionObserverEntry objects created by Compute(). kReportImplicitRootBounds = 1 << 0, - // If this bit is set, we need to update frames' viewport intersection. - // This flag is used in Frame/FrameView only. It doesn't matter to - // intersection observations in the current local frame tree, while - // viewport intersection of the current frame can trigger intersection - // observation updates in child remote frames. - kFrameViewportIntersectionNeedsUpdate = 1 << 1, // If this bit is set, and observer_->RootIsImplicit() is false, then // Compute() should update the observation. - kExplicitRootObserversNeedUpdate = 1 << 2, + kExplicitRootObserversNeedUpdate = 1 << 1, // If this bit is set, and observer_->RootIsImplicit() is true, then // Compute() should update the observation. - kImplicitRootObserversNeedUpdate = 1 << 3, + kImplicitRootObserversNeedUpdate = 1 << 2, // If this bit is set, it indicates that at least one LocalFrameView // ancestor is detached from the LayoutObject tree of its parent. Usually, // this is unnecessary -- if an ancestor FrameView is detached, then all // descendant frames are detached. There is, however, at least one exception // to this rule; see crbug.com/749737 for details. - kAncestorFrameIsDetachedFromLayout = 1 << 4, + kAncestorFrameIsDetachedFromLayout = 1 << 3, // If this bit is set, then the observer.delay parameter is ignored; i.e., // the computation will run even if the previous run happened within the // delay parameter. - kIgnoreDelay = 1 << 5, + kIgnoreDelay = 1 << 4, // If this bit is set, we can skip tracking the sticky frame during // UpdateViewportIntersectionsForSubtree. - kCanSkipStickyFrameTracking = 1 << 6, + kCanSkipStickyFrameTracking = 1 << 5, // If this bit is set, we only process intersection observations that // require post-layout delivery. - kPostLayoutDeliveryOnly = 1 << 7, + kPostLayoutDeliveryOnly = 1 << 6, // If this is set, the overflow clip edge is used. - kUseOverflowClipEdge = 1 << 8, + kUseOverflowClipEdge = 1 << 7, }; IntersectionObservation(IntersectionObserver&, Element&); @@ -73,6 +67,7 @@ class CORE_EXPORT IntersectionObservation final // bool, but int64_t matches IntersectionObserver::ComputeIntersections(). int64_t ComputeIntersection( unsigned flags, + gfx::Vector2dF accumulated_scroll_delta_since_last_update, absl::optional& monotonic_time, absl::optional& root_geometry); gfx::Vector2dF MinScrollDeltaToUpdate() const; diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc index 4bbae548afdb99..32dae8253c21eb 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc @@ -449,7 +449,8 @@ void IntersectionObserver::observe(Element* target, (use_overflow_clip_edge_ ? IntersectionObservation::kUseOverflowClipEdge : 0), - monotonic_time, root_geometry); + IntersectionGeometry::kInfiniteScrollDelta, monotonic_time, + root_geometry); } } @@ -515,45 +516,45 @@ DOMHighResTimeStamp IntersectionObserver::GetTimeStamp( ->MonotonicTimeToDOMHighResTimeStamp(monotonic_time); } -bool IntersectionObserver::HasRootMargin() const { - if (margin_target_ == kApplyMarginToTarget) { - return false; - } - CHECK_EQ(margin_.size(), 4u); - return !margin_[0].IsZero() || !margin_[1].IsZero() || !margin_[2].IsZero() || - !margin_[3].IsZero(); -} - int64_t IntersectionObserver::ComputeIntersections( unsigned flags, - absl::optional& monotonic_time) { + absl::optional& monotonic_time, + gfx::Vector2dF accumulated_scroll_delta_since_last_update) { DCHECK(!RootIsImplicit()); if (!RootIsValid() || !GetExecutionContext() || observations_.empty()) return 0; - // If we're processing post-layout deliveries only and we're not a post-layout - // delivery observer, then return early. Likewise, return if we need to - // compute non-post-layout-delivery observations but the observer behavior is - // post-layout. - bool post_layout_delivery_only = - flags & IntersectionObservation::kPostLayoutDeliveryOnly; - bool is_post_layout_delivery_observer = - GetDeliveryBehavior() == - IntersectionObserver::kDeliverDuringPostLayoutSteps; - if (post_layout_delivery_only != is_post_layout_delivery_observer) - return 0; - if (use_overflow_clip_edge_) flags |= IntersectionObservation::kUseOverflowClipEdge; absl::optional root_geometry; - // TODO(szager): Is this copy necessary? - HeapVector> observations_to_process( - observations_); int64_t result = 0; - for (auto& observation : observations_to_process) { - result += - observation->ComputeIntersection(flags, monotonic_time, root_geometry); + if (RuntimeEnabledFeatures::IntersectionOptimizationEnabled()) { + for (auto& observation : observations_) { + result += observation->ComputeIntersection( + flags, accumulated_scroll_delta_since_last_update, monotonic_time, + root_geometry); + } + } else { + // If we're processing post-layout deliveries only and we're not a + // post-layout delivery observer, then return early. Likewise, return if we + // need to compute non-post-layout-delivery observations but the observer + // behavior is post-layout. + bool post_layout_delivery_only = + flags & IntersectionObservation::kPostLayoutDeliveryOnly; + bool is_post_layout_delivery_observer = + GetDeliveryBehavior() == + IntersectionObserver::kDeliverDuringPostLayoutSteps; + if (post_layout_delivery_only != is_post_layout_delivery_observer) { + return 0; + } + // TODO(szager): Is this copy necessary? + HeapVector> observations_to_process( + observations_); + for (auto& observation : observations_to_process) { + result += observation->ComputeIntersection(flags, gfx::Vector2dF(), + monotonic_time, root_geometry); + } } return result; } diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h index 6dc21a510441a1..d80bdc3d5d0170 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h @@ -172,13 +172,14 @@ class CORE_EXPORT IntersectionObserver final Vector TargetMargin() const { return margin_target_ == kApplyMarginToTarget ? margin_ : Vector(); } - bool HasRootMargin() const; Vector ScrollMargin() const { return scroll_margin_; } // Returns the number of IntersectionObservations that recomputed geometry. - int64_t ComputeIntersections(unsigned flags, - absl::optional& monotonic_time); + int64_t ComputeIntersections( + unsigned flags, + absl::optional& monotonic_time, + gfx::Vector2dF accumulated_scroll_delta_since_last_update); gfx::Vector2dF MinScrollDeltaToUpdate() const; bool IsInternal() const; @@ -225,6 +226,7 @@ class CORE_EXPORT IntersectionObserver final Vector margin_; Vector scroll_margin_; MarginTarget margin_target_; + gfx::Vector2dF accumulated_scroll_delta_since_last_update_; unsigned root_is_implicit_ : 1; unsigned track_visibility_ : 1; unsigned track_fraction_of_root_ : 1; diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc index dce7dd84c4d5d3..c4afd40a45f909 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.cc @@ -60,20 +60,18 @@ void IntersectionObserverController::DeliverNotifications( } } -IntersectionUpdateResult IntersectionObserverController::ComputeIntersections( +bool IntersectionObserverController::ComputeIntersections( unsigned flags, LocalFrameUkmAggregator* metrics_aggregator, - absl::optional& monotonic_time) { + absl::optional& monotonic_time, + gfx::Vector2dF accumulated_scroll_delta_since_last_update) { needs_occlusion_tracking_ = false; if (!GetExecutionContext()) { - return IntersectionUpdateResult(); + return false; } TRACE_EVENT0("blink,devtools.timeline", "IntersectionObserverController::" "computeIntersections"); - bool has_implicit_root_observer_with_margin = false; - gfx::Vector2dF min_scroll_delta_to_update = - IntersectionGeometry::kInfiniteScrollDelta; HeapVector> observers_to_process( tracked_explicit_root_observers_); HeapVector> observations_to_process( @@ -89,13 +87,13 @@ IntersectionUpdateResult IntersectionObserverController::ComputeIntersections( if (observer->HasObservations()) { if (metrics_timer) metrics_timer->StartInterval(observer->GetUkmMetricId()); - int64_t count = observer->ComputeIntersections(flags, monotonic_time); + int64_t count = observer->ComputeIntersections( + flags, monotonic_time, accumulated_scroll_delta_since_last_update); if (observer->IsInternal()) internal_observation_count += count; else javascript_observation_count += count; needs_occlusion_tracking_ |= observer->trackVisibility(); - min_scroll_delta_to_update.SetToMin(observer->MinScrollDeltaToUpdate()); } else { tracked_explicit_root_observers_.erase(observer); } @@ -104,18 +102,14 @@ IntersectionUpdateResult IntersectionObserverController::ComputeIntersections( if (metrics_timer) metrics_timer->StartInterval(observation->Observer()->GetUkmMetricId()); absl::optional root_geometry; - int64_t count = observation->ComputeIntersection(flags, monotonic_time, - root_geometry); + int64_t count = observation->ComputeIntersection( + flags, accumulated_scroll_delta_since_last_update, monotonic_time, + root_geometry); if (observation->Observer()->IsInternal()) internal_observation_count += count; else javascript_observation_count += count; needs_occlusion_tracking_ |= observation->Observer()->trackVisibility(); - has_implicit_root_observer_with_margin |= - observation->Observer()->RootIsImplicit() && - observation->Observer()->HasRootMargin(); - min_scroll_delta_to_update.SetToMin( - observation->MinScrollDeltaToUpdate()); } } @@ -128,9 +122,7 @@ IntersectionUpdateResult IntersectionObserverController::ComputeIntersections( javascript_observation_count); } - return IntersectionUpdateResult{needs_occlusion_tracking_, - has_implicit_root_observer_with_margin, - min_scroll_delta_to_update}; + return needs_occlusion_tracking_; } void IntersectionObserverController::AddTrackedObserver( diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h index cb85860b10e6f7..be3220573ea2a9 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h @@ -18,18 +18,6 @@ namespace blink { class ExecutionContext; -struct IntersectionUpdateResult { - // True if trackVisibility() is true for any tracked observer. - bool needs_occlusion_tracking = false; - // If this is true, the parent frame will use zero min_scroll_delta_to_update, - // i.e. will update intersection on every scroll. - bool has_implicit_root_observer_with_margin = false; - // We only need to update intersection if the accumulated scroll delta in the - // frame exceeds this value in either direction. - gfx::Vector2dF min_scroll_delta_to_update = - IntersectionGeometry::kInfiniteScrollDelta; -}; - class IntersectionObserverController : public GarbageCollected, public ExecutionContextClient, @@ -46,11 +34,14 @@ class IntersectionObserverController // The flags argument is composed of values from // IntersectionObservation::ComputeFlags. They are dirty bits that control - // whether an IntersectionObserver needs to do any work. - IntersectionUpdateResult ComputeIntersections( + // whether an IntersectionObserver needs to do any work. The return value + // communicates whether observer->trackVisibility() is true for any tracked + // observer. + bool ComputeIntersections( unsigned flags, LocalFrameUkmAggregator* metrics_aggregator, - absl::optional& monotonic_time); + absl::optional& monotonic_time, + gfx::Vector2dF accumulated_scroll_delta_since_last_update); // The second argument indicates whether the Element is a target of any // observers for which observer->trackVisibility() is true. diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc index 74d0c43a249960..7d37451d55f14b 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc @@ -1301,8 +1301,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateNotScrollable) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1312,7 +1313,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateNotScrollable) { EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); EXPECT_EQ(IntersectionGeometry::kInfiniteScrollDelta, - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1346,8 +1347,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1356,15 +1358,13 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 50); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); @@ -1373,8 +1373,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1382,14 +1381,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 101); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1397,14 +1394,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(51, 101); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1412,8 +1407,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdZero) { EXPECT_EQ(observer_delegate->CallCount(), 3); EXPECT_EQ(observer_delegate->EntryCount(), 3); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(1, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(1, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1445,8 +1439,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateImplicitRoot) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1455,25 +1450,25 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateImplicitRoot) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); window.scrollTo(0, 50); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kNotNeeded, + frame_view->GetIntersectionObservationStateForTesting()); window.scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1481,14 +1476,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateImplicitRoot) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); window.scrollTo(0, 101); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1496,14 +1489,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateImplicitRoot) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); window.scrollTo(51, 101); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1511,8 +1502,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateImplicitRoot) { EXPECT_EQ(observer_delegate->CallCount(), 3); EXPECT_EQ(observer_delegate->EntryCount(), 3); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(1, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(1, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1549,8 +1539,9 @@ TEST_P(IntersectionObserverTest, ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1559,15 +1550,13 @@ TEST_P(IntersectionObserverTest, EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 50); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); @@ -1576,8 +1565,7 @@ TEST_P(IntersectionObserverTest, EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1585,14 +1573,12 @@ TEST_P(IntersectionObserverTest, EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 101); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1600,8 +1586,7 @@ TEST_P(IntersectionObserverTest, EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1638,8 +1623,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1648,15 +1634,13 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 50); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); @@ -1665,8 +1649,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1674,14 +1657,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 101); - EXPECT_EQ(gfx::Vector2dF(50, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1689,14 +1670,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(51, 101); - EXPECT_EQ(gfx::Vector2dF(50, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1704,8 +1683,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateMinimumThreshold) { EXPECT_EQ(observer_delegate->CallCount(), 3); EXPECT_EQ(observer_delegate->EntryCount(), 3); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(1, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(1, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1741,8 +1719,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThreshold0_5) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1751,25 +1730,23 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThreshold0_5) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 50); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(50, 100), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(50, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(50, 50), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1777,14 +1754,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThreshold0_5) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 101); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1792,14 +1767,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThreshold0_5) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 151); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1807,8 +1780,7 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThreshold0_5) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1845,8 +1817,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOne) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1855,25 +1828,23 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOne) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(20, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(20, 200), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(20, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(20, 200), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_EQ(gfx::Vector2dF(20, 100), observation->MinScrollDeltaToUpdate()); root->scrollTo(0, 200); - EXPECT_EQ(gfx::Vector2dF(20, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(20, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1881,14 +1852,12 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOne) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(20, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(20, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(20, 200); - EXPECT_EQ(gfx::Vector2dF(20, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(20, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1896,19 +1865,18 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOne) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(10, 0), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(10, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(31, 201); + EXPECT_EQ(gfx::Vector2dF(10, 0), observation->MinScrollDeltaToUpdate()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 3); EXPECT_EQ(observer_delegate->EntryCount(), 3); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(1, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(1, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -1952,8 +1920,9 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOneOfRoot) { DummyExceptionStateForTesting exception_state; observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); @@ -1962,25 +1931,23 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOneOfRoot) { EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(30, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(30, 200), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(0, 100); - EXPECT_EQ(gfx::Vector2dF(30, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); - EXPECT_EQ(LocalFrameView::kFrameViewportIntersectionOnly, + EXPECT_EQ(gfx::Vector2dF(30, 200), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_EQ(gfx::Vector2dF(30, 100), observation->MinScrollDeltaToUpdate()); root->scrollTo(30, 200); - EXPECT_EQ(gfx::Vector2dF(30, 200), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(30, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kDesired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); @@ -1988,19 +1955,19 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdOneOfRoot) { EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); + EXPECT_EQ(gfx::Vector2dF(0, 0), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); root->scrollTo(31, 201); + EXPECT_EQ(gfx::Vector2dF(0, 0), observation->MinScrollDeltaToUpdate()); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 3); EXPECT_EQ(observer_delegate->EntryCount(), 3); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); - EXPECT_EQ(gfx::Vector2dF(1, 1), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(1, 1), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -2036,15 +2003,15 @@ TEST_P(IntersectionObserverTest, MinScrollDeltaToUpdateThresholdFilterOnRoot) { ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); - EXPECT_EQ(gfx::Vector2dF(100, 100), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(100, 100), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -2081,15 +2048,15 @@ TEST_P(IntersectionObserverTest, ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -2127,15 +2094,15 @@ TEST_P(IntersectionObserverTest, ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } @@ -2175,15 +2142,15 @@ TEST_P(IntersectionObserverTest, ASSERT_FALSE(exception_state.HadException()); observer->observe(target, exception_state); ASSERT_FALSE(exception_state.HadException()); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + const IntersectionObservation* observation = + target->IntersectionObserverData()->GetObservationFor(*observer); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kRequired, frame_view->GetIntersectionObservationStateForTesting()); Compositor().BeginFrame(); test::RunPendingTasks(); - EXPECT_EQ(gfx::Vector2dF(), - frame_view->MinScrollDeltaToUpdateIntersectionForTesting()); + EXPECT_EQ(gfx::Vector2dF(), observation->MinScrollDeltaToUpdate()); EXPECT_EQ(LocalFrameView::kNotNeeded, frame_view->GetIntersectionObservationStateForTesting()); } diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 628e9de30d219e..3ec72aa4ca6a78 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc @@ -1624,8 +1624,8 @@ void LayoutObject::DeprecatedInvalidateIntersectionObserverCachedRects() { void LayoutObject::InvalidateIntersectionObserverCachedRects() { NOT_DESTROYED(); - if (GetNode() && GetNode()->IsElementNode()) { - if (auto* data = To(GetNode())->IntersectionObserverData()) { + if (const auto* element = DynamicTo(GetNode())) { + if (auto* data = element->IntersectionObserverData()) { data->InvalidateCachedRects(); } } @@ -4579,6 +4579,7 @@ void LayoutObject::SetShouldDoFullPaintInvalidation( DCHECK(IsLayoutFullPaintInvalidationReason(reason)); SetShouldCheckForPaintInvalidation(); SetShouldDoFullPaintInvalidationWithoutLayoutChangeInternal(reason); + InvalidateIntersectionObserverCachedRects(); } void LayoutObject::SetShouldDoFullPaintInvalidationWithoutLayoutChange(