Commit 389cf84d authored by szager's avatar szager Committed by Commit bot

IntersectionObserver: use post task inside of resume().

Rather than running callbacks immediately, post a task to run the
callbacks, to avoid conflicts while undeferring a page.

R=dcheng@chromium.org
BUG=670092

Review-Url: https://codereview.chromium.org/2565863002
Cr-Commit-Position: refs/heads/master@{#438043}
parent 2e30a3df
...@@ -26,9 +26,7 @@ IntersectionObserverController::IntersectionObserverController( ...@@ -26,9 +26,7 @@ IntersectionObserverController::IntersectionObserverController(
IntersectionObserverController::~IntersectionObserverController() {} IntersectionObserverController::~IntersectionObserverController() {}
void IntersectionObserverController::scheduleIntersectionObserverForDelivery( void IntersectionObserverController::postTaskToDeliverObservations() {
IntersectionObserver& observer) {
m_pendingIntersectionObservers.add(&observer);
if (!m_weakPtrFactory.hasWeakPtrs()) { if (!m_weakPtrFactory.hasWeakPtrs()) {
// TODO(ojan): These tasks decide whether to throttle a subframe, so they // TODO(ojan): These tasks decide whether to throttle a subframe, so they
// need to be unthrottled, but we should throttle all the other tasks // need to be unthrottled, but we should throttle all the other tasks
...@@ -41,12 +39,18 @@ void IntersectionObserverController::scheduleIntersectionObserverForDelivery( ...@@ -41,12 +39,18 @@ void IntersectionObserverController::scheduleIntersectionObserverForDelivery(
} }
} }
void IntersectionObserverController::scheduleIntersectionObserverForDelivery(
IntersectionObserver& observer) {
m_pendingIntersectionObservers.add(&observer);
postTaskToDeliverObservations();
}
void IntersectionObserverController::resume() { void IntersectionObserverController::resume() {
// If the callback fired while DOM objects were suspended, notifications might // If the callback fired while DOM objects were suspended, notifications might
// be late, so deliver them right away (rather than waiting to fire again). // be late, so deliver them right away (rather than waiting to fire again).
if (m_callbackFiredWhileSuspended) { if (m_callbackFiredWhileSuspended) {
m_callbackFiredWhileSuspended = false; m_callbackFiredWhileSuspended = false;
deliverIntersectionObservations(); postTaskToDeliverObservations();
} }
} }
......
...@@ -39,6 +39,7 @@ class IntersectionObserverController ...@@ -39,6 +39,7 @@ class IntersectionObserverController
private: private:
explicit IntersectionObserverController(Document*); explicit IntersectionObserverController(Document*);
void postTaskToDeliverObservations();
private: private:
// IntersectionObservers for which this is the tracking document. // IntersectionObservers for which this is the tracking document.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "core/dom/IntersectionObserverCallback.h" #include "core/dom/IntersectionObserverCallback.h"
#include "core/dom/IntersectionObserverInit.h" #include "core/dom/IntersectionObserverInit.h"
#include "core/frame/FrameView.h"
#include "platform/testing/UnitTestHelpers.h" #include "platform/testing/UnitTestHelpers.h"
#include "web/WebViewImpl.h" #include "web/WebViewImpl.h"
#include "web/tests/sim/SimCompositor.h" #include "web/tests/sim/SimCompositor.h"
...@@ -67,4 +68,63 @@ TEST_F(IntersectionObserverTest, ObserveSchedulesFrame) { ...@@ -67,4 +68,63 @@ TEST_F(IntersectionObserverTest, ObserveSchedulesFrame) {
EXPECT_TRUE(compositor().needsBeginFrame()); EXPECT_TRUE(compositor().needsBeginFrame());
} }
TEST_F(IntersectionObserverTest, ResumePostsTask) {
webView().resize(WebSize(800, 600));
SimRequest mainResource("https://example.com/", "text/html");
loadURL("https://example.com/");
mainResource.complete(
"<div id='leading-space' style='height: 700px;'></div>"
"<div id='target'></div>"
"<div id='trailing-space' style='height: 700px;'></div>");
IntersectionObserverInit observerInit;
DummyExceptionStateForTesting exceptionState;
TestIntersectionObserverCallback* observerCallback =
new TestIntersectionObserverCallback(document());
IntersectionObserver* observer = IntersectionObserver::create(
observerInit, *observerCallback, exceptionState);
ASSERT_FALSE(exceptionState.hadException());
Element* target = document().getElementById("target");
ASSERT_TRUE(target);
observer->observe(target, exceptionState);
compositor().beginFrame();
testing::runPendingTasks();
EXPECT_EQ(observerCallback->callCount(), 0);
// When document is not suspended, beginFrame() will generate notifications
// and post a task to deliver them.
document().view()->layoutViewportScrollableArea()->setScrollOffset(
ScrollOffset(0, 300), ProgrammaticScroll);
compositor().beginFrame();
EXPECT_EQ(observerCallback->callCount(), 0);
testing::runPendingTasks();
EXPECT_EQ(observerCallback->callCount(), 1);
// When a document is suspended, beginFrame() will generate a notification,
// but it will not be delivered. The notification will, however, be
// available via takeRecords();
document().suspendScheduledTasks();
document().view()->layoutViewportScrollableArea()->setScrollOffset(
ScrollOffset(0, 0), ProgrammaticScroll);
compositor().beginFrame();
EXPECT_EQ(observerCallback->callCount(), 1);
testing::runPendingTasks();
EXPECT_EQ(observerCallback->callCount(), 1);
EXPECT_FALSE(observer->takeRecords(exceptionState).isEmpty());
// Generate a notification while document is suspended; then resume document.
// Notification should happen in a post task.
document().view()->layoutViewportScrollableArea()->setScrollOffset(
ScrollOffset(0, 300), ProgrammaticScroll);
compositor().beginFrame();
testing::runPendingTasks();
EXPECT_EQ(observerCallback->callCount(), 1);
document().resumeScheduledTasks();
EXPECT_EQ(observerCallback->callCount(), 1);
testing::runPendingTasks();
EXPECT_EQ(observerCallback->callCount(), 2);
}
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment