diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc | 281 |
1 files changed, 242 insertions, 39 deletions
diff --git a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc index 0df836d2d53..c867a3d46d0 100644 --- a/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc +++ b/chromium/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc @@ -4,10 +4,13 @@ #include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h" +#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_delegate.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_init.h" +#include "third_party/blink/renderer/core/layout/layout_view.h" +#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/testing/sim/sim_compositor.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" @@ -24,49 +27,49 @@ class TestIntersectionObserverDelegate : public IntersectionObserverDelegate { public: TestIntersectionObserverDelegate(Document& document) : document_(document), call_count_(0) {} - void Deliver(const HeapVector<Member<IntersectionObserverEntry>>& entry, + void Deliver(const HeapVector<Member<IntersectionObserverEntry>>& entries, IntersectionObserver&) override { call_count_++; - - if (!entry.back()->intersectionRect()) { - last_intersection_rect_ = FloatRect(); - } else { - last_intersection_rect_ = - FloatRect(entry.back()->intersectionRect()->x(), - entry.back()->intersectionRect()->y(), - entry.back()->intersectionRect()->width(), - entry.back()->intersectionRect()->height()); - } + entries_.AppendVector(entries); } ExecutionContext* GetExecutionContext() const override { return document_; } int CallCount() const { return call_count_; } - FloatRect LastIntersectionRect() const { return last_intersection_rect_; } + int EntryCount() const { return entries_.size(); } + const IntersectionObserverEntry* LastEntry() const { return entries_.back(); } + FloatRect LastIntersectionRect() const { + if (entries_.IsEmpty()) + return FloatRect(); + const IntersectionObserverEntry* entry = entries_.back(); + return FloatRect(entry->intersectionRect()->x(), + entry->intersectionRect()->y(), + entry->intersectionRect()->width(), + entry->intersectionRect()->height()); + } void Trace(blink::Visitor* visitor) override { IntersectionObserverDelegate::Trace(visitor); visitor->Trace(document_); + visitor->Trace(entries_); } private: - FloatRect last_intersection_rect_; Member<Document> document_; + HeapVector<Member<IntersectionObserverEntry>> entries_; int call_count_; }; } // namespace -class IntersectionObserverTest - : public testing::WithParamInterface<bool>, - public SimTest, - ScopedIntersectionObserverGeometryMapperForTest { +class IntersectionObserverTest : public SimTest {}; + +class IntersectionObserverV2Test : public IntersectionObserverTest, + public ScopedIntersectionObserverV2ForTest { public: - IntersectionObserverTest() - : ScopedIntersectionObserverGeometryMapperForTest(GetParam()) {} + IntersectionObserverV2Test() + : IntersectionObserverTest(), ScopedIntersectionObserverV2ForTest(true) {} }; -INSTANTIATE_TEST_CASE_P(All, IntersectionObserverTest, testing::Bool()); - -TEST_P(IntersectionObserverTest, ObserveSchedulesFrame) { +TEST_F(IntersectionObserverTest, ObserveSchedulesFrame) { SimRequest main_resource("https://example.com/", "text/html"); LoadURL("https://example.com/"); main_resource.Complete("<div id='target'></div>"); @@ -90,7 +93,7 @@ TEST_P(IntersectionObserverTest, ObserveSchedulesFrame) { EXPECT_TRUE(Compositor().NeedsBeginFrame()); } -TEST_P(IntersectionObserverTest, ResumePostsTask) { +TEST_F(IntersectionObserverTest, ResumePostsTask) { WebView().Resize(WebSize(800, 600)); SimRequest main_resource("https://example.com/", "text/html"); LoadURL("https://example.com/"); @@ -118,8 +121,8 @@ TEST_P(IntersectionObserverTest, ResumePostsTask) { // When document is not suspended, beginFrame() will generate notifications // and post a task to deliver them. - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 300), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 300), + kProgrammaticScroll); Compositor().BeginFrame(); EXPECT_EQ(observer_delegate->CallCount(), 1); test::RunPendingTasks(); @@ -129,8 +132,8 @@ TEST_P(IntersectionObserverTest, ResumePostsTask) { // but it will not be delivered. The notification will, however, be // available via takeRecords(); GetDocument().PauseScheduledTasks(); - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 0), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 0), + kProgrammaticScroll); Compositor().BeginFrame(); EXPECT_EQ(observer_delegate->CallCount(), 2); test::RunPendingTasks(); @@ -139,8 +142,8 @@ TEST_P(IntersectionObserverTest, ResumePostsTask) { // Generate a notification while document is suspended; then resume document. // Notification should happen in a post task. - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 300), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 300), + kProgrammaticScroll); Compositor().BeginFrame(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 2); @@ -150,7 +153,54 @@ TEST_P(IntersectionObserverTest, ResumePostsTask) { EXPECT_EQ(observer_delegate->CallCount(), 3); } -TEST_P(IntersectionObserverTest, DisconnectClearsNotifications) { +TEST_F(IntersectionObserverTest, HitTestAfterMutation) { + WebView().Resize(WebSize(800, 600)); + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + main_resource.Complete(R"HTML( + <div id='leading-space' style='height: 700px;'></div> + <div id='target'></div> + <div id='trailing-space' style='height: 700px;'></div> + )HTML"); + + IntersectionObserverInit observer_init; + DummyExceptionStateForTesting exception_state; + TestIntersectionObserverDelegate* observer_delegate = + new TestIntersectionObserverDelegate(GetDocument()); + IntersectionObserver* observer = IntersectionObserver::Create( + observer_init, *observer_delegate, exception_state); + ASSERT_FALSE(exception_state.HadException()); + + Element* target = GetDocument().getElementById("target"); + ASSERT_TRUE(target); + observer->observe(target, exception_state); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + EXPECT_EQ(observer_delegate->CallCount(), 1); + + GetDocument().View()->ScheduleAnimation(); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + EXPECT_EQ(observer_delegate->CallCount(), 1); + + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 300), + kProgrammaticScroll); + + HitTestLocation location(LayoutPoint(0, 0)); + HitTestResult result( + HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive | + HitTestRequest::kAllowChildFrameContent), + location); + GetDocument().View()->GetLayoutView()->HitTest(location, result); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + EXPECT_EQ(observer_delegate->CallCount(), 2); +} + +TEST_F(IntersectionObserverTest, DisconnectClearsNotifications) { WebView().Resize(WebSize(800, 600)); SimRequest main_resource("https://example.com/", "text/html"); LoadURL("https://example.com/"); @@ -178,15 +228,15 @@ TEST_P(IntersectionObserverTest, DisconnectClearsNotifications) { // If disconnect() is called while an observer has unsent notifications, // those notifications should be discarded. - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 300), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 300), + kProgrammaticScroll); Compositor().BeginFrame(); observer->disconnect(); test::RunPendingTasks(); EXPECT_EQ(observer_delegate->CallCount(), 1); } -TEST_P(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) { +TEST_F(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) { WebView().GetSettings()->SetForceZeroLayoutHeight(true); WebView().Resize(WebSize(800, 600)); SimRequest main_resource("https://example.com/", "text/html"); @@ -227,8 +277,8 @@ TEST_P(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) { ASSERT_EQ(observer_delegate->CallCount(), 1); EXPECT_TRUE(observer_delegate->LastIntersectionRect().IsEmpty()); - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 600), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 600), + kProgrammaticScroll); Compositor().BeginFrame(); test::RunPendingTasks(); ASSERT_EQ(observer_delegate->CallCount(), 2); @@ -236,16 +286,15 @@ TEST_P(IntersectionObserverTest, RootIntersectionWithForceZeroLayoutHeight) { EXPECT_EQ(FloatRect(200, 400, 100, 100), observer_delegate->LastIntersectionRect()); - GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset( - ScrollOffset(0, 1200), kProgrammaticScroll); + GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 1200), + kProgrammaticScroll); Compositor().BeginFrame(); test::RunPendingTasks(); ASSERT_EQ(observer_delegate->CallCount(), 3); EXPECT_TRUE(observer_delegate->LastIntersectionRect().IsEmpty()); } -TEST_P(IntersectionObserverTest, TrackVisibilityInit) { - ScopedIntersectionObserverV2ForTest iov2_enabled(true); +TEST_F(IntersectionObserverV2Test, TrackVisibilityInit) { IntersectionObserverInit observer_init; DummyExceptionStateForTesting exception_state; TestIntersectionObserverDelegate* observer_delegate = @@ -259,4 +308,158 @@ TEST_P(IntersectionObserverTest, TrackVisibilityInit) { EXPECT_TRUE(observer->trackVisibility()); } +TEST_F(IntersectionObserverV2Test, BasicOcclusion) { + WebView().Resize(WebSize(800, 600)); + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + main_resource.Complete(R"HTML( + <style> + div { + width: 100px; + height: 100px; + } + </style> + <div id='target'> + <div id='child'></div> + </div> + <div id='occluder'></div> + )HTML"); + + IntersectionObserverInit observer_init; + observer_init.setTrackVisibility(true); + DummyExceptionStateForTesting exception_state; + TestIntersectionObserverDelegate* observer_delegate = + new TestIntersectionObserverDelegate(GetDocument()); + IntersectionObserver* observer = IntersectionObserver::Create( + observer_init, *observer_delegate, exception_state); + ASSERT_FALSE(exception_state.HadException()); + Element* target = GetDocument().getElementById("target"); + Element* occluder = GetDocument().getElementById("occluder"); + ASSERT_TRUE(target); + observer->observe(target); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 1); + EXPECT_EQ(observer_delegate->EntryCount(), 1); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_TRUE(observer_delegate->LastEntry()->isVisible()); + + occluder->SetInlineStyleProperty(CSSPropertyMarginTop, "-10px"); + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 2); + EXPECT_EQ(observer_delegate->EntryCount(), 2); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_FALSE(observer_delegate->LastEntry()->isVisible()); +} + +TEST_F(IntersectionObserverV2Test, BasicOpacity) { + WebView().Resize(WebSize(800, 600)); + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + main_resource.Complete(R"HTML( + <style> + div { + width: 100px; + height: 100px; + } + </style> + <div id='transparent'> + <div id='target'></div> + </div> + )HTML"); + + IntersectionObserverInit observer_init; + observer_init.setTrackVisibility(true); + DummyExceptionStateForTesting exception_state; + TestIntersectionObserverDelegate* observer_delegate = + new TestIntersectionObserverDelegate(GetDocument()); + IntersectionObserver* observer = IntersectionObserver::Create( + observer_init, *observer_delegate, exception_state); + ASSERT_FALSE(exception_state.HadException()); + Element* target = GetDocument().getElementById("target"); + Element* transparent = GetDocument().getElementById("transparent"); + ASSERT_TRUE(target); + ASSERT_TRUE(transparent); + observer->observe(target); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 1); + EXPECT_EQ(observer_delegate->EntryCount(), 1); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_TRUE(observer_delegate->LastEntry()->isVisible()); + + transparent->SetInlineStyleProperty(CSSPropertyOpacity, "0.99"); + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 2); + EXPECT_EQ(observer_delegate->EntryCount(), 2); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_FALSE(observer_delegate->LastEntry()->isVisible()); +} + +TEST_F(IntersectionObserverV2Test, BasicTransform) { + WebView().Resize(WebSize(800, 600)); + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + main_resource.Complete(R"HTML( + <style> + div { + width: 100px; + height: 100px; + } + </style> + <div id='transformed'> + <div id='target'></div> + </div> + )HTML"); + + IntersectionObserverInit observer_init; + observer_init.setTrackVisibility(true); + DummyExceptionStateForTesting exception_state; + TestIntersectionObserverDelegate* observer_delegate = + new TestIntersectionObserverDelegate(GetDocument()); + IntersectionObserver* observer = IntersectionObserver::Create( + observer_init, *observer_delegate, exception_state); + ASSERT_FALSE(exception_state.HadException()); + Element* target = GetDocument().getElementById("target"); + Element* transformed = GetDocument().getElementById("transformed"); + ASSERT_TRUE(target); + ASSERT_TRUE(transformed); + observer->observe(target); + + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 1); + EXPECT_EQ(observer_delegate->EntryCount(), 1); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_TRUE(observer_delegate->LastEntry()->isVisible()); + + // 2D translations and proportional upscaling is permitted. + transformed->SetInlineStyleProperty( + CSSPropertyTransform, "translateX(10px) translateY(20px) scale(2)"); + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 1); + EXPECT_EQ(observer_delegate->EntryCount(), 1); + + // Any other transform is not permitted. + transformed->SetInlineStyleProperty(CSSPropertyTransform, "skewX(10deg)"); + Compositor().BeginFrame(); + test::RunPendingTasks(); + ASSERT_FALSE(Compositor().NeedsBeginFrame()); + EXPECT_EQ(observer_delegate->CallCount(), 2); + EXPECT_EQ(observer_delegate->EntryCount(), 2); + EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); + EXPECT_FALSE(observer_delegate->LastEntry()->isVisible()); +} + } // namespace blink |