1 #include "config.h" 2 3 #include <gtest/gtest.h> 4 #include "FrameTestHelpers.h" 5 #include "RuntimeEnabledFeatures.h" 6 #include "URLTestHelpers.h" 7 #include "WebFrame.h" 8 #include "WebFrameClient.h" 9 #include "WebFrameImpl.h" 10 #include "WebHistoryItem.h" 11 #include "WebInputEvent.h" 12 #include "WebScriptSource.h" 13 #include "WebSettings.h" 14 #include "WebView.h" 15 #include "WebViewClient.h" 16 #include "WebViewImpl.h" 17 #include "core/page/FrameView.h" 18 #include "core/rendering/RenderView.h" 19 #include "public/platform/Platform.h" 20 #include "public/platform/WebUnitTestSupport.h" 21 22 using namespace WebCore; 23 using namespace WebKit; 24 25 namespace { 26 27 class MockWebFrameClient : public WebFrameClient { 28 }; 29 30 class ProgrammaticScrollTest : public testing::Test { 31 public: 32 ProgrammaticScrollTest() 33 : m_baseURL("http://www.test.com/") 34 { 35 } 36 37 virtual void SetUp() 38 { 39 RuntimeEnabledFeatures::setProgrammaticScrollNotificationsEnabled(true); 40 } 41 42 virtual void TearDown() 43 { 44 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); 45 } 46 47 protected: 48 49 void registerMockedHttpURLLoad(const std::string& fileName) 50 { 51 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str())); 52 } 53 54 std::string m_baseURL; 55 MockWebFrameClient m_mockWebFrameClient; 56 }; 57 58 class TestProgrammaticScrollClient : public WebViewClient { 59 public: 60 TestProgrammaticScrollClient() 61 { 62 reset(); 63 } 64 void reset() 65 { 66 m_eventReceived = false; 67 } 68 bool eventReceived() const { return m_eventReceived; } 69 70 // WebWidgetClient: 71 virtual void didProgrammaticallyScroll(const WebPoint&) OVERRIDE 72 { 73 m_eventReceived = true; 74 } 75 76 private: 77 bool m_eventReceived; 78 }; 79 80 TEST_F(ProgrammaticScrollTest, UserScroll) 81 { 82 registerMockedHttpURLLoad("short_scroll.html"); 83 TestProgrammaticScrollClient client; 84 85 WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "short_scroll.html", false, 0, &client); 86 webView->resize(WebSize(1000, 1000)); 87 webView->layout(); 88 89 WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(webView); 90 EXPECT_FALSE(client.eventReceived()); 91 92 // Non zero page scale and scroll. 93 webViewImpl->applyScrollAndScale(WebSize(9, 13), 2.0f); 94 EXPECT_FALSE(client.eventReceived()); 95 96 webView->close(); 97 } 98 99 TEST_F(ProgrammaticScrollTest, ProgrammaticScroll) 100 { 101 registerMockedHttpURLLoad("long_scroll.html"); 102 TestProgrammaticScrollClient client; 103 104 WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "long_scroll.html", true, 0, &client); 105 webView->resize(WebSize(1000, 1000)); 106 webView->layout(); 107 108 WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(webView); 109 WebFrameImpl* frameImpl = webViewImpl->mainFrameImpl(); 110 FrameView* frameView = frameImpl->frameView(); 111 112 // Slow scroll path. 113 frameView->setCanBlitOnScroll(false); 114 EXPECT_FALSE(client.eventReceived()); 115 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);")); 116 EXPECT_TRUE(client.eventReceived()); 117 client.reset(); 118 frameImpl->executeScript(WebScriptSource("window.scrollBy(0, 0);")); 119 EXPECT_FALSE(client.eventReceived()); 120 client.reset(); 121 122 // Fast scroll path. 123 frameImpl->frameView()->setCanBlitOnScroll(true); 124 EXPECT_FALSE(client.eventReceived()); 125 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 21);")); 126 EXPECT_TRUE(client.eventReceived()); 127 client.reset(); 128 frameImpl->executeScript(WebScriptSource("window.scrollBy(0, 0);")); 129 EXPECT_FALSE(client.eventReceived()); 130 client.reset(); 131 132 webView->close(); 133 } 134 135 TEST_F(ProgrammaticScrollTest, UserScrollOnMainThread) 136 { 137 registerMockedHttpURLLoad("long_scroll.html"); 138 TestProgrammaticScrollClient client; 139 140 WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "long_scroll.html", true, 0, &client); 141 webView->resize(WebSize(1000, 1000)); 142 webView->layout(); 143 144 WebGestureEvent gesture; 145 gesture.type = WebInputEvent::GestureScrollBegin; 146 webView->handleInputEvent(gesture); 147 FrameTestHelpers::runPendingTasks(); 148 EXPECT_FALSE(client.eventReceived()); 149 150 gesture.type = WebInputEvent::GestureScrollUpdate; 151 gesture.data.scrollUpdate.deltaY = 40; 152 webView->handleInputEvent(gesture); 153 FrameTestHelpers::runPendingTasks(); 154 EXPECT_FALSE(client.eventReceived()); 155 156 gesture.type = WebInputEvent::GestureScrollEnd; 157 gesture.data.scrollUpdate.deltaY = 0; 158 webView->handleInputEvent(gesture); 159 FrameTestHelpers::runPendingTasks(); 160 EXPECT_FALSE(client.eventReceived()); 161 162 webView->close(); 163 } 164 165 TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithScale) 166 { 167 registerMockedHttpURLLoad("long_scroll.html"); 168 TestProgrammaticScrollClient client; 169 170 WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "long_scroll.html", true, 0, &client); 171 webView->resize(WebSize(1000, 1000)); 172 webView->layout(); 173 174 WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(webView); 175 FrameView* frameView = webViewImpl->mainFrameImpl()->frameView(); 176 HistoryController* history = webViewImpl->page()->mainFrame()->loader()->history(); 177 178 // Scale and scroll the page and save that state. Then scale and scroll again and restore. 179 webViewImpl->setPageScaleFactor(2.0f, WebPoint(0, 200)); 180 history->saveDocumentAndScrollState(); 181 webViewImpl->setPageScaleFactor(3.0f, WebPoint(0, 300)); 182 // Flip back the wasScrolledByUser flag which was set to true by setPageScaleFactor 183 // because otherwise HistoryController::restoreScrollPositionAndViewState does nothing. 184 frameView->setWasScrolledByUser(false); 185 history->restoreScrollPositionAndViewState(); 186 187 // Expect that both scroll and scale were restored, and that it was not a programmatic scroll. 188 EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor()); 189 EXPECT_EQ(200, webViewImpl->mainFrameImpl()->scrollOffset().height); 190 EXPECT_TRUE(frameView->wasScrolledByUser()); 191 EXPECT_FALSE(client.eventReceived()); 192 193 webView->close(); 194 } 195 196 TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithoutScale) 197 { 198 registerMockedHttpURLLoad("long_scroll.html"); 199 TestProgrammaticScrollClient client; 200 201 WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "long_scroll.html", true, 0, &client); 202 webView->resize(WebSize(1000, 1000)); 203 webView->layout(); 204 205 WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(webView); 206 FrameView* frameView = webViewImpl->mainFrameImpl()->frameView(); 207 HistoryController* history = webViewImpl->page()->mainFrame()->loader()->history(); 208 209 // Scale and scroll the page and save that state, but then set scale to zero. Then scale and 210 // scroll again and restore. 211 webViewImpl->setPageScaleFactor(2.0f, WebPoint(0, 400)); 212 history->saveDocumentAndScrollState(); 213 webViewImpl->setPageScaleFactor(3.0f, WebPoint(0, 500)); 214 // Flip back the wasScrolledByUser flag which was set to true by setPageScaleFactor 215 // because otherwise HistoryController::restoreScrollPositionAndViewState does nothing. 216 frameView->setWasScrolledByUser(false); 217 // HistoryController::restoreScrollPositionAndViewState flows differently if scale is zero. 218 history->currentItem()->setPageScaleFactor(0.0f); 219 history->restoreScrollPositionAndViewState(); 220 221 // Expect that only the scroll position was restored, and that it was not a programmatic scroll. 222 EXPECT_EQ(3.0f, webViewImpl->pageScaleFactor()); 223 EXPECT_EQ(400, webViewImpl->mainFrameImpl()->scrollOffset().height); 224 EXPECT_TRUE(frameView->wasScrolledByUser()); 225 EXPECT_FALSE(client.eventReceived()); 226 227 webView->close(); 228 } 229 230 } 231