Commit d461a350 authored by Jian Li's avatar Jian Li Committed by Commit Bot

Revert "Reland "Rewrite scroll interruption tests into browser tests""

This reverts commit 7c25668c.

Reason for revert:

Caused test error for https://ci.chromium.org/p/chromium/builders/ci/linux-chromeos-dbg/20645

Original change's description:
> Reland "Rewrite scroll interruption tests into browser tests"
>
> After we finish the scroll unification, the scrolls happens mainly on
> the compositor thread, and the scroll code in the main thread will be
> removed. eventSender sends the scroll events to main thread, so it
> would not work after the scroll unification. We rewrite below tests
> fast/scroll-behavior/main-frame-interrupted-scroll.html,
> fast/scroll-behavior/overflow-interrupted-scroll.html and
> fast/scroll-behavior/subframe-interrupted-scroll.html into browser tests
> because we cannot guarantee that the scroll arrives before the animation
> completes.
>
> TBR=bokan@chromium.org
>
> Bug: 1047176
> Change-Id: I59bb34a98326892380d748a2a4691ea4664cad26
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438652
> Reviewed-by: Lan Wei <lanwei@chromium.org>
> Commit-Queue: Lan Wei <lanwei@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#811936}

TBR=bokan@chromium.org,lanwei@chromium.org

