Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: third_party/WebKit/Source/web/tests/RootScrollerTest.cpp

Issue 1913843004: Implementing document.setRootScroller API for main thread scrolling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@overscrollController
Patch Set: Fixing bad rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/page/scrolling/RootScroller.h"
6
7 #include "core/frame/FrameHost.h"
8 #include "core/frame/FrameView.h"
9 #include "core/frame/TopControls.h"
10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "core/page/Page.h"
12 #include "platform/testing/URLTestHelpers.h"
13 #include "platform/testing/UnitTestHelpers.h"
14 #include "public/platform/Platform.h"
15 #include "public/platform/WebURLLoaderMockFactory.h"
16 #include "public/web/WebCache.h"
17 #include "public/web/WebConsoleMessage.h"
18 #include "public/web/WebScriptSource.h"
19 #include "public/web/WebSettings.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "web/WebLocalFrameImpl.h"
22 #include "web/tests/FrameTestHelpers.h"
23 #include "wtf/Vector.h"
24
25 using blink::testing::runPendingTasks;
26 using testing::Mock;
27
28 namespace blink {
29
30 namespace {
31
32 class RootScrollerTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
33 public:
34 MOCK_METHOD4(didOverscroll, void(const WebFloatSize&, const WebFloatSize&, c onst WebFloatPoint&, const WebFloatSize&));
35 };
36
37 class RootScrollerTest : public ::testing::Test {
38 public:
39 RootScrollerTest()
40 : m_baseURL("http://www.test.com/")
41 {
42 registerMockedHttpURLLoad("overflow-scrolling.html");
43 registerMockedHttpURLLoad("root-scroller.html");
44 registerMockedHttpURLLoad("root-scroller-iframe.html");
45 registerMockedHttpURLLoad("root-scroller-child.html");
46 }
47
48 ~RootScrollerTest() override
49 {
50 Platform::current()->getURLLoaderMockFactory()->unregisterAllURLs();
51 WebCache::clear();
52 }
53
54 WebViewImpl* initialize(const std::string& pageName)
55 {
56 RuntimeEnabledFeatures::setSetRootScrollerEnabled(true);
jbroman 2016/04/27 19:21:29 I don't think you clear this state right now. Woul
bokan 2016/04/27 20:26:39 Good catch. Fixed using the pattern in FrameViewTe
57
58 // Load a page with large body and set viewport size to 400x400 to
59 // ensure main frame is scrollable.
60 m_helper.initializeAndLoad(
61 m_baseURL + pageName, true, 0, &m_client, &configureSettings);
62
63 // Initialize top controls to be shown.
64 webViewImpl()->resizeWithTopControls(IntSize(400, 400), 50, true);
65 webViewImpl()->topControls().setShownRatio(1);
66
67 mainFrameView()->updateAllLifecyclePhases();
68
69 return webViewImpl();
70 }
71
72 static void configureSettings(WebSettings* settings)
73 {
74 settings->setJavaScriptEnabled(true);
75 settings->setAcceleratedCompositingEnabled(true);
76 settings->setPreferCompositingToLCDTextEnabled(true);
77 // Android settings.
78 settings->setViewportEnabled(true);
79 settings->setViewportMetaEnabled(true);
80 settings->setShrinksViewportContentToFit(true);
81 settings->setMainFrameResizesAreOrientationChanges(true);
82 }
83
84 void registerMockedHttpURLLoad(const std::string& fileName)
85 {
86 URLTestHelpers::registerMockedURLFromBaseURL(
87 WebString::fromUTF8(m_baseURL.c_str()),
88 WebString::fromUTF8(fileName.c_str()));
89 }
90
91 void executeScript(const WebString& code)
92 {
93 mainWebFrame()->executeScript(WebScriptSource(code));
94 mainWebFrame()->view()->updateAllLifecyclePhases();
95 runPendingTasks();
96 }
97
98 WebGestureEvent generateEvent(
99 WebInputEvent::Type type, int deltaX = 0, int deltaY = 0)
100 {
101 WebGestureEvent event;
102 event.type = type;
103 event.sourceDevice = WebGestureDeviceTouchscreen;
104 event.x = 100;
105 event.y = 100;
106 if (type == WebInputEvent::GestureScrollUpdate) {
107 event.data.scrollUpdate.deltaX = deltaX;
108 event.data.scrollUpdate.deltaY = deltaY;
109 }
110 return event;
111 }
112
113 void verticalScroll(float deltaY)
114 {
115 webViewImpl()->handleInputEvent(
116 generateEvent(WebInputEvent::GestureScrollBegin));
117 webViewImpl()->handleInputEvent(
118 generateEvent(WebInputEvent::GestureScrollUpdate, 0, -deltaY));
119 webViewImpl()->handleInputEvent(
120 generateEvent(WebInputEvent::GestureScrollEnd));
121 }
122
123 WebViewImpl* webViewImpl() const
124 {
125 return m_helper.webViewImpl();
126 }
127
128 FrameHost& frameHost() const
129 {
130 return m_helper.webViewImpl()->page()->frameHost();
131 }
132
133 LocalFrame* mainFrame() const
134 {
135 return toWebLocalFrameImpl(webViewImpl()->mainFrame())->frame();
136 }
137
138 WebLocalFrame* mainWebFrame() const
139 {
140 return toWebLocalFrameImpl(webViewImpl()->mainFrame());
141 }
142
143 FrameView* mainFrameView() const
144 {
145 return webViewImpl()->mainFrameImpl()->frame()->view();
146 }
147
148 VisualViewport& visualViewport() const
149 {
150 return frameHost().visualViewport();
151 }
152
153 RootScroller& rootScroller() const
154 {
155 return *frameHost().rootScroller();
156 }
157
158 TopControls& topControls() const
159 {
160 return frameHost().topControls();
161 }
162
163 protected:
164 std::string m_baseURL;
165 RootScrollerTestWebViewClient m_client;
166 FrameTestHelpers::WebViewHelper m_helper;
167 };
168
169 // Test that a default root scroller element is set if setRootScroller isn't
170 // called on any elements.
171 TEST_F(RootScrollerTest, TestDefaultRootScroller)
172 {
173 initialize("overflow-scrolling.html");
174
175 EXPECT_EQ(
176 mainFrame()->document()->documentElement(),
177 rootScroller().get());
178 }
179
180 // Tests that setting an element as the root scroller causes it to control url
181 // bar hiding and overscroll.
182 TEST_F(RootScrollerTest, TestSetRootScroller)
183 {
184 initialize("root-scroller.html");
185
186 Element* container = mainFrame()->document()->getElementById("container");
187 TrackExceptionState exceptionState;
188 mainFrame()->document()->setRootScroller(container, exceptionState);
189 ASSERT_EQ(container, mainFrame()->document()->rootScroller());
190
191 // Content is 1000x1000, WebView size is 400x400 so max scroll is 600px.
192 double maximumScroll = 600;
193
194 webViewImpl()->handleInputEvent(
195 generateEvent(WebInputEvent::GestureScrollBegin));
196
197 {
198 // Scrolling over the #container DIV should cause the top controls to
199 // hide.
200 ASSERT_FLOAT_EQ(1, topControls().shownRatio());
201 webViewImpl()->handleInputEvent(generateEvent(
202 WebInputEvent::GestureScrollUpdate, 0, -topControls().height()));
203 ASSERT_FLOAT_EQ(0, topControls().shownRatio());
204 }
205
206 {
207 // Make sure we're actually scrolling the DIV and not the FrameView.
208 webViewImpl()->handleInputEvent(
209 generateEvent(WebInputEvent::GestureScrollUpdate, 0, -100));
210 ASSERT_FLOAT_EQ(100, container->scrollTop());
211 ASSERT_FLOAT_EQ(0, mainFrameView()->scrollPositionDouble().y());
212 }
213
214 {
215 // Scroll 50 pixels past the end. Ensure we report the 50 pixels as
216 // overscroll.
217 EXPECT_CALL(m_client,
218 didOverscroll(
219 WebFloatSize(0, 50),
220 WebFloatSize(0, 50),
221 WebFloatPoint(100, 100),
222 WebFloatSize()));
223 webViewImpl()->handleInputEvent(
224 generateEvent(WebInputEvent::GestureScrollUpdate, 0, -550));
225 ASSERT_FLOAT_EQ(maximumScroll, container->scrollTop());
226 ASSERT_FLOAT_EQ(0, mainFrameView()->scrollPositionDouble().y());
227 Mock::VerifyAndClearExpectations(&m_client);
228 }
229
230 {
231 // Continue the gesture overscroll.
232 EXPECT_CALL(m_client,
233 didOverscroll(
234 WebFloatSize(0, 20),
235 WebFloatSize(0, 70),
236 WebFloatPoint(100, 100),
237 WebFloatSize()));
238 webViewImpl()->handleInputEvent(
239 generateEvent(WebInputEvent::GestureScrollUpdate, 0, -20));
240 ASSERT_FLOAT_EQ(maximumScroll, container->scrollTop());
241 ASSERT_FLOAT_EQ(0, mainFrameView()->scrollPositionDouble().y());
242 Mock::VerifyAndClearExpectations(&m_client);
243 }
244
245 webViewImpl()->handleInputEvent(
246 generateEvent(WebInputEvent::GestureScrollEnd));
247
248 {
249 // Make sure a new gesture scroll still won't scroll the frameview and
250 // overscrolls.
251 webViewImpl()->handleInputEvent(
252 generateEvent(WebInputEvent::GestureScrollBegin));
253
254 EXPECT_CALL(m_client,
255 didOverscroll(
256 WebFloatSize(0, 30),
257 WebFloatSize(0, 30),
258 WebFloatPoint(100, 100),
259 WebFloatSize()));
260 webViewImpl()->handleInputEvent(
261 generateEvent(WebInputEvent::GestureScrollUpdate, 0, -30));
262 ASSERT_FLOAT_EQ(maximumScroll, container->scrollTop());
263 ASSERT_FLOAT_EQ(0, mainFrameView()->scrollPositionDouble().y());
264 Mock::VerifyAndClearExpectations(&m_client);
265
266 webViewImpl()->handleInputEvent(
267 generateEvent(WebInputEvent::GestureScrollEnd));
268 }
269
270 {
271 // Scrolling up should show the top controls.
272 webViewImpl()->handleInputEvent(
273 generateEvent(WebInputEvent::GestureScrollBegin));
274
275 ASSERT_FLOAT_EQ(0, topControls().shownRatio());
276 webViewImpl()->handleInputEvent(
277 generateEvent(WebInputEvent::GestureScrollUpdate, 0, 30));
278 ASSERT_FLOAT_EQ(0.6, topControls().shownRatio());
279
280 webViewImpl()->handleInputEvent(
281 generateEvent(WebInputEvent::GestureScrollEnd));
282 }
283 }
284
285 // Tests that removing the element that is the root scroller from the DOM tree
286 // resets the default element to be the root scroller.
287 TEST_F(RootScrollerTest, TestRemoveRootScrollerFromDom)
288 {
289 initialize("root-scroller.html");
290
291 ASSERT_EQ(
292 mainFrame()->document()->documentElement(),
293 rootScroller().get());
294
295 Element* container = mainFrame()->document()->getElementById("container");
296 TrackExceptionState exceptionState;
297 mainFrame()->document()->setRootScroller(container, exceptionState);
298
299 ASSERT_EQ(container, mainFrame()->document()->rootScroller());
300
301 mainFrame()->document()->body()->removeChild(container);
302
303 ASSERT_EQ(
304 mainFrame()->document()->documentElement(),
305 mainFrame()->document()->rootScroller());
306 }
307
308 // Tests that setting an element that isn't a valid scroller as the root
309 // scroller fails and doesn't change the current root scroller.
310 TEST_F(RootScrollerTest, TestSetRootScrollerOnInvalidElement)
311 {
312 initialize("root-scroller.html");
313
314 {
315 // Set to a non-block element. Should be rejected and a console message
316 // logged.
317 Element* element = mainFrame()->document()->getElementById("nonBlock");
318 TrackExceptionState exceptionState;
319 mainFrame()->document()->setRootScroller(element, exceptionState);
320 ASSERT_EQ(
321 mainFrame()->document()->documentElement(),
322 mainFrame()->document()->rootScroller());
323 EXPECT_TRUE(exceptionState.hadException());
324 }
325
326 {
327 // Set to an element with no size.
328 Element* element = mainFrame()->document()->getElementById("empty");
329 TrackExceptionState exceptionState;
330 mainFrame()->document()->setRootScroller(element, exceptionState);
331 ASSERT_EQ(
332 mainFrame()->document()->documentElement(),
333 mainFrame()->document()->rootScroller());
334 EXPECT_TRUE(exceptionState.hadException());
335 }
336 }
337
338 // Test that the root scroller resets to the default element when the current
339 // root scroller element becomes invalid as a scroller.
340 TEST_F(RootScrollerTest, TestRootScrollerBecomesInvalid)
341 {
342 initialize("root-scroller.html");
343
344 ASSERT_EQ(
345 mainFrame()->document()->documentElement(),
346 rootScroller().get());
347
348 Element* container = mainFrame()->document()->getElementById("container");
349 TrackExceptionState exceptionState;
350 mainFrame()->document()->setRootScroller(container, exceptionState);
351
352 ASSERT_EQ(container, mainFrame()->document()->rootScroller());
353
354 executeScript(
355 "document.querySelector('#container').style.display = 'inline'");
356
357 ASSERT_EQ(
358 mainFrame()->document()->documentElement(),
359 mainFrame()->document()->rootScroller());
360 }
361
362 // Tests that setting the root scroller of the top codument to an element that
363 // belongs to a nested document fails.
364 TEST_F(RootScrollerTest, TestSetRootScrollerOnElementInIframe)
365 {
366 initialize("root-scroller-iframe.html");
367
368 ASSERT_EQ(
369 mainFrame()->document()->documentElement(),
370 rootScroller().get());
371
372 {
373 // Trying to set an element from a nested document should fail.
374 HTMLFrameOwnerElement* iframe = toHTMLFrameOwnerElement(
375 mainFrame()->document()->getElementById("iframe"));
376 Element* innerContainer =
377 iframe->contentDocument()->getElementById("container");
378
379 TrackExceptionState exceptionState;
380 mainFrame()->document()->setRootScroller(
381 innerContainer,
382 exceptionState);
383 EXPECT_TRUE(exceptionState.hadException());
384
385 ASSERT_EQ(
386 mainFrame()->document()->documentElement(),
387 rootScroller().get());
388 }
389
390 {
391 // Setting the iframe itself, however, should work.
392 HTMLFrameOwnerElement* iframe = toHTMLFrameOwnerElement(
393 mainFrame()->document()->getElementById("iframe"));
394
395 TrackExceptionState exceptionState;
396 mainFrame()->document()->setRootScroller(iframe, exceptionState);
397 EXPECT_FALSE(exceptionState.hadException());
398
399 ASSERT_EQ(iframe, rootScroller().get());
400 }
401 }
402
403 // Tests that setting an otherwise valid element as the root scroller on a
404 // document within an iframe fails and getting the root scroller in the nested
405 // document returns the default element.
406 TEST_F(RootScrollerTest, TestRootScrollerWithinIframe)
407 {
408 initialize("root-scroller-iframe.html");
409
410 ASSERT_EQ(
411 mainFrame()->document()->documentElement(),
412 rootScroller().get());
413
414 {
415 // Trying to set an element within nested document should fail.
416 // rootScroller() should always return its documentElement.
417 HTMLFrameOwnerElement* iframe = toHTMLFrameOwnerElement(
418 mainFrame()->document()->getElementById("iframe"));
419
420 ASSERT_EQ(
421 iframe->contentDocument()->documentElement(),
422 iframe->contentDocument()->rootScroller());
423
424 Element* innerContainer =
425 iframe->contentDocument()->getElementById("container");
426 TrackExceptionState exceptionState;
427 iframe->contentDocument()->setRootScroller(
428 innerContainer,
429 exceptionState);
430 EXPECT_TRUE(exceptionState.hadException());
431
432 ASSERT_EQ(
433 iframe->contentDocument()->documentElement(),
434 iframe->contentDocument()->rootScroller());
435 }
436 }
437
438 // Tests that trying to set an element as the root scroller of a document inside
439 // an iframe fails when that element belongs to the parent document.
440 TEST_F(RootScrollerTest, TestSetRootScrollerOnElementFromOutsideIframe)
441 {
442 initialize("root-scroller-iframe.html");
443
444 ASSERT_EQ(
445 mainFrame()->document()->documentElement(),
446 rootScroller().get());
447 {
448 // Try to set the the root scroller of the child document to be the
449 // <iframe> element in the parent document.
450 HTMLFrameOwnerElement* iframe = toHTMLFrameOwnerElement(
451 mainFrame()->document()->getElementById("iframe"));
452 NonThrowableExceptionState nonThrow;
453 Element* body =
454 mainFrame()->document()->querySelector("body", nonThrow);
455
456 ASSERT_EQ(
457 iframe->contentDocument()->documentElement(),
458 iframe->contentDocument()->rootScroller());
459
460 TrackExceptionState exceptionState;
461 iframe->contentDocument()->setRootScroller(
462 iframe,
463 exceptionState);
464 EXPECT_TRUE(exceptionState.hadException());
465
466 ASSERT_EQ(
467 iframe->contentDocument()->documentElement(),
468 iframe->contentDocument()->rootScroller());
469
470 exceptionState.clearException();
471
472 // Try to set the root scroller of the child document to be the
473 // <body> element of the parent document.
474 iframe->contentDocument()->setRootScroller(
475 body,
476 exceptionState);
477 EXPECT_TRUE(exceptionState.hadException());
478
479 ASSERT_EQ(
480 iframe->contentDocument()->documentElement(),
481 iframe->contentDocument()->rootScroller());
482 }
483 }
484
485 } // namespace
486
487 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698