Change-Id: If1db54aa0562084ed90124f9b5e4597e37647378
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1047176
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2441293Reviewed-by: default avatarJian Li <jianli@chromium.org>
Commit-Queue: Jian Li <jianli@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812270}
parent d02e9394
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/renderer_host/input/synthetic_gesture.h"
#include "content/browser/renderer_host/input/synthetic_gesture_controller.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/shell/browser/shell.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/switches.h"
#include "ui/base/ui_base_features.h"
#include "ui/native_theme/native_theme_features.h"
namespace {
constexpr int kIntermediateScrollOffset = 25;
const std::string kOverflowScrollDataURL = R"HTML(
data:text/html;charset=utf-8,
<!DOCTYPE html>
<meta name='viewport' content='width=device-width, minimum-scale=1'>
<style>
%23container {
width: 200px;
height: 200px;
overflow: scroll;
}
%23content {
width: 7500px;
height: 7500px;
background-color: blue;
}
</style>
<div id="container">
<div id="content"></div>
</div>
<script>
var element = document.getElementById('container');
window.onload = function() {
document.title='ready';
}
</script>
)HTML";
const std::string kMainFrameScrollDataURL = R"HTML(
data:text/html;charset=utf-8,
<!DOCTYPE html>
<meta name='viewport' content='width=device-width, minimum-scale=1'>
<style>
%23scrollableDiv {
width: 500px;
height: 10000px;
background-color: blue;
}
</style>
<div id='scrollableDiv'></div>
<script>
window.onload = function() {
document.title='ready';
}
</script>
)HTML";
const std::string kSubframeScrollDataURL = R"HTML(
data:text/html;charset=utf-8,
<!DOCTYPE html>
<meta name='viewport' content='width=device-width, minimum-scale=1'>
<style>
%23subframe {
width: 200px;
height: 200px;
}
</style>
<body onload="document.title='ready'">
<iframe id='subframe' srcdoc="
<style>
%23content {
width: 7500px;
height: 7500px;
background-color: blue;
}
</style>
<div id='content'></div>">
</iframe>
</body>
<script>
var subframe = document.getElementById('subframe');
</script>
)HTML";
} // namespace
namespace content {
// This test is to verify that in-progress smooth scrolls stops when
// interrupted by an instant scroll, another smooth scroll, a touch scroll, or
// a mouse wheel scroll on an overflow:scroll element, main frame and subframe.
class ScrollBehaviorBrowserTest : public ContentBrowserTest,
public testing::WithParamInterface<bool> {
public:
ScrollBehaviorBrowserTest() : disable_threaded_scrolling_(GetParam()) {}
~ScrollBehaviorBrowserTest() override = default;
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
}
void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
run_loop_->Quit();
}
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
if (disable_threaded_scrolling_) {
command_line->AppendSwitch(blink::switches::kDisableThreadedScrolling);
}
// Set the scroll animation duration to 5 seconds so that we ensure
// the second scroll happens before the scroll animation finishes.
command_line->AppendSwitchASCII(
cc::switches::kCCScrollAnimationDurationForTesting, "5");
}
void LoadURL(const std::string page_url) {
const GURL data_url(page_url);
EXPECT_TRUE(NavigateToURL(shell(), data_url));
RenderWidgetHostImpl* host = GetWidgetHost();
host->GetView()->SetSize(gfx::Size(400, 400));
base::string16 ready_title(base::ASCIIToUTF16("ready"));
TitleWatcher watcher(shell()->web_contents(), ready_title);
ignore_result(watcher.WaitAndGetTitle());
HitTestRegionObserver observer(host->GetFrameSinkId());
// Wait for the hit test data to be ready
observer.WaitForHitTestData();
}
double ExecuteScriptAndExtractDouble(const std::string& script) {
double value = 0;
EXPECT_TRUE(content::ExecuteScriptAndExtractDouble(
shell(), "domAutomationController.send(" + script + ")", &value));
return value;
}
WebContentsImpl* web_contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
// The scroll delta values are in the viewport direction. Positive
// scroll_delta_y means scroll down, positive scroll_delta_x means scroll
// right.
void SimulateScroll(
SyntheticGestureParams::GestureSourceType gesture_source_type,
int scroll_delta_x,
int scroll_delta_y) {
auto scroll_update_watcher = std::make_unique<InputMsgWatcher>(
GetWidgetHost(), blink::WebInputEvent::Type::kGestureScrollEnd);
// This speed affects only the rate at which the requested scroll delta is
// sent from the synthetic gesture controller, and doesn't affect the speed
// of the animation in the renderer.
constexpr int kSpeedInstant = 400000;
SyntheticSmoothScrollGestureParams params;
params.gesture_source_type = gesture_source_type;
params.anchor = gfx::PointF(50, 50);
params.distances.push_back(gfx::Vector2d(-scroll_delta_x, -scroll_delta_y));
params.speed_in_pixels_s = kSpeedInstant;
params.granularity = ui::ScrollGranularity::kScrollByPixel;
run_loop_ = std::make_unique<base::RunLoop>();
auto gesture = std::make_unique<SyntheticSmoothScrollGesture>(params);
GetWidgetHost()->QueueSyntheticGesture(
std::move(gesture),
base::BindOnce(&ScrollBehaviorBrowserTest::OnSyntheticGestureCompleted,
base::Unretained(this)));
run_loop_->Run();
}
void WaitForScrollToStart(const std::string& script) {
// When the first smooth scroll starts and scroll to 5 pixels, we will
// send the second scroll to interrupt the current smooth scroll.
constexpr int kExpectedScrollTop = 5;
MainThreadFrameObserver frame_observer(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
while (ExecuteScriptAndExtractDouble(script) < kExpectedScrollTop)
frame_observer.Wait();
}
void WaitUntilLessThan(const std::string& script,
double starting_scroll_top) {
// For the scroll interruption, we want to make sure that the first smooth
// scroll animation stops right away, and the second scroll starts.
MainThreadFrameObserver frame_observer(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
double current = ExecuteScriptAndExtractDouble(script);
// If the animation doesn't reverse within this number of pixels we fail the
// test.
constexpr int kThreshold = 20;
while (current >= starting_scroll_top) {
ASSERT_LT(current, starting_scroll_top + kThreshold);
frame_observer.Wait();
current = ExecuteScriptAndExtractDouble(script);
}
}
void ValueHoldsAt(const std::string& scroll_top_script, double scroll_top) {
// This function checks that the scroll top value holds at the given value
// for 10 frames.
MainThreadFrameObserver frame_observer(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
int frame_count = 10;
while (frame_count > 0) {
ASSERT_EQ(ExecuteScriptAndExtractDouble(scroll_top_script), scroll_top);
frame_observer.Wait();
frame_count--;
}
}
RenderViewHost* GetRenderViewHost() const {
RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
CHECK(rvh);
return rvh;
}
std::unique_ptr<base::RunLoop> run_loop_;
bool disable_threaded_scrolling_ = false;
DISALLOW_COPY_AND_ASSIGN(ScrollBehaviorBrowserTest);
};
INSTANTIATE_TEST_SUITE_P(All, ScrollBehaviorBrowserTest, ::testing::Bool());
// This tests that a in-progress smooth scroll on an overflow:scroll element
// stops when interrupted by an instant scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
OverflowScrollInterruptedByInstantScroll) {
LoadURL(kOverflowScrollDataURL);
EXPECT_TRUE(
ExecuteScript(shell()->web_contents(),
"element.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script = "element.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by an instant scroll, the in-progress smooth scrolls stop.
EXPECT_TRUE(ExecuteScript(shell()->web_contents(), "element.scrollTop = 0;"));
// Instant scroll does not cause animation, it scroll to 0 right away.
// TODO(crbug.com/1133492): the last animation is committed after we set the
// scrollTop even when we cancel the animation, so the final scrollTop value
// is not 0, we need to fix it.
if (!disable_threaded_scrolling_)
ValueHoldsAt(scroll_top_script,
ExecuteScriptAndExtractDouble(scroll_top_script));
else
ValueHoldsAt(scroll_top_script, 0);
}
// This tests that a in-progress smooth scroll on an overflow:scroll element
// stops when interrupted by another smooth scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
OverflowScrollInterruptedBySmoothScroll) {
LoadURL(kOverflowScrollDataURL);
EXPECT_TRUE(
ExecuteScript(shell()->web_contents(),
"element.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script = "element.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by a smooth scroll, the in-progress smooth scrolls stop.
EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
"element.scrollTo({top: 0, behavior: 'smooth'});"));
WaitUntilLessThan(scroll_top_script, scroll_top);
double new_scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
EXPECT_LT(new_scroll_top, scroll_top);
EXPECT_GT(new_scroll_top, 0);
}
// This tests that a in-progress smooth scroll on an overflow:scroll element
// stops when interrupted by a touch scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
OverflowScrollInterruptedByTouchScroll) {
// TODO(crbug.com/1116647): compositing scroll should be able to cancel a
// running programmatic scroll.
if (!disable_threaded_scrolling_)
return;
LoadURL(kOverflowScrollDataURL);
EXPECT_TRUE(
ExecuteScript(shell()->web_contents(),
"element.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script = "element.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by a touch scroll, the in-progress smooth scrolls stop.
SimulateScroll(SyntheticGestureParams::TOUCH_INPUT, 0, -100);
// The touch scroll should cause scroll to 0 and cancel the animation, so
// make sure the value stays at 0.
ValueHoldsAt(scroll_top_script, 0);
}
// This tests that a in-progress smooth scroll on an overflow:scroll element
// stops when interrupted by a mouse wheel scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
OverflowScrollInterruptedByWheelScroll) {
// TODO(crbug.com/1116647): compositing scroll should be able to cancel a
// running programmatic scroll.
if (!disable_threaded_scrolling_)
return;
LoadURL(kOverflowScrollDataURL);
EXPECT_TRUE(
ExecuteScript(shell()->web_contents(),
"element.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script = "element.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by a wheel scroll, the in-progress smooth scrolls stop.
SimulateScroll(SyntheticGestureParams::MOUSE_INPUT, 0, -30);
// Smooth scrolling is disabled for wheel scroll on Mac.
// https://crbug.com/574283.
#if defined(OS_MAC)
ValueHoldsAt(scroll_top_script, 0);
#else
WaitUntilLessThan(scroll_top_script, scroll_top);
double new_scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
EXPECT_LT(new_scroll_top, scroll_top);
EXPECT_GT(new_scroll_top, 0);
#endif
}
// This tests that a in-progress smooth scroll on the main frame stops when
// interrupted by another smooth scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
MainFrameScrollInterruptedBySmoothScroll) {
LoadURL(kMainFrameScrollDataURL);
EXPECT_TRUE(
ExecuteScript(shell()->web_contents(),
"window.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script = "document.scrollingElement.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by a smooth scroll, the in-progress smooth scrolls stop.
EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
"window.scrollTo({top: 0, behavior: 'smooth'});"));
WaitUntilLessThan(scroll_top_script, scroll_top);
double new_scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
EXPECT_LT(new_scroll_top, scroll_top);
EXPECT_GT(new_scroll_top, 0);
}
// This tests that a in-progress smooth scroll on a subframe stops when
// interrupted by another smooth scroll.
IN_PROC_BROWSER_TEST_P(ScrollBehaviorBrowserTest,
SubframeScrollInterruptedBySmoothScroll) {
LoadURL(kSubframeScrollDataURL);
EXPECT_TRUE(ExecuteScript(
shell()->web_contents(),
"subframe.contentWindow.scrollTo({top: 100, behavior: 'smooth'});"));
std::string scroll_top_script =
"subframe.contentDocument.scrollingElement.scrollTop";
WaitForScrollToStart(scroll_top_script);
double scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
ASSERT_GT(scroll_top, 0);
ASSERT_LT(scroll_top, kIntermediateScrollOffset);
// When interrupted by a smooth scroll, the in-progress smooth scrolls stop.
EXPECT_TRUE(ExecuteScript(
shell()->web_contents(),
"subframe.contentWindow.scrollTo({top: 0, behavior: 'smooth'});"));
WaitUntilLessThan(scroll_top_script, scroll_top);
double new_scroll_top = ExecuteScriptAndExtractDouble(scroll_top_script);
EXPECT_LT(new_scroll_top, scroll_top);
EXPECT_GT(new_scroll_top, 0);
}
} // namespace content
...@@ -1049,7 +1049,6 @@ test("content_browsertests") { ...@@ -1049,7 +1049,6 @@ test("content_browsertests") {
"../browser/renderer_host/input/interaction_mq_dynamic_browsertest.cc", "../browser/renderer_host/input/interaction_mq_dynamic_browsertest.cc",
"../browser/renderer_host/input/main_thread_event_queue_browsertest.cc", "../browser/renderer_host/input/main_thread_event_queue_browsertest.cc",
"../browser/renderer_host/input/mouse_latency_browsertest.cc", "../browser/renderer_host/input/mouse_latency_browsertest.cc",
"../browser/renderer_host/input/scroll_behavior_browsertest.cc",
"../browser/renderer_host/input/scroll_latency_browsertest.cc", "../browser/renderer_host/input/scroll_latency_browsertest.cc",
"../browser/renderer_host/input/synthetic_input_browsertest.cc", "../browser/renderer_host/input/synthetic_input_browsertest.cc",
"../browser/renderer_host/input/touch_action_browsertest.cc", "../browser/renderer_host/input/touch_action_browsertest.cc",
......
<!DOCTYPE html>
<html>
<head>
<style>
#content {
width: 1000px;
height: 10000px;
background-color: blue;
}
</style>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/scroll-interruption-test.js"></script>
<script type="text/javascript">
function jsScroll(y) {
window.scrollTo({top: y, behavior: 'smooth'});
}
function doTest() {
const targets = {y_min: 40, y_mid: 3500, y_max: 7000};
const innerPoint = {x: 100, y: 100};
var scrollInterruptionTest = new SmoothScrollInterruptionTest(document.scrollingElement,
innerPoint,
targets,
jsScroll);
scrollInterruptionTest.run();
}
window.addEventListener('load', doTest, false);
</script>
</head>
<body>
<p>Test that interrupting a smooth scroll on the main frame works with both scroll behaviors and with input</p>
<div id="content"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
#container {
width: 200px;
height: 200px;
overflow: scroll;
}
#content {
width: 7500px;
height: 7500px;
background-color: blue;
}
</style>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/scroll-interruption-test.js"></script>
<script type="text/javascript">
function jsScroll(y) {
document.getElementById('container').scrollTo({top: y, behavior: 'smooth'});
}
function doTest() {
const targets = {y_min: 40, y_mid: 3500, y_max: 7000};
const innerPoint = {x: 100, y: 100};
var element = document.getElementById('container');
var scrollInterruptionTest = new SmoothScrollInterruptionTest(element,
innerPoint,
targets,
jsScroll);
scrollInterruptionTest.run();
}
window.addEventListener('load', doTest, false);
</script>
</head>
<body>
<p>Test that interrupting a smooth scroll on an overflow:scroll element works with both scroll behaviors and with input</p>
<div id="container">
<div id="content"></div>
</div>
</body>
</html>
// A SmoothScrollInterruptionTest verifies that in-progress smooth scrolls
// stop when interrupted by an instant scroll, another smooth scroll, a
// touch scroll, or a mouse wheel scroll.
//
// The only SmoothScrollInerruptionTest method that should be called by
// outside code is run().
//
// Creates a SmoothScrollInterruptionTest with arguments:
// scrollElement - Element being scrolled.
// innerPoint - Absolute position (expressed as a dictionary with x and y fields)
// of a point inside |scrollElement|, that can be used as the location
// of input events that trigger scrolls on |scrollElement|.
// targets - A dictionary whose members y_min, y_mid, and y_max should be
// y co-ordinates that are far enough apart from each other that a
// smooth scroll between any pair of them will be non-trivial (that
// is, take multiple frames to finish), and should be such that
// y_min < y_mid < y_max.
// jsScroll - Callback that takes a y co-ordinate and executes a js-driven
// smooth scroll to that y co-ordinate.
function SmoothScrollInterruptionTest(scrollElement, innerPoint, targets, jsScroll) {
this.scrollElement = scrollElement;
this.innerPoint = innerPoint;
this.scrollStartPoint = targets.y_mid;
this.scrollEndPoint = targets.y_max;
this.scrollNewEndpoint = targets.y_min;
this.jsScroll = jsScroll;
this.testCases = [];
this.testCases.push(new SmoothScrollInterruptionTestCase(interruptWithInstantScroll, verifyScrollInterruptedByInstantScroll, "instant scroll"));
this.testCases.push(new SmoothScrollInterruptionTestCase(interruptWithSmoothScroll, verifyScrollInterruptedBySmoothScroll, "smooth scroll"));
this.testCases.push(new SmoothScrollInterruptionTestCase(interruptWithTouchScroll, verifyScrollInterruptedByInputDrivenScroll, "touch scroll"));
this.testCases.push(new SmoothScrollInterruptionTestCase(interruptWithWheelScroll, verifyScrollInterruptedByInputDrivenScroll, "wheel scroll"));
this.currentTestCase = 0;
}
SmoothScrollInterruptionTest.prototype.startNextTestCase = function() {
if (this.currentTestCase >= this.testCases.length) {
this.allTestCasesComplete();
return;
}
var testCase = this.testCases[this.currentTestCase];
this.asyncTest = async_test(testCase.description);
var scrollElement = this.scrollElement;
var scrollStartPoint = this.scrollStartPoint;
scrollElement.scrollTop = scrollStartPoint;
window.requestAnimationFrame(this.waitForSyncScroll.bind(this));
}
SmoothScrollInterruptionTest.prototype.waitForSyncScroll = function() {
// Wait until cc has received the commit from main with the scrollStartPoint.
if (this.scrollElement.scrollTop != this.scrollStartPoint) {
// TODO(flackr): There seems to be a bug in that we shouldn't have to
// reapply the scroll position when cancelling a smooth scroll.
// https://crbug.com/667477
this.scrollElement.scrollTop = this.scrollStartPoint;
window.requestAnimationFrame(this.waitForSyncScroll.bind(this));
return;
}
this.performSmoothScroll();
}
SmoothScrollInterruptionTest.prototype.performSmoothScroll = function() {
var testCase = this.testCases[this.currentTestCase];
var scrollElement = this.scrollElement;
var scrollStartPoint = this.scrollStartPoint;
this.jsScroll(this.scrollEndPoint);
this.asyncTest.step(function() {
assert_equals(scrollElement.scrollTop, scrollStartPoint);
});
if (scrollElement.scrollTop == this.scrollEndPoint) {
// We've instant-scrolled, and failed the assert above.
this.testCaseComplete();
return;
}
window.requestAnimationFrame(this.waitForSmoothScrollStart.bind(this));
}
SmoothScrollInterruptionTest.prototype.waitForSmoothScrollStart = function() {
if (this.scrollElement.scrollTop == this.scrollStartPoint) {
window.requestAnimationFrame(this.waitForSmoothScrollStart.bind(this));
return;
}
var testCase = this.testCases[this.currentTestCase];
testCase.interruptSmoothScroll(this);
window.requestAnimationFrame(testCase.verifyScrollInterrupted.bind(testCase, this, this.testCaseComplete.bind(this)));
}
SmoothScrollInterruptionTest.prototype.testCaseComplete = function() {
this.asyncTest.done();
this.currentTestCase++;
this.startNextTestCase();
}
SmoothScrollInterruptionTest.prototype.run = function() {
setup({explicit_done: true, explicit_timeout: true});
this.startNextTestCase();
}
SmoothScrollInterruptionTest.prototype.allTestCasesComplete = function() {
done();
}
// A SmoothScrollInterruptionTestCase represents a single way of interrupting
// a smooth scroll and verifying that the smooth scroll gets canceled.
//
// Creates a SmoothScrollInterruptionTestCase with arguments:
// interruptSmoothScoll - Callback that takes a SmoothScrollInterruptionTest,
// and interrupts the on-going smooth scroll.
// verifyScrollInterrupted - Callback that takes a SmoothScrollInterruptionTest,
// a |verificationComplete| callback, and a timestamp,
// verifies (possibly asynchronously) that the smooth
// scroll has been superseded by the interruption, and
// then calls |verificationComplete|.
// description - String describing this test case.
function SmoothScrollInterruptionTestCase(interruptSmoothScroll, verifyScrollInterrupted, description) {
this.interruptSmoothScroll = interruptSmoothScroll;
this.verifyScrollInterrupted = verifyScrollInterrupted;
this.description = description;
}
function interruptWithInstantScroll(smoothScrollTest) {
smoothScrollTest.scrollElement.scrollTop = smoothScrollTest.scrollNewEndpoint;
smoothScrollTest.asyncTest.step(function() {
assert_equals(smoothScrollTest.scrollElement.scrollTop, smoothScrollTest.scrollNewEndpoint);
});
}
function verifyScrollInterruptedByInstantScroll(smoothScrollTest, verificationComplete) {
smoothScrollTest.asyncTest.step(function() {
assert_equals(smoothScrollTest.scrollElement.scrollTop, smoothScrollTest.scrollNewEndpoint);
});
verificationComplete();
}
function interruptWithSmoothScroll(smoothScrollTest) {
smoothScrollTest.jsScroll(smoothScrollTest.scrollNewEndpoint);
smoothScrollTest.asyncTest.step(function() {
assert_not_equals(smoothScrollTest.scrollElement.scrollTop, smoothScrollTest.scrollNewEndpoint);
});
this.scrollInterruptionPoint = smoothScrollTest.scrollElement.scrollTop;
}
function verifyScrollInterruptedBySmoothScroll(smoothScrollTest, verificationComplete) {
var currentPosition = smoothScrollTest.scrollElement.scrollTop;
if (currentPosition < this.scrollInterruptionPoint && currentPosition >= smoothScrollTest.scrollNewEndpoint) {
verificationComplete();
} else {
window.requestAnimationFrame(this.verifyScrollInterrupted.bind(this, smoothScrollTest, verificationComplete));
}
}
function interruptWithTouchScroll(smoothScrollTest) {
if (window.eventSender) {
eventSender.gestureScrollBegin(smoothScrollTest.innerPoint.x, smoothScrollTest.innerPoint.y);
eventSender.gestureScrollUpdate(0, -10);
eventSender.gestureScrollEnd(0, 0);
} else {
document.write("This test does not work in manual mode.");
}
}
function verifyScrollInterruptedByInputDrivenScroll(smoothScrollTest, verificationComplete, timestamp) {
var currentPosition = smoothScrollTest.scrollElement.scrollTop;
if (this.previousPosition && this.previousPosition == currentPosition) {
// Ensure that the animation has really stopped, not that we just have
// two frames that are so close together that the animation only seems to
// have stopped.
if (timestamp - this.previousTimestamp > 16) {
verificationComplete();
} else {
window.requestAnimationFrame(this.verifyScrollInterrupted.bind(this, smoothScrollTest, verificationComplete));
}
return;
}
this.previousPosition = currentPosition;
this.previousTimestamp = timestamp;
smoothScrollTest.asyncTest.step(function() {
assert_not_equals(currentPosition, smoothScrollTest.scrollEndPoint);
});
window.requestAnimationFrame(this.verifyScrollInterrupted.bind(this, smoothScrollTest, verificationComplete));
}
function interruptWithWheelScroll(smoothScrollTest) {
if (window.eventSender) {
eventSender.mouseMoveTo(smoothScrollTest.innerPoint.x, smoothScrollTest.innerPoint.y);
eventSender.mouseScrollBy(0, -10);
} else {
document.write("This test does not work in manual mode.");
}
}
<!DOCTYPE html>
<html>
<head>
<style>
#subframe {
width: 200px;
height: 200px;
}
</style>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/scroll-interruption-test.js"></script>
<script type="text/javascript">
function jsScroll(y) {
var subframe = document.getElementById('subframe');
subframe.contentWindow.scrollTo({top: y, behavior: 'smooth'});
}
function doTest()
{
const targets = {y_min: 40, y_mid: 3500, y_max: 7000};
const innerPoint = {x: 100, y: 100}
var subframeScrollingElement = document.getElementById('subframe').contentDocument.scrollingElement;
var scrollInterruptionTest = new SmoothScrollInterruptionTest(subframeScrollingElement,
innerPoint,
targets,
jsScroll);
scrollInterruptionTest.run();
}
window.addEventListener('load', doTest, false);
</script>
</head>
<body>
<p>Test that interrupting a smooth scroll on a subframe works with both scroll behaviors and with input</p>
<iframe id="subframe" src="resources/large-subframe.html"></iframe>
</body>
</html>
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