Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / tests / WebFrameTest.cpp
blobf3d4679483f3be29f9e692d77919a8a905a9f735
1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "config.h"
32 #include "public/web/WebFrame.h"
34 #include "SkBitmap.h"
35 #include "SkCanvas.h"
36 #include "bindings/core/v8/SerializedScriptValueFactory.h"
37 #include "bindings/core/v8/V8Node.h"
38 #include "core/clipboard/DataTransfer.h"
39 #include "core/css/StyleSheetContents.h"
40 #include "core/css/resolver/StyleResolver.h"
41 #include "core/css/resolver/ViewportStyleResolver.h"
42 #include "core/dom/Fullscreen.h"
43 #include "core/dom/NodeComputedStyle.h"
44 #include "core/dom/Range.h"
45 #include "core/editing/Editor.h"
46 #include "core/editing/EphemeralRange.h"
47 #include "core/editing/FrameSelection.h"
48 #include "core/editing/VisiblePosition.h"
49 #include "core/editing/markers/DocumentMarkerController.h"
50 #include "core/editing/spellcheck/SpellChecker.h"
51 #include "core/events/MouseEvent.h"
52 #include "core/fetch/FetchRequest.h"
53 #include "core/fetch/MemoryCache.h"
54 #include "core/fetch/ResourceFetcher.h"
55 #include "core/frame/FrameHost.h"
56 #include "core/frame/FrameView.h"
57 #include "core/frame/LocalFrame.h"
58 #include "core/frame/RemoteFrame.h"
59 #include "core/frame/Settings.h"
60 #include "core/frame/VisualViewport.h"
61 #include "core/html/HTMLDocument.h"
62 #include "core/html/HTMLFormElement.h"
63 #include "core/html/HTMLMediaElement.h"
64 #include "core/input/EventHandler.h"
65 #include "core/layout/HitTestResult.h"
66 #include "core/layout/LayoutFullScreen.h"
67 #include "core/layout/LayoutView.h"
68 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
69 #include "core/loader/DocumentLoader.h"
70 #include "core/loader/DocumentThreadableLoader.h"
71 #include "core/loader/DocumentThreadableLoaderClient.h"
72 #include "core/loader/FrameLoadRequest.h"
73 #include "core/loader/ThreadableLoader.h"
74 #include "core/page/Page.h"
75 #include "core/paint/DeprecatedPaintLayer.h"
76 #include "core/testing/NullExecutionContext.h"
77 #include "modules/mediastream/MediaStream.h"
78 #include "modules/mediastream/MediaStreamRegistry.h"
79 #include "platform/DragImage.h"
80 #include "platform/PlatformResourceLoader.h"
81 #include "platform/RuntimeEnabledFeatures.h"
82 #include "platform/UserGestureIndicator.h"
83 #include "platform/geometry/FloatRect.h"
84 #include "platform/network/ResourceError.h"
85 #include "platform/scroll/ScrollbarTheme.h"
86 #include "platform/testing/URLTestHelpers.h"
87 #include "platform/testing/UnitTestHelpers.h"
88 #include "platform/weborigin/SchemeRegistry.h"
89 #include "platform/weborigin/SecurityOrigin.h"
90 #include "public/platform/Platform.h"
91 #include "public/platform/WebFloatRect.h"
92 #include "public/platform/WebSecurityOrigin.h"
93 #include "public/platform/WebThread.h"
94 #include "public/platform/WebURL.h"
95 #include "public/platform/WebURLResponse.h"
96 #include "public/platform/WebUnitTestSupport.h"
97 #include "public/web/WebCache.h"
98 #include "public/web/WebConsoleMessage.h"
99 #include "public/web/WebDataSource.h"
100 #include "public/web/WebDeviceEmulationParams.h"
101 #include "public/web/WebDocument.h"
102 #include "public/web/WebFindOptions.h"
103 #include "public/web/WebFormElement.h"
104 #include "public/web/WebFrameClient.h"
105 #include "public/web/WebFrameWidget.h"
106 #include "public/web/WebHistoryItem.h"
107 #include "public/web/WebPrintParams.h"
108 #include "public/web/WebRange.h"
109 #include "public/web/WebRemoteFrame.h"
110 #include "public/web/WebScriptExecutionCallback.h"
111 #include "public/web/WebScriptSource.h"
112 #include "public/web/WebSearchableFormData.h"
113 #include "public/web/WebSecurityPolicy.h"
114 #include "public/web/WebSelection.h"
115 #include "public/web/WebSettings.h"
116 #include "public/web/WebSpellCheckClient.h"
117 #include "public/web/WebTextCheckingCompletion.h"
118 #include "public/web/WebTextCheckingResult.h"
119 #include "public/web/WebViewClient.h"
120 #include "web/WebLocalFrameImpl.h"
121 #include "web/WebRemoteFrameImpl.h"
122 #include "web/WebViewImpl.h"
123 #include "web/tests/FrameTestHelpers.h"
124 #include "wtf/Forward.h"
125 #include "wtf/dtoa/utils.h"
126 #include <gmock/gmock.h>
127 #include <gtest/gtest.h>
128 #include <map>
129 #include <stdarg.h>
130 #include <v8.h>
132 using blink::URLTestHelpers::toKURL;
133 using blink::FrameTestHelpers::UseMockScrollbarSettings;
134 using blink::testing::runPendingTasks;
135 using testing::ElementsAre;
136 using testing::Mock;
137 using testing::_;
139 namespace blink {
141 ::std::ostream& operator<<(::std::ostream& os, const WebFloatSize& size)
143 return os << "WebFloatSize: ["
144 << size.width<< ", " << size.height<< "]";
147 ::std::ostream& operator<<(::std::ostream& os, const WebFloatPoint& point)
149 return os << "WebFloatPoint: ["
150 << point.x<< ", " << point.y<< "]";
153 const int touchPointPadding = 32;
155 #define EXPECT_RECT_EQ(expected, actual) \
156 do { \
157 EXPECT_EQ(expected.x(), actual.x()); \
158 EXPECT_EQ(expected.y(), actual.y()); \
159 EXPECT_EQ(expected.width(), actual.width()); \
160 EXPECT_EQ(expected.height(), actual.height()); \
161 } while (false)
163 #define EXPECT_POINT_EQ(expected, actual) \
164 do { \
165 EXPECT_EQ(expected.x(), actual.x()); \
166 EXPECT_EQ(expected.y(), actual.y()); \
167 } while (false)
169 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
170 do { \
171 EXPECT_FLOAT_EQ(expected.x(), actual.x()); \
172 EXPECT_FLOAT_EQ(expected.y(), actual.y()); \
173 } while (false)
175 class WebFrameTest : public ::testing::Test {
176 protected:
177 WebFrameTest()
178 : m_baseURL("http://internal.test/")
179 , m_notBaseURL("http://external.test/")
180 , m_chromeURL("chrome://")
184 ~WebFrameTest() override
186 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
189 void registerMockedHttpURLLoad(const std::string& fileName)
191 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
194 void registerMockedChromeURLLoad(const std::string& fileName)
196 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_chromeURL.c_str()), WebString::fromUTF8(fileName.c_str()));
200 void registerMockedHttpURLLoadWithCSP(const std::string& fileName, const std::string& csp, bool reportOnly = false)
202 WebURLResponse response;
203 response.initialize();
204 response.setMIMEType("text/html");
205 response.addHTTPHeaderField(reportOnly ? WebString("Content-Security-Policy-Report-Only") : WebString("Content-Security-Policy"), WebString::fromUTF8(csp));
206 std::string fullString = m_baseURL + fileName;
207 URLTestHelpers::registerMockedURLLoadWithCustomResponse(toKURL(fullString.c_str()), WebString::fromUTF8(fileName.c_str()), WebString::fromUTF8(""), response);
210 void applyViewportStyleOverride(FrameTestHelpers::WebViewHelper* webViewHelper)
212 RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0));
213 styleSheet->parseString(loadResourceAsASCIIString("viewportAndroid.css"));
214 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
215 ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen"));
217 Document* document = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame())->document();
218 document->ensureStyleResolver().viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin);
219 document->ensureStyleResolver().viewportStyleResolver()->resolve();
222 static void configueCompositingWebView(WebSettings* settings)
224 settings->setAcceleratedCompositingEnabled(true);
225 settings->setPreferCompositingToLCDTextEnabled(true);
228 static void configureAndroid(WebSettings* settings)
230 settings->setViewportMetaEnabled(true);
231 settings->setViewportEnabled(true);
232 settings->setMainFrameResizesAreOrientationChanges(true);
233 settings->setShrinksViewportContentToFit(true);
236 static void configureLoadsImagesAutomatically(WebSettings* settings)
238 settings->setLoadsImagesAutomatically(true);
241 void initializeTextSelectionWebView(const std::string& url, FrameTestHelpers::WebViewHelper* webViewHelper)
243 webViewHelper->initializeAndLoad(url, true);
244 webViewHelper->webView()->settings()->setDefaultFontSize(12);
245 webViewHelper->webView()->resize(WebSize(640, 480));
248 PassOwnPtr<DragImage> nodeImageTestSetup(FrameTestHelpers::WebViewHelper* webViewHelper, const std::string& testcase)
250 registerMockedHttpURLLoad("nodeimage.html");
251 webViewHelper->initializeAndLoad(m_baseURL + "nodeimage.html");
252 webViewHelper->webView()->resize(WebSize(640, 480));
253 webViewHelper->webView()->layout();
254 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame());
255 ASSERT(frame);
256 Element* element = frame->document()->getElementById(testcase.c_str());
257 return frame->nodeImage(*element);
260 void removeElementById(WebLocalFrameImpl* frame, const AtomicString& id)
262 Element* element = frame->frame()->document()->getElementById(id);
263 ASSERT(element);
264 element->remove();
267 std::string m_baseURL;
268 std::string m_notBaseURL;
269 std::string m_chromeURL;
272 enum ParameterizedWebFrameTestConfig {
273 Default,
274 RootLayerScrolls
277 class ParameterizedWebFrameTest
278 : public WebFrameTest
279 , public ::testing::WithParamInterface<ParameterizedWebFrameTestConfig>
280 , public FrameTestHelpers::SettingOverrider {
281 public:
283 void overrideSettings(WebSettings* settings)
285 switch (GetParam()) {
286 case Default:
287 break;
288 case RootLayerScrolls:
289 settings->setRootLayerScrolls(true);
290 break;
295 // Friendly string for gtest failure messages.
296 void PrintTo(ParameterizedWebFrameTestConfig config, ::std::ostream* os)
298 switch (config) {
299 case Default:
300 *os << "Default";
301 break;
302 case RootLayerScrolls:
303 *os << "RootLayerScrolls";
304 break;
308 INSTANTIATE_TEST_CASE_P(All, ParameterizedWebFrameTest, ::testing::Values(
309 ParameterizedWebFrameTestConfig::Default,
310 ParameterizedWebFrameTestConfig::RootLayerScrolls));
312 TEST_P(ParameterizedWebFrameTest, ContentText)
314 registerMockedHttpURLLoad("iframes_test.html");
315 registerMockedHttpURLLoad("visible_iframe.html");
316 registerMockedHttpURLLoad("invisible_iframe.html");
317 registerMockedHttpURLLoad("zero_sized_iframe.html");
319 FrameTestHelpers::WebViewHelper webViewHelper(this);
320 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html");
322 // Now retrieve the frames text and test it only includes visible elements.
323 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
324 EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
325 EXPECT_NE(std::string::npos, content.find(" visible iframe"));
326 EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
327 EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
328 EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
331 TEST_P(ParameterizedWebFrameTest, FrameForEnteredContext)
333 registerMockedHttpURLLoad("iframes_test.html");
334 registerMockedHttpURLLoad("visible_iframe.html");
335 registerMockedHttpURLLoad("invisible_iframe.html");
336 registerMockedHttpURLLoad("zero_sized_iframe.html");
338 FrameTestHelpers::WebViewHelper webViewHelper(this);
339 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html", true);
341 v8::HandleScope scope(v8::Isolate::GetCurrent());
342 EXPECT_EQ(webViewHelper.webView()->mainFrame(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->mainWorldScriptContext()));
343 EXPECT_EQ(webViewHelper.webView()->mainFrame()->firstChild(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->firstChild()->mainWorldScriptContext()));
346 class ScriptExecutionCallbackHelper : public WebScriptExecutionCallback {
347 public:
348 explicit ScriptExecutionCallbackHelper(v8::Local<v8::Context> context)
349 : m_didComplete(false)
350 , m_context(context) { }
351 ~ScriptExecutionCallbackHelper() { }
353 bool didComplete() const { return m_didComplete; }
354 const String& stringValue() const { return m_stringValue; }
356 private:
357 void completed(const WebVector<v8::Local<v8::Value>>& values) override
359 m_didComplete = true;
360 if (!values.isEmpty() && values[0]->IsString()) {
361 m_stringValue = toCoreString(values[0]->ToString(m_context).ToLocalChecked());
365 bool m_didComplete;
366 String m_stringValue;
367 v8::Local<v8::Context> m_context;
370 TEST_P(ParameterizedWebFrameTest, RequestExecuteScript)
372 registerMockedHttpURLLoad("foo.html");
374 FrameTestHelpers::WebViewHelper webViewHelper(this);
375 webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
377 v8::HandleScope scope(v8::Isolate::GetCurrent());
378 ScriptExecutionCallbackHelper callbackHelper(webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
379 webViewHelper.webView()->mainFrame()->toWebLocalFrame()->requestExecuteScriptAndReturnValue(WebScriptSource(WebString("'hello';")), false, &callbackHelper);
380 runPendingTasks();
381 EXPECT_TRUE(callbackHelper.didComplete());
382 EXPECT_EQ("hello", callbackHelper.stringValue());
385 TEST_P(ParameterizedWebFrameTest, SuspendedRequestExecuteScript)
387 registerMockedHttpURLLoad("foo.html");
388 registerMockedHttpURLLoad("bar.html");
390 FrameTestHelpers::WebViewHelper webViewHelper(this);
391 webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
393 v8::HandleScope scope(v8::Isolate::GetCurrent());
394 ScriptExecutionCallbackHelper callbackHelper(webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
396 // Suspend scheduled tasks so the script doesn't run.
397 toWebLocalFrameImpl(webViewHelper.webView()->mainFrame())->frame()->document()->suspendScheduledTasks();
398 webViewHelper.webView()->mainFrame()->toWebLocalFrame()->requestExecuteScriptAndReturnValue(WebScriptSource(WebString("'hello';")), false, &callbackHelper);
399 runPendingTasks();
400 EXPECT_FALSE(callbackHelper.didComplete());
402 // If the frame navigates, pending scripts should be removed, but the callback should always be ran.
403 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "bar.html");
404 EXPECT_TRUE(callbackHelper.didComplete());
405 EXPECT_EQ(String(), callbackHelper.stringValue());
408 TEST_P(ParameterizedWebFrameTest, IframeScriptRemovesSelf)
410 registerMockedHttpURLLoad("single_iframe.html");
411 registerMockedHttpURLLoad("visible_iframe.html");
413 FrameTestHelpers::WebViewHelper webViewHelper(this);
414 webViewHelper.initializeAndLoad(m_baseURL + "single_iframe.html", true);
416 v8::HandleScope scope(v8::Isolate::GetCurrent());
417 ScriptExecutionCallbackHelper callbackHelper(webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
418 webViewHelper.webView()->mainFrame()->firstChild()->toWebLocalFrame()->requestExecuteScriptAndReturnValue(WebScriptSource(WebString("var iframe = window.top.document.getElementsByTagName('iframe')[0]; window.top.document.body.removeChild(iframe); 'hello';")), false, &callbackHelper);
419 runPendingTasks();
420 EXPECT_TRUE(callbackHelper.didComplete());
421 EXPECT_EQ(String(), callbackHelper.stringValue());
424 TEST_P(ParameterizedWebFrameTest, FormWithNullFrame)
426 registerMockedHttpURLLoad("form.html");
428 FrameTestHelpers::WebViewHelper webViewHelper(this);
429 webViewHelper.initializeAndLoad(m_baseURL + "form.html");
431 WebVector<WebFormElement> forms;
432 webViewHelper.webView()->mainFrame()->document().forms(forms);
433 webViewHelper.reset();
435 EXPECT_EQ(forms.size(), 1U);
437 // This test passes if this doesn't crash.
438 WebSearchableFormData searchableDataForm(forms[0]);
441 TEST_P(ParameterizedWebFrameTest, ChromePageJavascript)
443 registerMockedChromeURLLoad("history.html");
445 // Pass true to enable JavaScript.
446 FrameTestHelpers::WebViewHelper webViewHelper(this);
447 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
449 // Try to run JS against the chrome-style URL.
450 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
452 // Required to see any updates in contentAsText.
453 webViewHelper.webView()->layout();
455 // Now retrieve the frame's text and ensure it was modified by running javascript.
456 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
457 EXPECT_NE(std::string::npos, content.find("Clobbered"));
460 TEST_P(ParameterizedWebFrameTest, ChromePageNoJavascript)
462 registerMockedChromeURLLoad("history.html");
464 /// Pass true to enable JavaScript.
465 FrameTestHelpers::WebViewHelper webViewHelper(this);
466 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
468 // Try to run JS against the chrome-style URL after prohibiting it.
469 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
470 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
472 // Required to see any updates in contentAsText.
473 webViewHelper.webView()->layout();
475 // Now retrieve the frame's text and ensure it wasn't modified by running javascript.
476 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
477 EXPECT_EQ(std::string::npos, content.find("Clobbered"));
480 TEST_P(ParameterizedWebFrameTest, LocationSetHostWithMissingPort)
482 std::string fileName = "print-location-href.html";
483 registerMockedHttpURLLoad(fileName);
484 URLTestHelpers::registerMockedURLLoad(toKURL("http://internal.test:0/" + fileName), WebString::fromUTF8(fileName));
486 FrameTestHelpers::WebViewHelper webViewHelper(this);
488 /// Pass true to enable JavaScript.
489 webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
491 // Setting host to "hostname:" should be treated as "hostname:0".
492 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.host = 'internal.test:'; void 0;");
494 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
496 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
497 EXPECT_EQ("http://internal.test:0/" + fileName, content);
500 TEST_P(ParameterizedWebFrameTest, LocationSetEmptyPort)
502 std::string fileName = "print-location-href.html";
503 registerMockedHttpURLLoad(fileName);
504 URLTestHelpers::registerMockedURLLoad(toKURL("http://internal.test:0/" + fileName), WebString::fromUTF8(fileName));
506 FrameTestHelpers::WebViewHelper webViewHelper(this);
508 /// Pass true to enable JavaScript.
509 webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
511 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.port = ''; void 0;");
513 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
515 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
516 EXPECT_EQ("http://internal.test:0/" + fileName, content);
519 class EvaluateOnLoadWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
520 public:
521 EvaluateOnLoadWebFrameClient() : m_executing(false), m_wasExecuted(false) { }
523 void didClearWindowObject(WebLocalFrame* frame) override
525 EXPECT_FALSE(m_executing);
526 m_wasExecuted = true;
527 m_executing = true;
528 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
529 frame->executeScriptAndReturnValue(WebScriptSource(WebString("window.someProperty = 42;")));
530 m_executing = false;
533 bool m_executing;
534 bool m_wasExecuted;
537 TEST_P(ParameterizedWebFrameTest, DidClearWindowObjectIsNotRecursive)
539 EvaluateOnLoadWebFrameClient webFrameClient;
540 FrameTestHelpers::WebViewHelper webViewHelper(this);
541 webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
542 EXPECT_TRUE(webFrameClient.m_wasExecuted);
545 class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
546 public:
547 CSSCallbackWebFrameClient() : m_updateCount(0) { }
548 void didMatchCSS(WebLocalFrame*, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors) override;
550 std::map<WebLocalFrame*, std::set<std::string>> m_matchedSelectors;
551 int m_updateCount;
554 void CSSCallbackWebFrameClient::didMatchCSS(WebLocalFrame* frame, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors)
556 ++m_updateCount;
557 std::set<std::string>& frameSelectors = m_matchedSelectors[frame];
558 for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i) {
559 std::string selector = newlyMatchingSelectors[i].utf8();
560 EXPECT_EQ(0U, frameSelectors.count(selector)) << selector;
561 frameSelectors.insert(selector);
563 for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i) {
564 std::string selector = stoppedMatchingSelectors[i].utf8();
565 EXPECT_EQ(1U, frameSelectors.count(selector)) << selector;
566 frameSelectors.erase(selector);
570 class WebFrameCSSCallbackTest : public ::testing::Test {
571 protected:
572 WebFrameCSSCallbackTest()
574 m_frame = m_helper.initializeAndLoad("about:blank", true, &m_client)->mainFrame()->toWebLocalFrame();
577 ~WebFrameCSSCallbackTest()
579 EXPECT_EQ(1U, m_client.m_matchedSelectors.size());
582 WebDocument doc() const
584 return m_frame->document();
587 int updateCount() const
589 return m_client.m_updateCount;
592 const std::set<std::string>& matchedSelectors()
594 return m_client.m_matchedSelectors[m_frame];
597 void loadHTML(const std::string& html)
599 FrameTestHelpers::loadHTMLString(m_frame, html, toKURL("about:blank"));
602 void executeScript(const WebString& code)
604 m_frame->executeScript(WebScriptSource(code));
605 m_frame->view()->layout();
606 runPendingTasks();
609 CSSCallbackWebFrameClient m_client;
610 FrameTestHelpers::WebViewHelper m_helper;
611 WebLocalFrame* m_frame;
614 TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet)
616 loadHTML(
617 "<style>"
618 // This stylesheet checks that the internal property and value can't be
619 // set by a stylesheet, only WebDocument::watchCSSSelectors().
620 "div.initial_on { -internal-callback: none; }"
621 "div.initial_off { -internal-callback: -internal-presence; }"
622 "</style>"
623 "<div class=\"initial_on\"></div>"
624 "<div class=\"initial_off\"></div>");
626 std::vector<WebString> selectors;
627 selectors.push_back(WebString::fromUTF8("div.initial_on"));
628 m_frame->document().watchCSSSelectors(WebVector<WebString>(selectors));
629 m_frame->view()->layout();
630 runPendingTasks();
631 EXPECT_EQ(1, updateCount());
632 EXPECT_THAT(matchedSelectors(), ElementsAre("div.initial_on"));
634 // Check that adding a watched selector calls back for already-present nodes.
635 selectors.push_back(WebString::fromUTF8("div.initial_off"));
636 doc().watchCSSSelectors(WebVector<WebString>(selectors));
637 m_frame->view()->layout();
638 runPendingTasks();
639 EXPECT_EQ(2, updateCount());
640 EXPECT_THAT(matchedSelectors(), ElementsAre("div.initial_off", "div.initial_on"));
642 // Check that we can turn off callbacks for certain selectors.
643 doc().watchCSSSelectors(WebVector<WebString>());
644 m_frame->view()->layout();
645 runPendingTasks();
646 EXPECT_EQ(3, updateCount());
647 EXPECT_THAT(matchedSelectors(), ElementsAre());
650 TEST_F(WebFrameCSSCallbackTest, SharedComputedStyle)
652 // Check that adding an element calls back when it matches an existing rule.
653 std::vector<WebString> selectors;
654 selectors.push_back(WebString::fromUTF8("span"));
655 doc().watchCSSSelectors(WebVector<WebString>(selectors));
657 executeScript(
658 "i1 = document.createElement('span');"
659 "i1.id = 'first_span';"
660 "document.body.appendChild(i1)");
661 EXPECT_EQ(1, updateCount());
662 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
664 // Adding a second element that shares a ComputedStyle shouldn't call back.
665 // We use <span>s to avoid default style rules that can set
666 // ComputedStyle::unique().
667 executeScript(
668 "i2 = document.createElement('span');"
669 "i2.id = 'second_span';"
670 "i1 = document.getElementById('first_span');"
671 "i1.parentNode.insertBefore(i2, i1.nextSibling);");
672 EXPECT_EQ(1, updateCount());
673 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
675 // Removing the first element shouldn't call back.
676 executeScript(
677 "i1 = document.getElementById('first_span');"
678 "i1.parentNode.removeChild(i1);");
679 EXPECT_EQ(1, updateCount());
680 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
682 // But removing the second element *should* call back.
683 executeScript(
684 "i2 = document.getElementById('second_span');"
685 "i2.parentNode.removeChild(i2);");
686 EXPECT_EQ(2, updateCount());
687 EXPECT_THAT(matchedSelectors(), ElementsAre());
690 TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange)
692 loadHTML("<span></span>");
694 std::vector<WebString> selectors;
695 selectors.push_back(WebString::fromUTF8("span[attr=\"value\"]"));
696 doc().watchCSSSelectors(WebVector<WebString>(selectors));
697 runPendingTasks();
699 EXPECT_EQ(0, updateCount());
700 EXPECT_THAT(matchedSelectors(), ElementsAre());
702 executeScript(
703 "document.querySelector('span').setAttribute('attr', 'value');");
704 EXPECT_EQ(1, updateCount());
705 EXPECT_THAT(matchedSelectors(), ElementsAre("span[attr=\"value\"]"));
708 TEST_F(WebFrameCSSCallbackTest, DisplayNone)
710 loadHTML("<div style='display:none'><span></span></div>");
712 std::vector<WebString> selectors;
713 selectors.push_back(WebString::fromUTF8("span"));
714 doc().watchCSSSelectors(WebVector<WebString>(selectors));
715 runPendingTasks();
717 EXPECT_EQ(0, updateCount()) << "Don't match elements in display:none trees.";
719 executeScript(
720 "d = document.querySelector('div');"
721 "d.style.display = 'block';");
722 EXPECT_EQ(1, updateCount()) << "Match elements when they become displayed.";
723 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
725 executeScript(
726 "d = document.querySelector('div');"
727 "d.style.display = 'none';");
728 EXPECT_EQ(2, updateCount()) << "Unmatch elements when they become undisplayed.";
729 EXPECT_THAT(matchedSelectors(), ElementsAre());
731 executeScript(
732 "s = document.querySelector('span');"
733 "s.style.display = 'none';");
734 EXPECT_EQ(2, updateCount()) << "No effect from no-display'ing a span that's already undisplayed.";
736 executeScript(
737 "d = document.querySelector('div');"
738 "d.style.display = 'block';");
739 EXPECT_EQ(2, updateCount()) << "No effect from displaying a div whose span is display:none.";
741 executeScript(
742 "s = document.querySelector('span');"
743 "s.style.display = 'inline';");
744 EXPECT_EQ(3, updateCount()) << "Now the span is visible and produces a callback.";
745 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
747 executeScript(
748 "s = document.querySelector('span');"
749 "s.style.display = 'none';");
750 EXPECT_EQ(4, updateCount()) << "Undisplaying the span directly should produce another callback.";
751 EXPECT_THAT(matchedSelectors(), ElementsAre());
754 TEST_F(WebFrameCSSCallbackTest, Reparenting)
756 loadHTML(
757 "<div id='d1'><span></span></div>"
758 "<div id='d2'></div>");
760 std::vector<WebString> selectors;
761 selectors.push_back(WebString::fromUTF8("span"));
762 doc().watchCSSSelectors(WebVector<WebString>(selectors));
763 m_frame->view()->layout();
764 runPendingTasks();
766 EXPECT_EQ(1, updateCount());
767 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
769 executeScript(
770 "s = document.querySelector('span');"
771 "d2 = document.getElementById('d2');"
772 "d2.appendChild(s);");
773 EXPECT_EQ(1, updateCount()) << "Just moving an element that continues to match shouldn't send a spurious callback.";
774 EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
777 TEST_F(WebFrameCSSCallbackTest, MultiSelector)
779 loadHTML("<span></span>");
781 // Check that selector lists match as the whole list, not as each element
782 // independently.
783 std::vector<WebString> selectors;
784 selectors.push_back(WebString::fromUTF8("span"));
785 selectors.push_back(WebString::fromUTF8("span,p"));
786 doc().watchCSSSelectors(WebVector<WebString>(selectors));
787 m_frame->view()->layout();
788 runPendingTasks();
790 EXPECT_EQ(1, updateCount());
791 EXPECT_THAT(matchedSelectors(), ElementsAre("span", "span, p"));
794 TEST_F(WebFrameCSSCallbackTest, InvalidSelector)
796 loadHTML("<p><span></span></p>");
798 // Build a list with one valid selector and one invalid.
799 std::vector<WebString> selectors;
800 selectors.push_back(WebString::fromUTF8("span"));
801 selectors.push_back(WebString::fromUTF8("[")); // Invalid.
802 selectors.push_back(WebString::fromUTF8("p span")); // Not compound.
803 doc().watchCSSSelectors(WebVector<WebString>(selectors));
804 m_frame->view()->layout();
805 runPendingTasks();
807 EXPECT_EQ(1, updateCount());
808 EXPECT_THAT(matchedSelectors(), ElementsAre("span"))
809 << "An invalid selector shouldn't prevent other selectors from matching.";
812 TEST_P(ParameterizedWebFrameTest, DispatchMessageEventWithOriginCheck)
814 registerMockedHttpURLLoad("postmessage_test.html");
816 // Pass true to enable JavaScript.
817 FrameTestHelpers::WebViewHelper webViewHelper(this);
818 webViewHelper.initializeAndLoad(m_baseURL + "postmessage_test.html", true);
820 // Send a message with the correct origin.
821 WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL)));
822 WebDocument document = webViewHelper.webView()->mainFrame()->document();
823 WebDOMEvent event = document.createEvent("MessageEvent");
824 WebDOMMessageEvent message = event.to<WebDOMMessageEvent>();
825 WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
826 message.initMessageEvent("message", false, false, data, "http://origin.com", 0, document, "");
827 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message);
829 // Send another message with incorrect origin.
830 WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(toKURL(m_chromeURL)));
831 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message);
833 // Required to see any updates in contentAsText.
834 webViewHelper.webView()->layout();
836 // Verify that only the first addition is in the body of the page.
837 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
838 EXPECT_NE(std::string::npos, content.find("Message 1."));
839 EXPECT_EQ(std::string::npos, content.find("Message 2."));
842 TEST_P(ParameterizedWebFrameTest, PostMessageThenDetach)
844 FrameTestHelpers::WebViewHelper webViewHelper(this);
845 webViewHelper.initializeAndLoad("about:blank");
847 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame());
848 NonThrowableExceptionState exceptionState;
849 frame->domWindow()->postMessage(SerializedScriptValueFactory::instance().create("message"), 0, "*", frame->localDOMWindow(), exceptionState);
850 webViewHelper.reset();
851 EXPECT_FALSE(exceptionState.hadException());
853 // Success is not crashing.
854 runPendingTasks();
857 namespace {
859 class FixedLayoutTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
860 public:
861 WebScreenInfo screenInfo() override { return m_screenInfo; }
863 WebScreenInfo m_screenInfo;
866 class FakeCompositingWebViewClient : public FixedLayoutTestWebViewClient {
869 // Viewport settings need to be set before the page gets loaded
870 void enableViewportSettings(WebSettings* settings)
872 settings->setViewportMetaEnabled(true);
873 settings->setViewportEnabled(true);
874 settings->setMainFrameResizesAreOrientationChanges(true);
875 settings->setShrinksViewportContentToFit(true);
878 // Helper function to set autosizing multipliers on a document.
879 bool setTextAutosizingMultiplier(Document* document, float multiplier)
881 bool multiplierSet = false;
882 for (LayoutObject* layoutObject = document->layoutView(); layoutObject; layoutObject = layoutObject->nextInPreOrder()) {
883 if (layoutObject->style()) {
884 layoutObject->mutableStyleRef().setTextAutosizingMultiplier(multiplier);
886 EXPECT_EQ(multiplier, layoutObject->style()->textAutosizingMultiplier());
887 multiplierSet = true;
890 return multiplierSet;
893 // Helper function to check autosizing multipliers on a document.
894 bool checkTextAutosizingMultiplier(Document* document, float multiplier)
896 bool multiplierChecked = false;
897 for (LayoutObject* layoutObject = document->layoutView(); layoutObject; layoutObject = layoutObject->nextInPreOrder()) {
898 if (layoutObject->style() && layoutObject->isText()) {
899 EXPECT_EQ(multiplier, layoutObject->style()->textAutosizingMultiplier());
900 multiplierChecked = true;
903 return multiplierChecked;
906 } // anonymous namespace
908 TEST_P(ParameterizedWebFrameTest, ChangeInFixedLayoutResetsTextAutosizingMultipliers)
910 UseMockScrollbarSettings mockScrollbarSettings;
911 registerMockedHttpURLLoad("fixed_layout.html");
913 FixedLayoutTestWebViewClient client;
914 int viewportWidth = 640;
915 int viewportHeight = 480;
917 FrameTestHelpers::WebViewHelper webViewHelper(this);
918 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
920 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
921 document->settings()->setTextAutosizingEnabled(true);
922 EXPECT_TRUE(document->settings()->textAutosizingEnabled());
923 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight));
924 webViewHelper.webViewImpl()->layout();
926 EXPECT_TRUE(setTextAutosizingMultiplier(document, 2));
928 ViewportDescription description = document->viewportDescription();
929 // Choose a width that's not going match the viewport width of the loaded document.
930 description.minWidth = Length(100, blink::Fixed);
931 description.maxWidth = Length(100, blink::Fixed);
932 webViewHelper.webViewImpl()->updatePageDefinedViewportConstraints(description);
934 EXPECT_TRUE(checkTextAutosizingMultiplier(document, 1));
937 TEST_P(ParameterizedWebFrameTest, WorkingTextAutosizingMultipliers_VirtualViewport)
939 UseMockScrollbarSettings mockScrollbarSettings;
940 const std::string htmlFile = "fixed_layout.html";
941 registerMockedHttpURLLoad(htmlFile);
943 FixedLayoutTestWebViewClient client;
945 FrameTestHelpers::WebViewHelper webViewHelper(this);
946 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, configureAndroid);
948 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
949 document->settings()->setTextAutosizingEnabled(true);
950 EXPECT_TRUE(document->settings()->textAutosizingEnabled());
952 webViewHelper.webView()->resize(WebSize(490, 800));
954 // Multiplier: 980 / 490 = 2.0
955 EXPECT_TRUE(checkTextAutosizingMultiplier(document, 2.0));
958 TEST_P(ParameterizedWebFrameTest, VisualViewportSetSizeInvalidatesTextAutosizingMultipliers)
960 UseMockScrollbarSettings mockScrollbarSettings;
961 registerMockedHttpURLLoad("iframe_reload.html");
962 registerMockedHttpURLLoad("visible_iframe.html");
964 FixedLayoutTestWebViewClient client;
965 int viewportWidth = 640;
966 int viewportHeight = 480;
968 FrameTestHelpers::WebViewHelper webViewHelper(this);
969 webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, 0, &client, enableViewportSettings);
971 LocalFrame* mainFrame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame());
972 Document* document = mainFrame->document();
973 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
974 document->settings()->setTextAutosizingEnabled(true);
975 EXPECT_TRUE(document->settings()->textAutosizingEnabled());
976 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight));
977 webViewHelper.webViewImpl()->layout();
979 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
980 if (!frame->isLocalFrame())
981 continue;
982 EXPECT_TRUE(setTextAutosizingMultiplier(toLocalFrame(frame)->document(), 2));
983 for (LayoutObject* layoutObject = toLocalFrame(frame)->document()->layoutView(); layoutObject; layoutObject = layoutObject->nextInPreOrder()) {
984 if (layoutObject->isText())
985 EXPECT_FALSE(layoutObject->needsLayout());
989 frameView->page()->frameHost().visualViewport().setSize(IntSize(200, 200));
991 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
992 if (!frame->isLocalFrame())
993 continue;
994 for (LayoutObject* layoutObject = toLocalFrame(frame)->document()->layoutView(); layoutObject; layoutObject = layoutObject->nextInPreOrder()) {
995 if (layoutObject->isText())
996 EXPECT_TRUE(layoutObject->needsLayout());
1001 TEST_P(ParameterizedWebFrameTest, ZeroHeightPositiveWidthNotIgnored)
1003 UseMockScrollbarSettings mockScrollbarSettings;
1005 FixedLayoutTestWebViewClient client;
1006 client.m_screenInfo.deviceScaleFactor = 1;
1007 int viewportWidth = 1280;
1008 int viewportHeight = 0;
1010 FrameTestHelpers::WebViewHelper webViewHelper(this);
1011 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1012 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1014 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1015 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1018 TEST_P(ParameterizedWebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag)
1020 UseMockScrollbarSettings mockScrollbarSettings;
1021 registerMockedHttpURLLoad("no_viewport_tag.html");
1023 int viewportWidth = 640;
1024 int viewportHeight = 480;
1026 FixedLayoutTestWebViewClient client;
1027 client.m_screenInfo.deviceScaleFactor = 2;
1029 FrameTestHelpers::WebViewHelper webViewHelper(this);
1030 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
1032 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1033 webViewHelper.webView()->layout();
1035 EXPECT_EQ(2, webViewHelper.webView()->deviceScaleFactor());
1037 // Device scale factor should be independent of page scale.
1038 webViewHelper.webView()->setDefaultPageScaleLimits(1, 2);
1039 webViewHelper.webView()->setPageScaleFactor(0.5);
1040 webViewHelper.webView()->layout();
1041 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1043 // Force the layout to happen before leaving the test.
1044 webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
1047 TEST_P(ParameterizedWebFrameTest, FixedLayoutInitializeAtMinimumScale)
1049 UseMockScrollbarSettings mockScrollbarSettings;
1051 registerMockedHttpURLLoad("fixed_layout.html");
1053 FixedLayoutTestWebViewClient client;
1054 client.m_screenInfo.deviceScaleFactor = 1;
1055 int viewportWidth = 640;
1056 int viewportHeight = 480;
1058 // Make sure we initialize to minimum scale, even if the window size
1059 // only becomes available after the load begins.
1060 FrameTestHelpers::WebViewHelper webViewHelper(this);
1061 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1062 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
1063 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "fixed_layout.html");
1064 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1066 int defaultFixedLayoutWidth = 980;
1067 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
1068 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1069 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->minimumPageScaleFactor());
1071 // Assume the user has pinch zoomed to page scale factor 2.
1072 float userPinchPageScaleFactor = 2;
1073 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
1074 webViewHelper.webView()->layout();
1076 // Make sure we don't reset to initial scale if the page continues to load.
1077 webViewHelper.webViewImpl()->didCommitLoad(false, false);
1078 webViewHelper.webViewImpl()->didChangeContentsSize();
1079 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1081 // Make sure we don't reset to initial scale if the viewport size changes.
1082 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100));
1083 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1086 TEST_P(ParameterizedWebFrameTest, WideDocumentInitializeAtMinimumScale)
1088 UseMockScrollbarSettings mockScrollbarSettings;
1090 registerMockedHttpURLLoad("wide_document.html");
1092 FixedLayoutTestWebViewClient client;
1093 client.m_screenInfo.deviceScaleFactor = 1;
1094 int viewportWidth = 640;
1095 int viewportHeight = 480;
1097 // Make sure we initialize to minimum scale, even if the window size
1098 // only becomes available after the load begins.
1099 FrameTestHelpers::WebViewHelper webViewHelper(this);
1100 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1101 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
1102 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "wide_document.html");
1103 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1105 int wideDocumentWidth = 1500;
1106 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth;
1107 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1108 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->minimumPageScaleFactor());
1110 // Assume the user has pinch zoomed to page scale factor 2.
1111 float userPinchPageScaleFactor = 2;
1112 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
1113 webViewHelper.webView()->layout();
1115 // Make sure we don't reset to initial scale if the page continues to load.
1116 webViewHelper.webViewImpl()->didCommitLoad(false, false);
1117 webViewHelper.webViewImpl()->didChangeContentsSize();
1118 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1120 // Make sure we don't reset to initial scale if the viewport size changes.
1121 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100));
1122 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1125 TEST_P(ParameterizedWebFrameTest, DelayedViewportInitialScale)
1127 UseMockScrollbarSettings mockScrollbarSettings;
1128 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
1130 FixedLayoutTestWebViewClient client;
1131 client.m_screenInfo.deviceScaleFactor = 1;
1132 int viewportWidth = 640;
1133 int viewportHeight = 480;
1135 FrameTestHelpers::WebViewHelper webViewHelper(this);
1136 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
1137 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1139 EXPECT_EQ(0.25f, webViewHelper.webView()->pageScaleFactor());
1141 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
1142 ViewportDescription description = document->viewportDescription();
1143 description.zoom = 2;
1144 document->setViewportDescription(description);
1145 webViewHelper.webView()->layout();
1146 EXPECT_EQ(2, webViewHelper.webView()->pageScaleFactor());
1149 TEST_P(ParameterizedWebFrameTest, setLoadWithOverviewModeToFalse)
1151 UseMockScrollbarSettings mockScrollbarSettings;
1152 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
1154 FixedLayoutTestWebViewClient client;
1155 client.m_screenInfo.deviceScaleFactor = 1;
1156 int viewportWidth = 640;
1157 int viewportHeight = 480;
1159 FrameTestHelpers::WebViewHelper webViewHelper(this);
1160 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
1161 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1162 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1163 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1165 // The page must be displayed at 100% zoom.
1166 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1169 TEST_P(ParameterizedWebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport)
1171 UseMockScrollbarSettings mockScrollbarSettings;
1172 registerMockedHttpURLLoad("large-div.html");
1174 FixedLayoutTestWebViewClient client;
1175 client.m_screenInfo.deviceScaleFactor = 1;
1176 int viewportWidth = 640;
1177 int viewportHeight = 480;
1179 FrameTestHelpers::WebViewHelper webViewHelper(this);
1180 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1181 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1182 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1183 webViewHelper.webView()->settings()->setUseWideViewport(false);
1184 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1186 // The page must be displayed at 100% zoom, despite that it hosts a wide div element.
1187 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1190 TEST_P(ParameterizedWebFrameTest, NoWideViewportIgnoresPageViewportWidth)
1192 UseMockScrollbarSettings mockScrollbarSettings;
1193 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
1195 FixedLayoutTestWebViewClient client;
1196 client.m_screenInfo.deviceScaleFactor = 1;
1197 int viewportWidth = 640;
1198 int viewportHeight = 480;
1200 FrameTestHelpers::WebViewHelper webViewHelper(this);
1201 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
1202 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1203 webViewHelper.webView()->settings()->setUseWideViewport(false);
1204 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1206 // The page sets viewport width to 3000, but with UseWideViewport == false is must be ignored.
1207 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1208 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1211 TEST_P(ParameterizedWebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale)
1213 UseMockScrollbarSettings mockScrollbarSettings;
1214 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1216 FixedLayoutTestWebViewClient client;
1217 client.m_screenInfo.deviceScaleFactor = 1;
1218 int viewportWidth = 640;
1219 int viewportHeight = 480;
1221 FrameTestHelpers::WebViewHelper webViewHelper(this);
1222 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1223 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1224 webViewHelper.webView()->settings()->setUseWideViewport(false);
1225 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1227 // The page sets viewport width to 3000, but with UseWideViewport == false it must be ignored.
1228 // While the initial scale specified by the page must be accounted.
1229 EXPECT_EQ(viewportWidth / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1230 EXPECT_EQ(viewportHeight / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1233 TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithoutViewportTag)
1235 UseMockScrollbarSettings mockScrollbarSettings;
1236 registerMockedHttpURLLoad("no_viewport_tag.html");
1238 FixedLayoutTestWebViewClient client;
1239 client.m_screenInfo.deviceScaleFactor = 1;
1240 int viewportWidth = 640;
1241 int viewportHeight = 480;
1243 FrameTestHelpers::WebViewHelper webViewHelper(this);
1244 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
1245 applyViewportStyleOverride(&webViewHelper);
1246 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1247 webViewHelper.webView()->settings()->setUseWideViewport(true);
1248 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1250 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1251 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1254 TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithXhtmlMp)
1256 UseMockScrollbarSettings mockScrollbarSettings;
1257 registerMockedHttpURLLoad("viewport/viewport-legacy-xhtmlmp.html");
1259 FixedLayoutTestWebViewClient client;
1260 client.m_screenInfo.deviceScaleFactor = 1;
1261 int viewportWidth = 640;
1262 int viewportHeight = 480;
1264 FrameTestHelpers::WebViewHelper webViewHelper(this);
1265 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1266 applyViewportStyleOverride(&webViewHelper);
1267 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1268 webViewHelper.webView()->settings()->setUseWideViewport(true);
1269 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport/viewport-legacy-xhtmlmp.html");
1271 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1272 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1273 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1276 TEST_P(ParameterizedWebFrameTest, NoWideViewportAndHeightInMeta)
1278 UseMockScrollbarSettings mockScrollbarSettings;
1279 registerMockedHttpURLLoad("viewport-height-1000.html");
1281 FixedLayoutTestWebViewClient client;
1282 client.m_screenInfo.deviceScaleFactor = 1;
1283 int viewportWidth = 640;
1284 int viewportHeight = 480;
1286 FrameTestHelpers::WebViewHelper webViewHelper(this);
1287 webViewHelper.initializeAndLoad(m_baseURL + "viewport-height-1000.html", true, 0, &client, enableViewportSettings);
1288 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1289 webViewHelper.webView()->settings()->setUseWideViewport(false);
1290 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1292 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1295 TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithAutoWidth)
1297 UseMockScrollbarSettings mockScrollbarSettings;
1298 registerMockedHttpURLLoad("viewport-2x-initial-scale.html");
1300 FixedLayoutTestWebViewClient client;
1301 client.m_screenInfo.deviceScaleFactor = 1;
1302 int viewportWidth = 640;
1303 int viewportHeight = 480;
1305 FrameTestHelpers::WebViewHelper webViewHelper(this);
1306 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1307 applyViewportStyleOverride(&webViewHelper);
1308 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1309 webViewHelper.webView()->settings()->setUseWideViewport(true);
1310 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1312 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1313 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1316 TEST_P(ParameterizedWebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode)
1318 UseMockScrollbarSettings mockScrollbarSettings;
1319 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1321 FixedLayoutTestWebViewClient client;
1322 client.m_screenInfo.deviceScaleFactor = 1;
1323 int viewportWidth = 640;
1324 int viewportHeight = 480;
1326 FrameTestHelpers::WebViewHelper webViewHelper(this);
1327 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1328 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1329 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1331 // The page must be displayed at 200% zoom, as specified in its viewport meta tag.
1332 EXPECT_EQ(2.0f, webViewHelper.webView()->pageScaleFactor());
1335 TEST_P(ParameterizedWebFrameTest, setInitialPageScaleFactorPermanently)
1337 UseMockScrollbarSettings mockScrollbarSettings;
1339 registerMockedHttpURLLoad("fixed_layout.html");
1341 FixedLayoutTestWebViewClient client;
1342 client.m_screenInfo.deviceScaleFactor = 1;
1343 float enforcedPageScaleFactor = 2.0f;
1345 FrameTestHelpers::WebViewHelper webViewHelper(this);
1346 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1347 applyViewportStyleOverride(&webViewHelper);
1348 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1349 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1350 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1351 webViewHelper.webView()->layout();
1353 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1355 int viewportWidth = 640;
1356 int viewportHeight = 480;
1357 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1358 webViewHelper.webView()->layout();
1360 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1362 webViewHelper.webView()->setInitialPageScaleOverride(-1);
1363 webViewHelper.webView()->layout();
1364 EXPECT_EQ(1.0, webViewHelper.webView()->pageScaleFactor());
1367 TEST_P(ParameterizedWebFrameTest, PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode)
1369 UseMockScrollbarSettings mockScrollbarSettings;
1370 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
1372 FixedLayoutTestWebViewClient client;
1373 client.m_screenInfo.deviceScaleFactor = 1;
1374 int viewportWidth = 640;
1375 int viewportHeight = 480;
1376 float enforcedPageScaleFactor = 0.5f;
1378 FrameTestHelpers::WebViewHelper webViewHelper(this);
1379 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
1380 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1381 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1382 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1384 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1387 TEST_P(ParameterizedWebFrameTest, PermanentInitialPageScaleFactorOverridesPageViewportInitialScale)
1389 UseMockScrollbarSettings mockScrollbarSettings;
1390 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1392 FixedLayoutTestWebViewClient client;
1393 client.m_screenInfo.deviceScaleFactor = 1;
1394 int viewportWidth = 640;
1395 int viewportHeight = 480;
1396 float enforcedPageScaleFactor = 0.5f;
1398 FrameTestHelpers::WebViewHelper webViewHelper(this);
1399 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1400 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1401 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1403 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1406 TEST_P(ParameterizedWebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered)
1408 UseMockScrollbarSettings mockScrollbarSettings;
1409 const char* pages[] = {
1410 // These pages trigger the clobbering condition. There must be a matching item in "pageScaleFactors" array.
1411 "viewport-device-0.5x-initial-scale.html",
1412 "viewport-initial-scale-1.html",
1413 // These ones do not.
1414 "viewport-auto-initial-scale.html",
1415 "viewport-target-densitydpi-device-and-fixed-width.html"
1417 float pageScaleFactors[] = { 0.5f, 1.0f };
1418 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i)
1419 registerMockedHttpURLLoad(pages[i]);
1421 FixedLayoutTestWebViewClient client;
1422 client.m_screenInfo.deviceScaleFactor = 1;
1423 int viewportWidth = 400;
1424 int viewportHeight = 300;
1425 float enforcedPageScaleFactor = 0.75f;
1427 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i) {
1428 for (int quirkEnabled = 0; quirkEnabled <= 1; ++quirkEnabled) {
1429 FrameTestHelpers::WebViewHelper webViewHelper(this);
1430 webViewHelper.initializeAndLoad(m_baseURL + pages[i], true, 0, &client, enableViewportSettings);
1431 applyViewportStyleOverride(&webViewHelper);
1432 webViewHelper.webView()->settings()->setClobberUserAgentInitialScaleQuirk(quirkEnabled);
1433 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1434 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1436 float expectedPageScaleFactor = quirkEnabled && i < ARRAY_SIZE(pageScaleFactors) ? pageScaleFactors[i] : enforcedPageScaleFactor;
1437 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1442 TEST_P(ParameterizedWebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth)
1444 UseMockScrollbarSettings mockScrollbarSettings;
1446 FixedLayoutTestWebViewClient client;
1447 client.m_screenInfo.deviceScaleFactor = 1;
1448 int viewportWidth = 640;
1449 int viewportHeight = 480;
1450 float enforcedPageScaleFactor = 0.5;
1452 FrameTestHelpers::WebViewHelper webViewHelper(this);
1453 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1454 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1455 webViewHelper.webView()->settings()->setUseWideViewport(false);
1456 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1457 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1458 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1460 EXPECT_EQ(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1461 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1464 TEST_P(ParameterizedWebFrameTest, DocumentElementClientHeightWorksWithWrapContentMode)
1466 UseMockScrollbarSettings mockScrollbarSettings;
1467 registerMockedHttpURLLoad("0-by-0.html");
1469 FixedLayoutTestWebViewClient client;
1470 client.m_screenInfo.deviceScaleFactor = 1;
1471 int viewportWidth = 640;
1472 int viewportHeight = 480;
1474 FrameTestHelpers::WebViewHelper webViewHelper(this);
1476 webViewHelper.initializeAndLoad(m_baseURL + "0-by-0.html", true, 0, &client, configureAndroid);
1477 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1478 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1480 LocalFrame* frame = webViewHelper.webViewImpl()->mainFrameImpl()->frame();
1481 Document* document = frame->document();
1482 EXPECT_EQ(viewportHeight, document->documentElement()->clientHeight());
1483 EXPECT_EQ(viewportWidth, document->documentElement()->clientWidth());
1486 TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeightWorksWithWrapContentMode)
1488 UseMockScrollbarSettings mockScrollbarSettings;
1489 registerMockedHttpURLLoad("0-by-0.html");
1491 FixedLayoutTestWebViewClient client;
1492 client.m_screenInfo.deviceScaleFactor = 1;
1493 int viewportWidth = 640;
1494 int viewportHeight = 480;
1496 FrameTestHelpers::WebViewHelper webViewHelper(this);
1498 webViewHelper.initializeAndLoad(m_baseURL + "0-by-0.html", true, 0, &client, configureAndroid);
1499 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1500 DeprecatedPaintLayerCompositor* compositor = webViewHelper.webViewImpl()->compositor();
1501 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1502 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1503 EXPECT_EQ(0.0, compositor->containerLayer()->size().width());
1504 EXPECT_EQ(0.0, compositor->containerLayer()->size().height());
1506 webViewHelper.webView()->resize(WebSize(viewportWidth, 0));
1507 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1508 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1509 EXPECT_EQ(viewportWidth, compositor->containerLayer()->size().width());
1510 EXPECT_EQ(0.0, compositor->containerLayer()->size().height());
1512 // The flag ForceZeroLayoutHeight will cause the following resize of viewport
1513 // height to be ignored by the outer viewport (the container layer of
1514 // LayerCompositor). The height of the visualViewport, however, is not affected.
1515 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1516 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1517 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1518 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1519 EXPECT_EQ(viewportWidth, compositor->containerLayer()->size().width());
1520 EXPECT_EQ(viewportHeight, compositor->containerLayer()->size().height());
1522 LocalFrame* frame = webViewHelper.webViewImpl()->mainFrameImpl()->frame();
1523 VisualViewport& visualViewport = frame->page()->frameHost().visualViewport();
1524 EXPECT_EQ(viewportHeight, visualViewport.containerLayer()->size().height());
1525 EXPECT_TRUE(visualViewport.containerLayer()->platformLayer()->masksToBounds());
1526 EXPECT_FALSE(compositor->containerLayer()->platformLayer()->masksToBounds());
1529 TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeight)
1531 UseMockScrollbarSettings mockScrollbarSettings;
1532 registerMockedHttpURLLoad("200-by-300.html");
1534 FixedLayoutTestWebViewClient client;
1535 client.m_screenInfo.deviceScaleFactor = 1;
1536 int viewportWidth = 640;
1537 int viewportHeight = 480;
1539 FrameTestHelpers::WebViewHelper webViewHelper(this);
1541 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1542 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1543 webViewHelper.webView()->layout();
1545 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1546 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1547 EXPECT_TRUE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1549 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1551 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight * 2));
1552 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1553 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1555 webViewHelper.webView()->resize(WebSize(viewportWidth * 2, viewportHeight));
1556 webViewHelper.webView()->layout();
1557 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1559 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(false);
1560 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1563 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksWithRelayoutsWhenHeightChanged)
1565 // this unit test is an attempt to target a real world case where an app could
1566 // 1. call resize(width, 0) and setForceZeroLayoutHeight(true)
1567 // 2. load content (hoping that the viewport height would increase
1568 // as more content is added)
1569 // 3. fail to register touch events aimed at the loaded content
1570 // because the layout is only updated if either width or height is changed
1571 UseMockScrollbarSettings mockScrollbarSettings;
1572 registerMockedHttpURLLoad("button.html");
1574 FixedLayoutTestWebViewClient client;
1575 client.m_screenInfo.deviceScaleFactor = 1;
1576 int viewportWidth = 640;
1577 int viewportHeight = 480;
1579 FrameTestHelpers::WebViewHelper webViewHelper;
1581 webViewHelper.initializeAndLoad(m_baseURL + "button.html", true, 0, &client, configureAndroid);
1582 // set view height to zero so that if the height of the view is not
1583 // successfully updated during later resizes touch events will fail
1584 // (as in not hit content included in the view)
1585 webViewHelper.webView()->resize(WebSize(viewportWidth, 0));
1586 webViewHelper.webView()->layout();
1588 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1589 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1591 IntPoint hitPoint = IntPoint(30, 30); // button size is 100x100
1593 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
1594 Document* document = frame->frame()->document();
1595 Element* element = document->getElementById("tap_button");
1597 ASSERT_NE(nullptr, element);
1598 EXPECT_EQ(String("oldValue"), element->innerText());
1600 PlatformGestureEvent gestureEvent(PlatformEvent::Type::GestureTap, hitPoint, hitPoint, IntSize(0, 0), 0, false, false, false, false);
1601 webViewHelper.webViewImpl()->mainFrameImpl()->frame()->eventHandler().handleGestureEvent(gestureEvent);
1602 // when pressed, the button changes its own text to "updatedValue"
1603 EXPECT_EQ(String("updatedValue"), element->innerText());
1606 TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations)
1608 UseMockScrollbarSettings mockScrollbarSettings;
1609 registerMockedHttpURLLoad("200-by-300.html");
1610 registerMockedHttpURLLoad("large-div.html");
1612 FixedLayoutTestWebViewClient client;
1613 client.m_screenInfo.deviceScaleFactor = 1;
1614 int viewportWidth = 640;
1615 int viewportHeight = 480;
1617 FrameTestHelpers::WebViewHelper webViewHelper(this);
1619 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1620 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1621 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1622 webViewHelper.webView()->layout();
1624 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
1625 webViewHelper.webView()->layout();
1627 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1630 TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk)
1632 UseMockScrollbarSettings mockScrollbarSettings;
1633 registerMockedHttpURLLoad("200-by-300.html");
1635 FixedLayoutTestWebViewClient client;
1636 client.m_screenInfo.deviceScaleFactor = 1;
1637 int viewportWidth = 640;
1638 int viewportHeight = 480;
1640 FrameTestHelpers::WebViewHelper webViewHelper(this);
1642 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1643 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1644 webViewHelper.webView()->settings()->setUseWideViewport(true);
1645 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1646 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1647 webViewHelper.webView()->layout();
1649 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1652 TEST_P(ParameterizedWebFrameTest, WideViewportAndWideContentWithInitialScale)
1654 UseMockScrollbarSettings mockScrollbarSettings;
1655 registerMockedHttpURLLoad("wide_document_width_viewport.html");
1657 FixedLayoutTestWebViewClient client;
1658 client.m_screenInfo.deviceScaleFactor = 1;
1659 int viewportWidth = 600;
1660 int viewportHeight = 800;
1662 FrameTestHelpers::WebViewHelper webViewHelper(this);
1663 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1664 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1665 webViewHelper.webView()->settings()->setUseWideViewport(true);
1666 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1667 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1669 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "wide_document_width_viewport.html");
1670 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1672 int wideDocumentWidth = 800;
1673 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth;
1674 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1675 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webViewImpl()->minimumPageScaleFactor());
1678 TEST_P(ParameterizedWebFrameTest, WideViewportQuirkClobbersHeight)
1680 UseMockScrollbarSettings mockScrollbarSettings;
1681 registerMockedHttpURLLoad("viewport-height-1000.html");
1683 FixedLayoutTestWebViewClient client;
1684 client.m_screenInfo.deviceScaleFactor = 1;
1685 int viewportWidth = 600;
1686 int viewportHeight = 800;
1688 FrameTestHelpers::WebViewHelper webViewHelper(this);
1689 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1690 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1691 webViewHelper.webView()->settings()->setUseWideViewport(false);
1692 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1693 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1695 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-height-1000.html");
1696 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1698 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1699 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1702 TEST_P(ParameterizedWebFrameTest, LayoutSize320Quirk)
1704 UseMockScrollbarSettings mockScrollbarSettings;
1705 registerMockedHttpURLLoad("viewport/viewport-30.html");
1707 FixedLayoutTestWebViewClient client;
1708 client.m_screenInfo.deviceScaleFactor = 1;
1709 int viewportWidth = 600;
1710 int viewportHeight = 800;
1712 FrameTestHelpers::WebViewHelper webViewHelper(this);
1713 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1714 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1715 webViewHelper.webView()->settings()->setUseWideViewport(true);
1716 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1717 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1719 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport/viewport-30.html");
1720 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1722 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1723 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1724 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1726 // The magic number to snap to device-width is 320, so test that 321 is
1727 // respected.
1728 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
1729 ViewportDescription description = document->viewportDescription();
1730 description.minWidth = Length(321, blink::Fixed);
1731 description.maxWidth = Length(321, blink::Fixed);
1732 document->setViewportDescription(description);
1733 webViewHelper.webView()->layout();
1734 EXPECT_EQ(321, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1736 description.minWidth = Length(320, blink::Fixed);
1737 description.maxWidth = Length(320, blink::Fixed);
1738 document->setViewportDescription(description);
1739 webViewHelper.webView()->layout();
1740 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1742 description = document->viewportDescription();
1743 description.maxHeight = Length(1000, blink::Fixed);
1744 document->setViewportDescription(description);
1745 webViewHelper.webView()->layout();
1746 EXPECT_EQ(1000, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1748 description.maxHeight = Length(320, blink::Fixed);
1749 document->setViewportDescription(description);
1750 webViewHelper.webView()->layout();
1751 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1754 TEST_P(ParameterizedWebFrameTest, ZeroValuesQuirk)
1756 UseMockScrollbarSettings mockScrollbarSettings;
1757 registerMockedHttpURLLoad("viewport-zero-values.html");
1759 FixedLayoutTestWebViewClient client;
1760 client.m_screenInfo.deviceScaleFactor = 1;
1761 int viewportWidth = 640;
1762 int viewportHeight = 480;
1764 FrameTestHelpers::WebViewHelper webViewHelper(this);
1765 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1766 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1767 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1768 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1769 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-zero-values.html");
1770 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1772 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1773 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1775 webViewHelper.webView()->settings()->setUseWideViewport(true);
1776 webViewHelper.webView()->layout();
1777 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1778 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1781 TEST_P(ParameterizedWebFrameTest, OverflowHiddenDisablesScrolling)
1783 registerMockedHttpURLLoad("body-overflow-hidden.html");
1785 FixedLayoutTestWebViewClient client;
1786 client.m_screenInfo.deviceScaleFactor = 1;
1787 int viewportWidth = 640;
1788 int viewportHeight = 480;
1790 FrameTestHelpers::WebViewHelper webViewHelper(this);
1791 webViewHelper.initialize(true, 0, &client);
1792 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1793 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1795 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1796 EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
1797 EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
1800 TEST_P(ParameterizedWebFrameTest, OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars)
1802 registerMockedHttpURLLoad("body-overflow-hidden-short.html");
1804 FixedLayoutTestWebViewClient client;
1805 client.m_screenInfo.deviceScaleFactor = 1;
1806 int viewportWidth = 640;
1807 int viewportHeight = 480;
1809 FrameTestHelpers::WebViewHelper webViewHelper(this);
1810 webViewHelper.initialize(true, 0, &client);
1811 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden-short.html");
1812 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1814 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1815 EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
1816 EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
1818 webViewHelper.webViewImpl()->mainFrameImpl()->setCanHaveScrollbars(true);
1819 EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
1820 EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
1823 TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk)
1825 registerMockedHttpURLLoad("body-overflow-hidden.html");
1827 FixedLayoutTestWebViewClient client;
1828 client.m_screenInfo.deviceScaleFactor = 1;
1829 int viewportWidth = 640;
1830 int viewportHeight = 480;
1832 FrameTestHelpers::WebViewHelper webViewHelper;
1833 webViewHelper.initialize(true, 0, &client);
1834 webViewHelper.webView()->settings()->setIgnoreMainFrameOverflowHiddenQuirk(true);
1835 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1836 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1838 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1839 EXPECT_TRUE(view->userInputScrollable(VerticalScrollbar));
1842 TEST_P(ParameterizedWebFrameTest, NonZeroValuesNoQuirk)
1844 UseMockScrollbarSettings mockScrollbarSettings;
1845 registerMockedHttpURLLoad("viewport-nonzero-values.html");
1847 FixedLayoutTestWebViewClient client;
1848 client.m_screenInfo.deviceScaleFactor = 1;
1849 int viewportWidth = 640;
1850 int viewportHeight = 480;
1851 float expectedPageScaleFactor = 0.5f;
1853 FrameTestHelpers::WebViewHelper webViewHelper(this);
1854 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1855 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1856 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1857 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-nonzero-values.html");
1858 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1860 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1861 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1863 webViewHelper.webView()->settings()->setUseWideViewport(true);
1864 webViewHelper.webView()->layout();
1865 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1866 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1869 TEST_P(ParameterizedWebFrameTest, setPageScaleFactorDoesNotLayout)
1871 UseMockScrollbarSettings mockScrollbarSettings;
1872 registerMockedHttpURLLoad("fixed_layout.html");
1874 FixedLayoutTestWebViewClient client;
1875 client.m_screenInfo.deviceScaleFactor = 1;
1876 // Small viewport to ensure there are always scrollbars.
1877 int viewportWidth = 64;
1878 int viewportHeight = 48;
1880 FrameTestHelpers::WebViewHelper webViewHelper(this);
1881 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1882 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1883 webViewHelper.webView()->layout();
1885 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1886 webViewHelper.webViewImpl()->setPageScaleFactor(3);
1887 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1888 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1891 TEST_P(ParameterizedWebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout)
1893 UseMockScrollbarSettings mockScrollbarSettings;
1895 registerMockedHttpURLLoad("fixed_layout.html");
1897 FixedLayoutTestWebViewClient client;
1898 client.m_screenInfo.deviceScaleFactor = 1;
1899 int viewportWidth = 640;
1900 int viewportHeight = 480;
1902 FrameTestHelpers::WebViewHelper webViewHelper(this);
1903 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1904 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1905 webViewHelper.webView()->layout();
1907 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1908 webViewHelper.webViewImpl()->setPageScaleFactor(30);
1909 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1910 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1914 TEST_P(ParameterizedWebFrameTest, pageScaleFactorWrittenToHistoryItem)
1916 UseMockScrollbarSettings mockScrollbarSettings;
1917 registerMockedHttpURLLoad("fixed_layout.html");
1919 FixedLayoutTestWebViewClient client;
1920 client.m_screenInfo.deviceScaleFactor = 1;
1921 int viewportWidth = 640;
1922 int viewportHeight = 480;
1924 FrameTestHelpers::WebViewHelper webViewHelper(this);
1925 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1926 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1927 webViewHelper.webView()->layout();
1929 webViewHelper.webView()->setPageScaleFactor(3);
1930 EXPECT_EQ(3, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1933 TEST_P(ParameterizedWebFrameTest, initialScaleWrittenToHistoryItem)
1935 UseMockScrollbarSettings mockScrollbarSettings;
1936 registerMockedHttpURLLoad("fixed_layout.html");
1938 FixedLayoutTestWebViewClient client;
1939 client.m_screenInfo.deviceScaleFactor = 1;
1940 int viewportWidth = 640;
1941 int viewportHeight = 480;
1943 FrameTestHelpers::WebViewHelper webViewHelper(this);
1944 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1945 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
1946 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "fixed_layout.html");
1947 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1948 webViewHelper.webView()->layout();
1950 int defaultFixedLayoutWidth = 980;
1951 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
1952 EXPECT_EQ(minimumPageScaleFactor, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1955 TEST_P(ParameterizedWebFrameTest, pageScaleFactorDoesntShrinkFrameView)
1957 UseMockScrollbarSettings mockScrollbarSettings;
1958 registerMockedHttpURLLoad("large-div.html");
1960 FixedLayoutTestWebViewClient client;
1961 client.m_screenInfo.deviceScaleFactor = 1;
1962 // Small viewport to ensure there are always scrollbars.
1963 int viewportWidth = 64;
1964 int viewportHeight = 48;
1966 FrameTestHelpers::WebViewHelper webViewHelper(this);
1967 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1968 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1969 webViewHelper.webView()->layout();
1971 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1972 int viewportWidthMinusScrollbar = viewportWidth;
1973 int viewportHeightMinusScrollbar = viewportHeight;
1975 if (view->verticalScrollbar() && !view->verticalScrollbar()->isOverlayScrollbar())
1976 viewportWidthMinusScrollbar -= 15;
1978 if (view->horizontalScrollbar() && !view->horizontalScrollbar()->isOverlayScrollbar())
1979 viewportHeightMinusScrollbar -= 15;
1981 webViewHelper.webView()->setPageScaleFactor(2);
1983 IntSize unscaledSize = view->visibleContentSize(IncludeScrollbars);
1984 EXPECT_EQ(viewportWidth, unscaledSize.width());
1985 EXPECT_EQ(viewportHeight, unscaledSize.height());
1987 IntSize unscaledSizeMinusScrollbar = view->visibleContentSize(ExcludeScrollbars);
1988 EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width());
1989 EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height());
1991 IntSize frameViewSize = view->visibleContentRect().size();
1992 EXPECT_EQ(viewportWidthMinusScrollbar, frameViewSize.width());
1993 EXPECT_EQ(viewportHeightMinusScrollbar, frameViewSize.height());
1996 TEST_P(ParameterizedWebFrameTest, pageScaleFactorDoesNotApplyCssTransform)
1998 UseMockScrollbarSettings mockScrollbarSettings;
1999 registerMockedHttpURLLoad("fixed_layout.html");
2001 FixedLayoutTestWebViewClient client;
2002 client.m_screenInfo.deviceScaleFactor = 1;
2003 int viewportWidth = 640;
2004 int viewportHeight = 480;
2006 FrameTestHelpers::WebViewHelper webViewHelper(this);
2007 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
2008 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2009 webViewHelper.webView()->layout();
2011 webViewHelper.webView()->setPageScaleFactor(2);
2013 EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentLayoutObject()->unscaledDocumentRect().width());
2014 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
2017 TEST_P(ParameterizedWebFrameTest, targetDensityDpiHigh)
2019 UseMockScrollbarSettings mockScrollbarSettings;
2020 registerMockedHttpURLLoad("viewport-target-densitydpi-high.html");
2022 FixedLayoutTestWebViewClient client;
2023 // high-dpi = 240
2024 float targetDpi = 240.0f;
2025 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
2026 int viewportWidth = 640;
2027 int viewportHeight = 480;
2029 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
2030 float deviceScaleFactor = deviceScaleFactors[i];
2031 float deviceDpi = deviceScaleFactor * 160.0f;
2032 client.m_screenInfo.deviceScaleFactor = deviceScaleFactor;
2034 FrameTestHelpers::WebViewHelper webViewHelper(this);
2035 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-high.html", true, 0, &client, enableViewportSettings);
2036 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2037 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2038 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2040 // We need to account for the fact that logical pixels are unconditionally multiplied by deviceScaleFactor to produce
2041 // physical pixels.
2042 float densityDpiScaleRatio = deviceScaleFactor * targetDpi / deviceDpi;
2043 EXPECT_NEAR(viewportWidth * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2044 EXPECT_NEAR(viewportHeight * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2045 EXPECT_NEAR(1.0f / densityDpiScaleRatio, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2049 TEST_P(ParameterizedWebFrameTest, targetDensityDpiDevice)
2051 UseMockScrollbarSettings mockScrollbarSettings;
2052 registerMockedHttpURLLoad("viewport-target-densitydpi-device.html");
2054 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
2056 FixedLayoutTestWebViewClient client;
2057 int viewportWidth = 640;
2058 int viewportHeight = 480;
2060 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
2061 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
2063 FrameTestHelpers::WebViewHelper webViewHelper(this);
2064 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device.html", true, 0, &client, enableViewportSettings);
2065 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2066 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2067 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2069 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2070 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2071 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2075 TEST_P(ParameterizedWebFrameTest, targetDensityDpiDeviceAndFixedWidth)
2077 UseMockScrollbarSettings mockScrollbarSettings;
2078 registerMockedHttpURLLoad("viewport-target-densitydpi-device-and-fixed-width.html");
2080 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
2082 FixedLayoutTestWebViewClient client;
2083 int viewportWidth = 640;
2084 int viewportHeight = 480;
2086 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
2087 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
2089 FrameTestHelpers::WebViewHelper webViewHelper(this);
2090 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device-and-fixed-width.html", true, 0, &client, enableViewportSettings);
2091 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2092 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2093 webViewHelper.webView()->settings()->setUseWideViewport(true);
2094 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2096 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2097 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2098 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2102 TEST_P(ParameterizedWebFrameTest, NoWideViewportAndScaleLessThanOne)
2104 UseMockScrollbarSettings mockScrollbarSettings;
2105 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
2107 FixedLayoutTestWebViewClient client;
2108 client.m_screenInfo.deviceScaleFactor = 1.33f;
2109 int viewportWidth = 640;
2110 int viewportHeight = 480;
2112 FrameTestHelpers::WebViewHelper webViewHelper(this);
2113 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1.html", true, 0, &client, enableViewportSettings);
2114 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2115 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2116 webViewHelper.webView()->settings()->setUseWideViewport(false);
2117 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2118 webViewHelper.webView()->layout();
2120 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2121 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2122 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2125 TEST_P(ParameterizedWebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth)
2127 UseMockScrollbarSettings mockScrollbarSettings;
2128 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1-device-width.html");
2130 FixedLayoutTestWebViewClient client;
2131 client.m_screenInfo.deviceScaleFactor = 1.33f;
2132 int viewportWidth = 640;
2133 int viewportHeight = 480;
2135 FrameTestHelpers::WebViewHelper webViewHelper(this);
2136 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true, 0, &client, enableViewportSettings);
2137 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2138 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2139 webViewHelper.webView()->settings()->setUseWideViewport(false);
2140 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2141 webViewHelper.webView()->layout();
2143 const float pageZoom = 0.25f;
2144 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2145 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2146 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2149 TEST_P(ParameterizedWebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride)
2151 UseMockScrollbarSettings mockScrollbarSettings;
2152 registerMockedHttpURLLoad("large-div.html");
2154 FixedLayoutTestWebViewClient client;
2155 int viewportWidth = 640;
2156 int viewportHeight = 480;
2157 float enforcedPageScaleFactor = 5.0f;
2159 FrameTestHelpers::WebViewHelper webViewHelper(this);
2160 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
2161 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
2162 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2163 webViewHelper.webView()->settings()->setUseWideViewport(false);
2164 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
2165 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2166 webViewHelper.webView()->layout();
2168 EXPECT_NEAR(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2169 EXPECT_NEAR(viewportHeight / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2170 EXPECT_NEAR(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2173 TEST_P(ParameterizedWebFrameTest, NoUserScalableQuirkIgnoresViewportScale)
2175 UseMockScrollbarSettings mockScrollbarSettings;
2176 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
2178 FixedLayoutTestWebViewClient client;
2179 int viewportWidth = 640;
2180 int viewportHeight = 480;
2182 FrameTestHelpers::WebViewHelper webViewHelper(this);
2183 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
2184 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
2185 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2186 webViewHelper.webView()->layout();
2188 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2189 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2190 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2193 TEST_P(ParameterizedWebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport)
2195 UseMockScrollbarSettings mockScrollbarSettings;
2196 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
2198 FixedLayoutTestWebViewClient client;
2199 client.m_screenInfo.deviceScaleFactor = 1.33f;
2200 int viewportWidth = 640;
2201 int viewportHeight = 480;
2203 FrameTestHelpers::WebViewHelper webViewHelper(this);
2204 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
2205 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
2206 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
2207 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2208 webViewHelper.webView()->settings()->setUseWideViewport(false);
2209 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2210 webViewHelper.webView()->layout();
2212 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2213 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2214 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2217 TEST_P(ParameterizedWebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport)
2219 UseMockScrollbarSettings mockScrollbarSettings;
2220 registerMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html");
2222 FixedLayoutTestWebViewClient client;
2223 int viewportWidth = 640;
2224 int viewportHeight = 480;
2226 FrameTestHelpers::WebViewHelper webViewHelper(this);
2227 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale-non-user-scalable.html", true, 0, &client, enableViewportSettings);
2228 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
2229 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2230 webViewHelper.webView()->settings()->setUseWideViewport(true);
2231 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2233 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2234 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2235 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2238 TEST_P(ParameterizedWebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff)
2240 UseMockScrollbarSettings mockScrollbarSettings;
2241 registerMockedHttpURLLoad("no_viewport_tag.html");
2243 FixedLayoutTestWebViewClient client;
2244 int viewportWidth = 640;
2245 int viewportHeight = 480;
2247 FrameTestHelpers::WebViewHelper webViewHelper(this);
2248 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
2249 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
2250 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2251 webViewHelper.webView()->settings()->setUseWideViewport(false);
2252 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2254 EXPECT_NEAR(1.0f, webViewHelper.webViewImpl()->pageScaleFactor(), 0.01f);
2255 EXPECT_NEAR(1.0f, webViewHelper.webViewImpl()->minimumPageScaleFactor(), 0.01f);
2256 EXPECT_NEAR(5.0f, webViewHelper.webViewImpl()->maximumPageScaleFactor(), 0.01f);
2259 class WebFrameResizeTest : public ParameterizedWebFrameTest {
2260 protected:
2262 static FloatSize computeRelativeOffset(const IntPoint& absoluteOffset, const LayoutRect& rect)
2264 FloatSize relativeOffset = FloatPoint(absoluteOffset) - FloatPoint(rect.location());
2265 relativeOffset.scale(1.f / rect.width(), 1.f / rect.height());
2266 return relativeOffset;
2269 void testResizeYieldsCorrectScrollAndScale(const char* url,
2270 const float initialPageScaleFactor,
2271 const WebSize scrollOffset,
2272 const WebSize viewportSize,
2273 const bool shouldScaleRelativeToViewportWidth) {
2274 UseMockScrollbarSettings mockScrollbarSettings;
2275 registerMockedHttpURLLoad(url);
2277 const float aspectRatio = static_cast<float>(viewportSize.width) / viewportSize.height;
2279 FrameTestHelpers::WebViewHelper webViewHelper(this);
2280 webViewHelper.initializeAndLoad(m_baseURL + url, true, 0, 0, enableViewportSettings);
2281 webViewHelper.webViewImpl()->setDefaultPageScaleLimits(0.25f, 5);
2283 // Origin scrollOffsets preserved under resize.
2285 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
2286 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
2287 ASSERT_EQ(viewportSize, webViewHelper.webViewImpl()->size());
2288 ASSERT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2289 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
2290 float expectedPageScaleFactor = initialPageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1);
2291 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
2292 EXPECT_EQ(WebSize(), webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2295 // Resizing just the height should not affect pageScaleFactor or scrollOffset.
2297 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
2298 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
2299 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(scrollOffset);
2300 webViewHelper.webViewImpl()->layout();
2301 const WebSize expectedScrollOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
2302 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
2303 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2304 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2305 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
2306 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2307 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2312 INSTANTIATE_TEST_CASE_P(All, WebFrameResizeTest, ::testing::Values(
2313 ParameterizedWebFrameTestConfig::Default,
2314 ParameterizedWebFrameTestConfig::RootLayerScrolls));
2316 TEST_P(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth)
2318 // With width=device-width, pageScaleFactor is preserved across resizes as
2319 // long as the content adjusts according to the device-width.
2320 const char* url = "resize_scroll_mobile.html";
2321 const float initialPageScaleFactor = 1;
2322 const WebSize scrollOffset(0, 50);
2323 const WebSize viewportSize(120, 160);
2324 const bool shouldScaleRelativeToViewportWidth = true;
2326 testResizeYieldsCorrectScrollAndScale(
2327 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2330 TEST_P(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForMinimumScale)
2332 // This tests a scenario where minimum-scale is set to 1.0, but some element
2333 // on the page is slightly larger than the portrait width, so our "natural"
2334 // minimum-scale would be lower. In that case, we should stick to 1.0 scale
2335 // on rotation and not do anything strange.
2336 const char* url = "resize_scroll_minimum_scale.html";
2337 const float initialPageScaleFactor = 1;
2338 const WebSize scrollOffset(0, 0);
2339 const WebSize viewportSize(240, 320);
2340 const bool shouldScaleRelativeToViewportWidth = false;
2342 testResizeYieldsCorrectScrollAndScale(
2343 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2346 TEST_P(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedWidth)
2348 // With a fixed width, pageScaleFactor scales by the relative change in viewport width.
2349 const char* url = "resize_scroll_fixed_width.html";
2350 const float initialPageScaleFactor = 2;
2351 const WebSize scrollOffset(0, 200);
2352 const WebSize viewportSize(240, 320);
2353 const bool shouldScaleRelativeToViewportWidth = true;
2355 testResizeYieldsCorrectScrollAndScale(
2356 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2359 TEST_P(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout)
2361 // With a fixed layout, pageScaleFactor scales by the relative change in viewport width.
2362 const char* url = "resize_scroll_fixed_layout.html";
2363 const float initialPageScaleFactor = 2;
2364 const WebSize scrollOffset(200, 400);
2365 const WebSize viewportSize(320, 240);
2366 const bool shouldScaleRelativeToViewportWidth = true;
2368 testResizeYieldsCorrectScrollAndScale(
2369 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2372 TEST_P(ParameterizedWebFrameTest, pageScaleFactorUpdatesScrollbars)
2374 UseMockScrollbarSettings mockScrollbarSettings;
2375 registerMockedHttpURLLoad("fixed_layout.html");
2377 FixedLayoutTestWebViewClient client;
2378 client.m_screenInfo.deviceScaleFactor = 1;
2379 int viewportWidth = 640;
2380 int viewportHeight = 480;
2382 FrameTestHelpers::WebViewHelper webViewHelper(this);
2383 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
2384 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2385 webViewHelper.webView()->layout();
2387 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2388 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2389 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2391 webViewHelper.webView()->setPageScaleFactor(10);
2393 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2394 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2397 TEST_P(ParameterizedWebFrameTest, CanOverrideScaleLimits)
2399 UseMockScrollbarSettings mockScrollbarSettings;
2401 registerMockedHttpURLLoad("no_scale_for_you.html");
2403 FixedLayoutTestWebViewClient client;
2404 client.m_screenInfo.deviceScaleFactor = 1;
2405 int viewportWidth = 640;
2406 int viewportHeight = 480;
2408 FrameTestHelpers::WebViewHelper webViewHelper(this);
2409 webViewHelper.initializeAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client, enableViewportSettings);
2410 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
2411 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2413 EXPECT_EQ(2.0f, webViewHelper.webViewImpl()->minimumPageScaleFactor());
2414 EXPECT_EQ(2.0f, webViewHelper.webViewImpl()->maximumPageScaleFactor());
2416 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(true);
2417 webViewHelper.webView()->layout();
2419 EXPECT_EQ(1.0f, webViewHelper.webViewImpl()->minimumPageScaleFactor());
2420 EXPECT_EQ(5.0f, webViewHelper.webViewImpl()->maximumPageScaleFactor());
2422 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(false);
2423 webViewHelper.webView()->layout();
2425 EXPECT_EQ(2.0f, webViewHelper.webViewImpl()->minimumPageScaleFactor());
2426 EXPECT_EQ(2.0f, webViewHelper.webViewImpl()->maximumPageScaleFactor());
2429 // Android doesn't have scrollbars on the main FrameView
2430 #if OS(ANDROID)
2431 TEST_F(WebFrameTest, DISABLED_updateOverlayScrollbarLayers)
2432 #else
2433 TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
2434 #endif
2436 UseMockScrollbarSettings mockScrollbarSettings;
2438 registerMockedHttpURLLoad("large-div.html");
2440 int viewWidth = 500;
2441 int viewHeight = 500;
2443 OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
2444 FrameTestHelpers::WebViewHelper webViewHelper;
2445 webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
2447 webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
2448 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
2450 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2451 EXPECT_TRUE(view->layoutView()->compositor()->layerForHorizontalScrollbar());
2452 EXPECT_TRUE(view->layoutView()->compositor()->layerForVerticalScrollbar());
2454 webViewHelper.webView()->resize(WebSize(viewWidth * 10, viewHeight * 10));
2455 webViewHelper.webView()->layout();
2456 EXPECT_FALSE(view->layoutView()->compositor()->layerForHorizontalScrollbar());
2457 EXPECT_FALSE(view->layoutView()->compositor()->layerForVerticalScrollbar());
2460 void setScaleAndScrollAndLayout(WebViewImpl* webView, WebPoint scroll, float scale)
2462 webView->setPageScaleFactor(scale);
2463 webView->mainFrame()->setScrollOffset(WebSize(scroll.x, scroll.y));
2464 webView->layout();
2467 void simulatePageScale(WebViewImpl* webViewImpl, float& scale)
2469 IntSize scrollDelta = webViewImpl->fakePageScaleAnimationTargetPositionForTesting() - webViewImpl->mainFrameImpl()->frameView()->scrollPosition();
2470 float scaleDelta = webViewImpl->fakePageScaleAnimationPageScaleForTesting() / webViewImpl->pageScaleFactor();
2471 webViewImpl->applyViewportDeltas(WebFloatSize(), FloatSize(scrollDelta), WebFloatSize(), scaleDelta, 0);
2472 scale = webViewImpl->pageScaleFactor();
2475 void simulateMultiTargetZoom(WebViewImpl* webViewImpl, const WebRect& rect, float& scale)
2477 if (webViewImpl->zoomToMultipleTargetsRect(rect))
2478 simulatePageScale(webViewImpl, scale);
2481 void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale)
2483 webViewImpl->animateDoubleTapZoom(point);
2484 EXPECT_TRUE(webViewImpl->fakeDoubleTapAnimationPendingForTesting());
2485 simulatePageScale(webViewImpl, scale);
2488 TEST_P(ParameterizedWebFrameTest, DivAutoZoomParamsTest)
2490 registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html");
2492 const float deviceScaleFactor = 2.0f;
2493 int viewportWidth = 640 / deviceScaleFactor;
2494 int viewportHeight = 1280 / deviceScaleFactor;
2495 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2496 FrameTestHelpers::WebViewHelper webViewHelper(this);
2497 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html", false, 0, 0, configureAndroid);
2498 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2499 webViewHelper.webView()->setDefaultPageScaleLimits(0.01f, 4);
2500 webViewHelper.webView()->setPageScaleFactor(0.5f);
2501 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2502 webViewHelper.webView()->layout();
2504 WebRect wideDiv(200, 100, 400, 150);
2505 WebRect tallDiv(200, 300, 400, 800);
2506 WebPoint doubleTapPointWide(wideDiv.x + 50, wideDiv.y + 50);
2507 WebPoint doubleTapPointTall(tallDiv.x + 50, tallDiv.y + 50);
2508 float scale;
2509 WebPoint scroll;
2511 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2513 // Test double-tap zooming into wide div.
2514 WebRect wideBlockBound = webViewHelper.webViewImpl()->computeBlockBound(doubleTapPointWide, false);
2515 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBound, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2516 // The div should horizontally fill the screen (modulo margins), and
2517 // vertically centered (modulo integer rounding).
2518 EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
2519 EXPECT_NEAR(wideDiv.x, scroll.x, 20);
2520 EXPECT_EQ(0, scroll.y);
2522 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
2524 // Test zoom out back to minimum scale.
2525 wideBlockBound = webViewHelper.webViewImpl()->computeBlockBound(doubleTapPointWide, false);
2526 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBound, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2527 // FIXME: Looks like we are missing EXPECTs here.
2529 scale = webViewHelper.webViewImpl()->minimumPageScaleFactor();
2530 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), scale);
2532 // Test double-tap zooming into tall div.
2533 WebRect tallBlockBound = webViewHelper.webViewImpl()->computeBlockBound(doubleTapPointTall, false);
2534 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointTall.x, doubleTapPointTall.y), tallBlockBound, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2535 // The div should start at the top left of the viewport.
2536 EXPECT_NEAR(viewportWidth / (float) tallDiv.width, scale, 0.1);
2537 EXPECT_NEAR(tallDiv.x, scroll.x, 20);
2538 EXPECT_NEAR(tallDiv.y, scroll.y, 20);
2541 TEST_P(ParameterizedWebFrameTest, DivAutoZoomWideDivTest)
2543 registerMockedHttpURLLoad("get_wide_div_for_auto_zoom_test.html");
2545 const float deviceScaleFactor = 2.0f;
2546 int viewportWidth = 640 / deviceScaleFactor;
2547 int viewportHeight = 1280 / deviceScaleFactor;
2548 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2549 FrameTestHelpers::WebViewHelper webViewHelper(this);
2550 webViewHelper.initializeAndLoad(m_baseURL + "get_wide_div_for_auto_zoom_test.html", false, 0, 0, configureAndroid);
2551 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2552 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2553 webViewHelper.webView()->setPageScaleFactor(1.0f);
2554 webViewHelper.webView()->layout();
2556 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2558 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2560 WebRect div(0, 100, viewportWidth, 150);
2561 WebPoint point(div.x + 50, div.y + 50);
2562 float scale;
2563 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2565 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2566 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2567 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2568 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2571 TEST_P(ParameterizedWebFrameTest, DivAutoZoomVeryTallTest)
2573 // When a block is taller than the viewport and a zoom targets a lower part
2574 // of it, then we should keep the target point onscreen instead of snapping
2575 // back up the top of the block.
2576 registerMockedHttpURLLoad("very_tall_div.html");
2578 const float deviceScaleFactor = 2.0f;
2579 int viewportWidth = 640 / deviceScaleFactor;
2580 int viewportHeight = 1280 / deviceScaleFactor;
2581 FrameTestHelpers::WebViewHelper webViewHelper(this);
2582 webViewHelper.initializeAndLoad(m_baseURL + "very_tall_div.html", true, 0, 0, configureAndroid);
2583 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2584 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2585 webViewHelper.webView()->setPageScaleFactor(1.0f);
2586 webViewHelper.webView()->layout();
2588 WebRect div(200, 300, 400, 5000);
2589 WebPoint point(div.x + 50, div.y + 3000);
2590 float scale;
2591 WebPoint scroll;
2593 WebRect blockBound = webViewHelper.webViewImpl()->computeBlockBound(point, true);
2594 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(point, blockBound, 0, 1.0f, scale, scroll);
2595 EXPECT_EQ(scale, 1.0f);
2596 EXPECT_EQ(scroll.y, 2660);
2599 TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest)
2601 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2603 const float deviceScaleFactor = 2.0f;
2604 int viewportWidth = 640 / deviceScaleFactor;
2605 int viewportHeight = 1280 / deviceScaleFactor;
2606 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2607 FrameTestHelpers::WebViewHelper webViewHelper;
2608 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html", false, 0, 0, configureAndroid);
2609 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2610 webViewHelper.webView()->setDefaultPageScaleLimits(0.5f, 4);
2611 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2612 webViewHelper.webView()->setPageScaleFactor(0.5f);
2613 webViewHelper.webView()->setMaximumLegibleScale(1.f);
2614 webViewHelper.webView()->layout();
2616 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2618 WebRect topDiv(200, 100, 200, 150);
2619 WebRect bottomDiv(200, 300, 200, 150);
2620 WebPoint topPoint(topDiv.x + 50, topDiv.y + 50);
2621 WebPoint bottomPoint(bottomDiv.x + 50, bottomDiv.y + 50);
2622 float scale;
2623 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2625 // Test double tap on two different divs
2626 // After first zoom, we should go back to minimum page scale with a second double tap.
2627 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2628 EXPECT_FLOAT_EQ(1, scale);
2629 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2630 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2632 // If the user pinch zooms after double tap, a second double tap should zoom back to the div.
2633 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2634 EXPECT_FLOAT_EQ(1, scale);
2635 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 0.6f, 0);
2636 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2637 EXPECT_FLOAT_EQ(1, scale);
2638 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2639 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2641 // If we didn't yet get an auto-zoom update and a second double-tap arrives, should go back to minimum scale.
2642 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2643 webViewHelper.webViewImpl()->animateDoubleTapZoom(topPoint);
2644 EXPECT_TRUE(webViewHelper.webViewImpl()->fakeDoubleTapAnimationPendingForTesting());
2645 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2646 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2649 TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest)
2651 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2653 int viewportWidth = 320;
2654 int viewportHeight = 480;
2655 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2656 FrameTestHelpers::WebViewHelper webViewHelper;
2657 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html", false, 0, 0, configureAndroid);
2658 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2659 webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2660 webViewHelper.webView()->setMaximumLegibleScale(1.f);
2661 webViewHelper.webView()->layout();
2663 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2665 WebRect div(200, 100, 200, 150);
2666 WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2667 float scale;
2669 // Test double tap scale bounds.
2670 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1
2671 webViewHelper.webView()->setDefaultPageScaleLimits(0.5f, 4);
2672 webViewHelper.webView()->layout();
2673 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2674 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2675 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2676 EXPECT_FLOAT_EQ(1, scale);
2677 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2678 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2679 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2680 EXPECT_FLOAT_EQ(1, scale);
2682 // Zoom in to reset double_tap_zoom_in_effect flag.
2683 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2684 // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2685 webViewHelper.webView()->setDefaultPageScaleLimits(1.1f, 4);
2686 webViewHelper.webView()->layout();
2687 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2688 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2689 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2690 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2691 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2692 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2693 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2694 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2696 // Zoom in to reset double_tap_zoom_in_effect flag.
2697 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2698 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
2699 webViewHelper.webView()->setDefaultPageScaleLimits(0.95f, 4);
2700 webViewHelper.webView()->layout();
2701 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2702 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2703 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2704 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2705 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2706 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2707 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2708 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2711 TEST_F(WebFrameTest, DivAutoZoomScaleLegibleScaleTest)
2713 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2715 int viewportWidth = 320;
2716 int viewportHeight = 480;
2717 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2718 float maximumLegibleScaleFactor = 1.13f;
2719 FrameTestHelpers::WebViewHelper webViewHelper;
2720 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html", false, 0, 0, configureAndroid);
2721 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2722 webViewHelper.webView()->setMaximumLegibleScale(maximumLegibleScaleFactor);
2723 webViewHelper.webView()->layout();
2725 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2726 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(true);
2728 WebRect div(200, 100, 200, 150);
2729 WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2730 float scale;
2732 // Test double tap scale bounds.
2733 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < maximumLegibleScaleFactor
2734 float legibleScale = maximumLegibleScaleFactor;
2735 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2736 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2737 webViewHelper.webView()->setDefaultPageScaleLimits(0.5f, 4);
2738 webViewHelper.webView()->layout();
2739 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2740 EXPECT_FLOAT_EQ(legibleScale, scale);
2741 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2742 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2743 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2744 EXPECT_FLOAT_EQ(legibleScale, scale);
2746 // Zoom in to reset double_tap_zoom_in_effect flag.
2747 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2748 // 1 < maximumLegibleScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2749 webViewHelper.webView()->setDefaultPageScaleLimits(1.0f, 4);
2750 webViewHelper.webView()->layout();
2751 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2752 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2753 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2754 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2755 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2756 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2757 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2758 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2760 // Zoom in to reset double_tap_zoom_in_effect flag.
2761 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2762 // minimumPageScale < 1 < maximumLegibleScaleFactor < doubleTapZoomAlreadyLegibleScale
2763 webViewHelper.webView()->setDefaultPageScaleLimits(0.95f, 4);
2764 webViewHelper.webView()->layout();
2765 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2766 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2767 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2768 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2769 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2770 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2771 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2772 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2774 // Zoom in to reset double_tap_zoom_in_effect flag.
2775 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2776 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < maximumLegibleScaleFactor
2777 webViewHelper.webView()->setDefaultPageScaleLimits(0.9f, 4);
2778 webViewHelper.webView()->layout();
2779 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2780 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2781 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2782 EXPECT_FLOAT_EQ(legibleScale, scale);
2783 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2784 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2785 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2786 EXPECT_FLOAT_EQ(legibleScale, scale);
2790 TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest)
2792 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2794 int viewportWidth = 320;
2795 int viewportHeight = 480;
2796 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2797 float accessibilityFontScaleFactor = 1.13f;
2798 FrameTestHelpers::WebViewHelper webViewHelper;
2799 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html", false, 0, 0, configureAndroid);
2800 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2801 webViewHelper.webView()->setMaximumLegibleScale(1.f);
2802 webViewHelper.webView()->layout();
2804 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2805 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(true);
2806 webViewHelper.webViewImpl()->page()->settings().setAccessibilityFontScaleFactor(accessibilityFontScaleFactor);
2808 WebRect div(200, 100, 200, 150);
2809 WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2810 float scale;
2812 // Test double tap scale bounds.
2813 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < accessibilityFontScaleFactor
2814 float legibleScale = accessibilityFontScaleFactor;
2815 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2816 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2817 webViewHelper.webView()->setDefaultPageScaleLimits(0.5f, 4);
2818 webViewHelper.webView()->layout();
2819 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2820 EXPECT_FLOAT_EQ(legibleScale, scale);
2821 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2822 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2823 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2824 EXPECT_FLOAT_EQ(legibleScale, scale);
2826 // Zoom in to reset double_tap_zoom_in_effect flag.
2827 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2828 // 1 < accessibilityFontScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2829 webViewHelper.webView()->setDefaultPageScaleLimits(1.0f, 4);
2830 webViewHelper.webView()->layout();
2831 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2832 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2833 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2834 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2835 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2836 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2837 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2838 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2840 // Zoom in to reset double_tap_zoom_in_effect flag.
2841 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2842 // minimumPageScale < 1 < accessibilityFontScaleFactor < doubleTapZoomAlreadyLegibleScale
2843 webViewHelper.webView()->setDefaultPageScaleLimits(0.95f, 4);
2844 webViewHelper.webView()->layout();
2845 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2846 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2847 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2848 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2849 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2850 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2851 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2852 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2854 // Zoom in to reset double_tap_zoom_in_effect flag.
2855 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0);
2856 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < accessibilityFontScaleFactor
2857 webViewHelper.webView()->setDefaultPageScaleLimits(0.9f, 4);
2858 webViewHelper.webView()->layout();
2859 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2860 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2861 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2862 EXPECT_FLOAT_EQ(legibleScale, scale);
2863 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2864 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2865 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2866 EXPECT_FLOAT_EQ(legibleScale, scale);
2869 TEST_P(ParameterizedWebFrameTest, BlockBoundTest)
2871 registerMockedHttpURLLoad("block_bound.html");
2873 FrameTestHelpers::WebViewHelper webViewHelper(this);
2874 webViewHelper.initializeAndLoad(m_baseURL + "block_bound.html", false, 0, 0, configureAndroid);
2876 IntRect rectBack = IntRect(0, 0, 200, 200);
2877 IntRect rectLeftTop = IntRect(10, 10, 80, 80);
2878 IntRect rectRightBottom = IntRect(110, 110, 80, 80);
2879 IntRect blockBound;
2881 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(9, 9), true));
2882 EXPECT_RECT_EQ(rectBack, blockBound);
2884 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(10, 10), true));
2885 EXPECT_RECT_EQ(rectLeftTop, blockBound);
2887 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(50, 50), true));
2888 EXPECT_RECT_EQ(rectLeftTop, blockBound);
2890 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(89, 89), true));
2891 EXPECT_RECT_EQ(rectLeftTop, blockBound);
2893 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(90, 90), true));
2894 EXPECT_RECT_EQ(rectBack, blockBound);
2896 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(109, 109), true));
2897 EXPECT_RECT_EQ(rectBack, blockBound);
2899 blockBound = IntRect(webViewHelper.webViewImpl()->computeBlockBound(WebPoint(110, 110), true));
2900 EXPECT_RECT_EQ(rectRightBottom, blockBound);
2903 TEST_P(ParameterizedWebFrameTest, DivMultipleTargetZoomMultipleDivsTest)
2905 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2907 const float deviceScaleFactor = 2.0f;
2908 int viewportWidth = 640 / deviceScaleFactor;
2909 int viewportHeight = 1280 / deviceScaleFactor;
2910 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2911 FrameTestHelpers::WebViewHelper webViewHelper(this);
2912 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
2913 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2914 webViewHelper.webView()->setDefaultPageScaleLimits(0.5f, 4);
2915 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2916 webViewHelper.webView()->setPageScaleFactor(0.5f);
2917 webViewHelper.webView()->setMaximumLegibleScale(1.f);
2918 webViewHelper.webView()->layout();
2920 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2922 WebRect viewportRect(0, 0, viewportWidth, viewportHeight);
2923 WebRect topDiv(200, 100, 200, 150);
2924 WebRect bottomDiv(200, 300, 200, 150);
2925 float scale;
2926 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2928 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2929 EXPECT_FLOAT_EQ(1, scale);
2930 simulateMultiTargetZoom(webViewHelper.webViewImpl(), bottomDiv, scale);
2931 EXPECT_FLOAT_EQ(1, scale);
2932 simulateMultiTargetZoom(webViewHelper.webViewImpl(), viewportRect, scale);
2933 EXPECT_FLOAT_EQ(1, scale);
2934 webViewHelper.webViewImpl()->setPageScaleFactor(webViewHelper.webViewImpl()->minimumPageScaleFactor());
2935 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2936 EXPECT_FLOAT_EQ(1, scale);
2939 TEST_F(WebFrameTest, DontZoomInOnFocusedInTouchAction)
2941 registerMockedHttpURLLoad("textbox_in_touch_action.html");
2943 int viewportWidth = 600;
2944 int viewportHeight = 1000;
2946 FrameTestHelpers::WebViewHelper webViewHelper;
2947 webViewHelper.initializeAndLoad(m_baseURL + "textbox_in_touch_action.html");
2948 webViewHelper.webViewImpl()->setDefaultPageScaleLimits(0.25f, 4);
2949 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2950 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(false);
2951 webViewHelper.webViewImpl()->settings()->setAutoZoomFocusedNodeToLegibleScale(true);
2952 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight));
2954 float initialScale = webViewHelper.webViewImpl()->pageScaleFactor();
2956 // Focus the first textbox that's in a touch-action: pan-x ancestor, this
2957 // shouldn't cause an autozoom since pan-x disables pinch-zoom.
2958 webViewHelper.webViewImpl()->advanceFocus(false);
2959 webViewHelper.webViewImpl()->scrollFocusedNodeIntoRect(WebRect());
2960 EXPECT_EQ(webViewHelper.webViewImpl()->fakePageScaleAnimationPageScaleForTesting(), 0);
2962 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
2963 ASSERT_EQ(initialScale, webViewHelper.webViewImpl()->pageScaleFactor());
2965 // Focus the second textbox that's in a touch-action: manipulation ancestor,
2966 // this should cause an autozoom since it allows pinch-zoom.
2967 webViewHelper.webViewImpl()->advanceFocus(false);
2968 webViewHelper.webViewImpl()->scrollFocusedNodeIntoRect(WebRect());
2969 EXPECT_GT(webViewHelper.webViewImpl()->fakePageScaleAnimationPageScaleForTesting(), initialScale);
2971 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
2972 ASSERT_EQ(initialScale, webViewHelper.webViewImpl()->pageScaleFactor());
2974 // Focus the third textbox that has a touch-action: pan-x ancestor, this
2975 // should cause an autozoom since it's seperated from the node with the
2976 // touch-action by an overflow:scroll element.
2977 webViewHelper.webView()->advanceFocus(false);
2978 webViewHelper.webViewImpl()->scrollFocusedNodeIntoRect(WebRect());
2979 EXPECT_GT(webViewHelper.webViewImpl()->fakePageScaleAnimationPageScaleForTesting(), initialScale);
2983 TEST_F(WebFrameTest, DivScrollIntoEditableTest)
2985 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
2987 const bool autoZoomToLegibleScale = true;
2988 int viewportWidth = 450;
2989 int viewportHeight = 300;
2990 float leftBoxRatio = 0.3f;
2991 int caretPadding = 10;
2992 float minReadableCaretHeight = 16.0f;
2993 FrameTestHelpers::WebViewHelper webViewHelper;
2994 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
2995 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(false);
2996 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2997 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 4);
2999 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
3001 WebRect editBoxWithText(200, 200, 250, 20);
3002 WebRect editBoxWithNoText(200, 250, 250, 20);
3004 // Test scrolling the focused node
3005 // The edit box is shorter and narrower than the viewport when legible.
3006 webViewHelper.webView()->advanceFocus(false);
3007 // Set the caret to the end of the input box.
3008 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(1000, 1000);
3009 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), 1);
3010 WebRect rect, caret;
3011 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
3013 // Set the page scale to be smaller than the minimal readable scale.
3014 float initialScale = minReadableCaretHeight / caret.height * 0.5f;
3015 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
3017 float scale;
3018 IntPoint scroll;
3019 bool needAnimation;
3020 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3021 EXPECT_TRUE(needAnimation);
3022 // The edit box should be left aligned with a margin for possible label.
3023 int hScroll = editBoxWithText.x - leftBoxRatio * viewportWidth / scale;
3024 EXPECT_NEAR(hScroll, scroll.x(), 2);
3025 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
3026 EXPECT_NEAR(vScroll, scroll.y(), 2);
3027 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
3029 // The edit box is wider than the viewport when legible.
3030 viewportWidth = 200;
3031 viewportHeight = 150;
3032 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
3033 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
3034 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3035 EXPECT_TRUE(needAnimation);
3036 // The caret should be right aligned since the caret would be offscreen when the edit box is left aligned.
3037 hScroll = caret.x + caret.width + caretPadding - viewportWidth / scale;
3038 EXPECT_NEAR(hScroll, scroll.x(), 2);
3039 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
3041 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
3042 // Move focus to edit box with text.
3043 webViewHelper.webView()->advanceFocus(false);
3044 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3045 EXPECT_TRUE(needAnimation);
3046 // The edit box should be left aligned.
3047 hScroll = editBoxWithNoText.x;
3048 EXPECT_NEAR(hScroll, scroll.x(), 2);
3049 vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2;
3050 EXPECT_NEAR(vScroll, scroll.y(), 2);
3051 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
3053 // Move focus back to the first edit box.
3054 webViewHelper.webView()->advanceFocus(true);
3055 // Zoom out slightly.
3056 const float withinToleranceScale = scale * 0.9f;
3057 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, withinToleranceScale);
3058 // Move focus back to the second edit box.
3059 webViewHelper.webView()->advanceFocus(false);
3060 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3061 // The scale should not be adjusted as the zoomed out scale was sufficiently close to the previously focused scale.
3062 EXPECT_FALSE(needAnimation);
3065 TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest)
3067 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
3069 const bool autoZoomToLegibleScale = true;
3070 const int viewportWidth = 450;
3071 const int viewportHeight = 300;
3072 const float minReadableCaretHeight = 16.0f;
3073 FrameTestHelpers::WebViewHelper webViewHelper;
3074 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
3075 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(false);
3076 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
3077 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
3079 const WebRect editBoxWithText(200, 200, 250, 20);
3081 webViewHelper.webView()->advanceFocus(false);
3082 // Set the caret to the begining of the input box.
3083 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(0, 0);
3084 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), 1);
3085 WebRect rect, caret;
3086 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
3088 // Set the page scale to be twice as large as the minimal readable scale.
3089 float newScale = minReadableCaretHeight / caret.height * 2.0;
3090 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), newScale);
3092 float scale;
3093 IntPoint scroll;
3094 bool needAnimation;
3095 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3096 EXPECT_TRUE(needAnimation);
3097 // Edit box and caret should be left alinged
3098 int hScroll = editBoxWithText.x;
3099 EXPECT_NEAR(hScroll, scroll.x(), 1);
3100 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
3101 EXPECT_NEAR(vScroll, scroll.y(), 1);
3102 // Page scale have to be unchanged
3103 EXPECT_EQ(newScale, scale);
3105 // Set page scale and scroll such that edit box will be under the screen
3106 newScale = 3.0;
3107 hScroll = 200;
3108 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(hScroll, 0), newScale);
3109 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3110 EXPECT_TRUE(needAnimation);
3111 // Horizontal scroll have to be the same
3112 EXPECT_NEAR(hScroll, scroll.x(), 1);
3113 vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
3114 EXPECT_NEAR(vScroll, scroll.y(), 1);
3115 // Page scale have to be unchanged
3116 EXPECT_EQ(newScale, scale);
3119 // Tests the scroll into view functionality when autoZoomeFocusedNodeToLegibleScale set
3120 // to false. i.e. The path non-Android platforms take.
3121 TEST_F(WebFrameTest, DivScrollIntoEditableTestZoomToLegibleScaleDisabled)
3123 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
3125 const bool autoZoomToLegibleScale = false;
3126 int viewportWidth = 100;
3127 int viewportHeight = 100;
3128 float leftBoxRatio = 0.3f;
3129 FrameTestHelpers::WebViewHelper webViewHelper;
3130 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
3131 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(false);
3132 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
3133 webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 4);
3135 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
3137 WebRect editBoxWithText(200, 200, 250, 20);
3138 WebRect editBoxWithNoText(200, 250, 250, 20);
3140 // Test scrolling the focused node
3141 // Since we're zoomed out, the caret is considered too small to be legible and so we'd
3142 // normally zoom in. Make sure we don't change scale since the auto-zoom setting is off.
3144 // Focus the second empty textbox.
3145 webViewHelper.webView()->advanceFocus(false);
3146 webViewHelper.webView()->advanceFocus(false);
3148 // Set the page scale to be smaller than the minimal readable scale.
3149 float initialScale = 0.25f;
3150 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), initialScale);
3152 float scale;
3153 IntPoint scroll;
3154 bool needAnimation;
3155 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3157 // There should be no change in page scale.
3158 EXPECT_EQ(initialScale, scale);
3159 // The edit box should be left aligned with a margin for possible label.
3160 EXPECT_TRUE(needAnimation);
3161 int hScroll = editBoxWithNoText.x - leftBoxRatio * viewportWidth / scale;
3162 EXPECT_NEAR(hScroll, scroll.x(), 2);
3163 int vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2;
3164 EXPECT_NEAR(vScroll, scroll.y(), 2);
3166 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
3168 // Select the first textbox.
3169 webViewHelper.webView()->advanceFocus(true);
3170 WebRect rect, caret;
3171 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
3172 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), autoZoomToLegibleScale, scale, scroll, needAnimation);
3174 // There should be no change at all since the textbox is fully visible already.
3175 EXPECT_EQ(initialScale, scale);
3176 EXPECT_FALSE(needAnimation);
3179 TEST_P(ParameterizedWebFrameTest, CharacterIndexAtPointWithPinchZoom)
3181 registerMockedHttpURLLoad("sometext.html");
3183 FrameTestHelpers::WebViewHelper webViewHelper(this);
3184 webViewHelper.initializeAndLoad(m_baseURL + "sometext.html");
3185 webViewHelper.webViewImpl()->resize(WebSize(640, 480));
3186 webViewHelper.webViewImpl()->layout();
3189 webViewHelper.webViewImpl()->setPageScaleFactor(2);
3190 webViewHelper.webViewImpl()->setVisualViewportOffset(WebFloatPoint(50, 60));
3192 WebRect baseRect;
3193 WebRect extentRect;
3195 WebFrame* mainFrame = webViewHelper.webViewImpl()->mainFrame();
3196 size_t ix = mainFrame->characterIndexForPoint(WebPoint(320, 388));
3198 EXPECT_EQ(2ul, ix);
3201 TEST_P(ParameterizedWebFrameTest, FirstRectForCharacterRangeWithPinchZoom)
3203 registerMockedHttpURLLoad("textbox.html");
3205 FrameTestHelpers::WebViewHelper webViewHelper(this);
3206 webViewHelper.initializeAndLoad(m_baseURL + "textbox.html", true);
3207 webViewHelper.webViewImpl()->resize(WebSize(640, 480));
3209 WebFrame* mainFrame = webViewHelper.webViewImpl()->mainFrame();
3210 mainFrame->executeScript(WebScriptSource("selectRange();"));
3212 WebRect oldRect;
3213 mainFrame->firstRectForCharacterRange(0, 5, oldRect);
3215 WebFloatPoint visualOffset(100, 130);
3216 float scale = 2;
3217 webViewHelper.webViewImpl()->setPageScaleFactor(scale);
3218 webViewHelper.webViewImpl()->setVisualViewportOffset(visualOffset);
3220 WebRect baseRect;
3221 WebRect extentRect;
3223 WebRect rect;
3224 mainFrame->firstRectForCharacterRange(0, 5, rect);
3226 EXPECT_EQ((oldRect.x - visualOffset.x) * scale, rect.x);
3227 EXPECT_EQ((oldRect.y - visualOffset.y) * scale, rect.y);
3228 EXPECT_EQ(oldRect.width*scale, rect.width);
3229 EXPECT_EQ(oldRect.height*scale, rect.height);
3231 class TestReloadDoesntRedirectWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3232 public:
3233 WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) override
3235 EXPECT_FALSE(info.isRedirect);
3236 return WebNavigationPolicyCurrentTab;
3240 TEST_P(ParameterizedWebFrameTest, ReloadDoesntSetRedirect)
3242 // Test for case in http://crbug.com/73104. Reloading a frame very quickly
3243 // would sometimes call decidePolicyForNavigation with isRedirect=true
3244 registerMockedHttpURLLoad("form.html");
3246 TestReloadDoesntRedirectWebFrameClient webFrameClient;
3247 FrameTestHelpers::WebViewHelper webViewHelper(this);
3248 webViewHelper.initializeAndLoad(m_baseURL + "form.html", false, &webFrameClient);
3250 webViewHelper.webView()->mainFrame()->reload(true);
3251 // start another reload before request is delivered.
3252 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
3255 class ReloadWithOverrideURLTask : public WebTaskRunner::Task {
3256 public:
3257 ReloadWithOverrideURLTask(WebFrame* frame, const KURL& url, bool ignoreCache)
3258 : m_frame(frame), m_url(url), m_ignoreCache(ignoreCache)
3262 void run() override
3264 m_frame->reloadWithOverrideURL(m_url, m_ignoreCache);
3267 private:
3268 WebFrame* const m_frame;
3269 const KURL m_url;
3270 const bool m_ignoreCache;
3273 class ClearScrollStateOnCommitWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3274 public:
3275 void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType) override
3277 frame->view()->resetScrollAndScaleState();
3281 TEST_F(WebFrameTest, ReloadWithOverrideURLPreservesState)
3283 const std::string firstURL = "200-by-300.html";
3284 const std::string secondURL = "content-width-1000.html";
3285 const std::string thirdURL = "very_tall_div.html";
3286 const float pageScaleFactor = 1.1684f;
3287 const int pageWidth = 120;
3288 const int pageHeight = 100;
3290 registerMockedHttpURLLoad(firstURL);
3291 registerMockedHttpURLLoad(secondURL);
3292 registerMockedHttpURLLoad(thirdURL);
3294 FrameTestHelpers::WebViewHelper webViewHelper;
3295 ClearScrollStateOnCommitWebFrameClient client;
3296 webViewHelper.initializeAndLoad(m_baseURL + firstURL, true, &client);
3297 webViewHelper.webViewImpl()->resize(WebSize(pageWidth, pageHeight));
3298 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(WebSize(pageWidth / 4, pageHeight / 4));
3299 webViewHelper.webViewImpl()->setPageScaleFactor(pageScaleFactor);
3301 WebSize previousOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
3302 float previousScale = webViewHelper.webViewImpl()->pageScaleFactor();
3304 // Reload the page and end up at the same url. State should be propagated.
3305 Platform::current()->currentThread()->taskRunner()->postTask(
3306 FROM_HERE, new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + firstURL), false));
3307 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
3308 EXPECT_EQ(previousOffset.width, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().width);
3309 EXPECT_EQ(previousOffset.height, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().height);
3310 EXPECT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor());
3312 // Reload the page using the cache. State should not be propagated.
3313 Platform::current()->currentThread()->taskRunner()->postTask(
3314 FROM_HERE, new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + secondURL), false));
3315 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
3316 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().width);
3317 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().height);
3318 EXPECT_EQ(1.0f, webViewHelper.webViewImpl()->pageScaleFactor());
3320 // Reload the page while ignoring the cache. State should not be propagated.
3321 Platform::current()->currentThread()->taskRunner()->postTask(
3322 FROM_HERE, new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + thirdURL), true));
3323 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
3324 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().width);
3325 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrame()->scrollOffset().height);
3326 EXPECT_EQ(1.0f, webViewHelper.webViewImpl()->pageScaleFactor());
3329 TEST_P(ParameterizedWebFrameTest, ReloadWhileProvisional)
3331 // Test that reloading while the previous load is still pending does not cause the initial
3332 // request to get lost.
3333 registerMockedHttpURLLoad("fixed_layout.html");
3335 FrameTestHelpers::WebViewHelper webViewHelper(this);
3336 webViewHelper.initialize();
3337 WebURLRequest request;
3338 request.initialize();
3339 request.setURL(toKURL(m_baseURL + "fixed_layout.html"));
3340 webViewHelper.webView()->mainFrame()->loadRequest(request);
3341 // start reload before first request is delivered.
3342 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
3344 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
3345 ASSERT_TRUE(dataSource);
3346 EXPECT_EQ(toKURL(m_baseURL + "fixed_layout.html"), toKURL(dataSource->request().url().spec()));
3349 TEST_P(ParameterizedWebFrameTest, AppendRedirects)
3351 const std::string firstURL = "about:blank";
3352 const std::string secondURL = "http://internal.test";
3354 FrameTestHelpers::WebViewHelper webViewHelper(this);
3355 webViewHelper.initializeAndLoad(firstURL, true);
3357 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
3358 ASSERT_TRUE(dataSource);
3359 dataSource->appendRedirect(toKURL(secondURL));
3361 WebVector<WebURL> redirects;
3362 dataSource->redirectChain(redirects);
3363 ASSERT_EQ(2U, redirects.size());
3364 EXPECT_EQ(toKURL(firstURL), toKURL(redirects[0].spec().data()));
3365 EXPECT_EQ(toKURL(secondURL), toKURL(redirects[1].spec().data()));
3368 TEST_P(ParameterizedWebFrameTest, IframeRedirect)
3370 registerMockedHttpURLLoad("iframe_redirect.html");
3371 registerMockedHttpURLLoad("visible_iframe.html");
3373 FrameTestHelpers::WebViewHelper webViewHelper(this);
3374 webViewHelper.initializeAndLoad(m_baseURL + "iframe_redirect.html", true);
3375 // Pump pending requests one more time. The test page loads script that navigates.
3376 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
3378 WebFrame* iframe = webViewHelper.webView()->findFrameByName(WebString::fromUTF8("ifr"));
3379 ASSERT_TRUE(iframe);
3380 WebDataSource* iframeDataSource = iframe->dataSource();
3381 ASSERT_TRUE(iframeDataSource);
3382 WebVector<WebURL> redirects;
3383 iframeDataSource->redirectChain(redirects);
3384 ASSERT_EQ(2U, redirects.size());
3385 EXPECT_EQ(toKURL("about:blank"), toKURL(redirects[0].spec().data()));
3386 EXPECT_EQ(toKURL("http://internal.test/visible_iframe.html"), toKURL(redirects[1].spec().data()));
3389 TEST_P(ParameterizedWebFrameTest, ClearFocusedNodeTest)
3391 registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
3392 registerMockedHttpURLLoad("autofocus_input_field_iframe.html");
3394 FrameTestHelpers::WebViewHelper webViewHelper(this);
3395 webViewHelper.initializeAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true);
3397 // Clear the focused node.
3398 webViewHelper.webView()->clearFocusedElement();
3400 // Now retrieve the FocusedNode and test it should be null.
3401 EXPECT_EQ(0, webViewHelper.webViewImpl()->focusedElement());
3404 // Implementation of WebFrameClient that tracks the v8 contexts that are created
3405 // and destroyed for verification.
3406 class ContextLifetimeTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3407 public:
3408 struct Notification {
3409 public:
3410 Notification(WebLocalFrame* frame, v8::Local<v8::Context> context, int worldId)
3411 : frame(frame)
3412 , context(context->GetIsolate(), context)
3413 , worldId(worldId)
3417 ~Notification()
3419 context.Reset();
3422 bool Equals(Notification* other)
3424 return other && frame == other->frame && context == other->context && worldId == other->worldId;
3427 WebLocalFrame* frame;
3428 v8::Persistent<v8::Context> context;
3429 int worldId;
3432 ~ContextLifetimeTestWebFrameClient() override
3434 reset();
3437 void reset()
3439 for (size_t i = 0; i < createNotifications.size(); ++i)
3440 delete createNotifications[i];
3442 for (size_t i = 0; i < releaseNotifications.size(); ++i)
3443 delete releaseNotifications[i];
3445 createNotifications.clear();
3446 releaseNotifications.clear();
3449 std::vector<Notification*> createNotifications;
3450 std::vector<Notification*> releaseNotifications;
3452 private:
3453 void didCreateScriptContext(WebLocalFrame* frame, v8::Local<v8::Context> context, int extensionGroup, int worldId) override
3455 createNotifications.push_back(new Notification(frame, context, worldId));
3458 void willReleaseScriptContext(WebLocalFrame* frame, v8::Local<v8::Context> context, int worldId) override
3460 releaseNotifications.push_back(new Notification(frame, context, worldId));
3464 // TODO(aa): Deflake this test.
3465 TEST_P(ParameterizedWebFrameTest, FLAKY_ContextNotificationsLoadUnload)
3467 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
3469 registerMockedHttpURLLoad("context_notifications_test.html");
3470 registerMockedHttpURLLoad("context_notifications_test_frame.html");
3472 // Load a frame with an iframe, make sure we get the right create notifications.
3473 ContextLifetimeTestWebFrameClient webFrameClient;
3474 FrameTestHelpers::WebViewHelper webViewHelper(this);
3475 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
3477 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
3478 WebFrame* childFrame = mainFrame->firstChild();
3480 ASSERT_EQ(2u, webFrameClient.createNotifications.size());
3481 EXPECT_EQ(0u, webFrameClient.releaseNotifications.size());
3483 ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0];
3484 ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1];
3486 EXPECT_EQ(mainFrame, firstCreateNotification->frame);
3487 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context);
3488 EXPECT_EQ(0, firstCreateNotification->worldId);
3490 EXPECT_EQ(childFrame, secondCreateNotification->frame);
3491 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context);
3492 EXPECT_EQ(0, secondCreateNotification->worldId);
3494 // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order.
3495 webViewHelper.reset();
3497 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
3498 ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0];
3499 ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1];
3501 ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification));
3502 ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification));
3505 TEST_P(ParameterizedWebFrameTest, ContextNotificationsReload)
3507 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
3509 registerMockedHttpURLLoad("context_notifications_test.html");
3510 registerMockedHttpURLLoad("context_notifications_test_frame.html");
3512 ContextLifetimeTestWebFrameClient webFrameClient;
3513 FrameTestHelpers::WebViewHelper webViewHelper(this);
3514 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
3516 // Refresh, we should get two release notifications and two more create notifications.
3517 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
3518 ASSERT_EQ(4u, webFrameClient.createNotifications.size());
3519 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
3521 // The two release notifications we got should be exactly the same as the first two create notifications.
3522 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
3523 EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals(
3524 webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i]));
3527 // The last two create notifications should be for the current frames and context.
3528 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
3529 WebFrame* childFrame = mainFrame->firstChild();
3530 ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2];
3531 ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3];
3533 EXPECT_EQ(mainFrame, firstRefreshNotification->frame);
3534 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context);
3535 EXPECT_EQ(0, firstRefreshNotification->worldId);
3537 EXPECT_EQ(childFrame, secondRefreshNotification->frame);
3538 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context);
3539 EXPECT_EQ(0, secondRefreshNotification->worldId);
3542 TEST_P(ParameterizedWebFrameTest, ContextNotificationsIsolatedWorlds)
3544 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3545 v8::HandleScope handleScope(isolate);
3547 registerMockedHttpURLLoad("context_notifications_test.html");
3548 registerMockedHttpURLLoad("context_notifications_test_frame.html");
3550 ContextLifetimeTestWebFrameClient webFrameClient;
3551 FrameTestHelpers::WebViewHelper webViewHelper(this);
3552 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
3554 // Add an isolated world.
3555 webFrameClient.reset();
3557 int isolatedWorldId = 42;
3558 WebScriptSource scriptSource("hi!");
3559 int numSources = 1;
3560 int extensionGroup = 0;
3561 webViewHelper.webView()->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup);
3563 // We should now have a new create notification.
3564 ASSERT_EQ(1u, webFrameClient.createNotifications.size());
3565 ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0];
3566 ASSERT_EQ(isolatedWorldId, notification->worldId);
3567 ASSERT_EQ(webViewHelper.webView()->mainFrame(), notification->frame);
3569 // We don't have an API to enumarate isolated worlds for a frame, but we can at least assert that the context we got is *not* the main world's context.
3570 ASSERT_NE(webViewHelper.webView()->mainFrame()->mainWorldScriptContext(), v8::Local<v8::Context>::New(isolate, notification->context));
3572 webViewHelper.reset();
3574 // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context).
3575 ASSERT_EQ(3u, webFrameClient.releaseNotifications.size());
3577 // And one of them should be exactly the same as the create notification for the isolated context.
3578 int matchCount = 0;
3579 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
3580 if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0]))
3581 ++matchCount;
3583 EXPECT_EQ(1, matchCount);
3586 TEST_P(ParameterizedWebFrameTest, FindInPage)
3588 registerMockedHttpURLLoad("find.html");
3589 FrameTestHelpers::WebViewHelper webViewHelper(this);
3590 webViewHelper.initializeAndLoad(m_baseURL + "find.html");
3591 WebFrame* frame = webViewHelper.webView()->mainFrame();
3592 const int findIdentifier = 12345;
3593 WebFindOptions options;
3595 // Find in a <div> element.
3596 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0));
3597 frame->stopFinding(false);
3598 WebRange range = frame->selectionRange();
3599 EXPECT_EQ(5, range.startOffset());
3600 EXPECT_EQ(9, range.endOffset());
3601 EXPECT_TRUE(frame->document().focusedElement().isNull());
3603 // Find in an <input> value.
3604 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0));
3605 // Confirm stopFinding(false) sets the selection on the found text.
3606 frame->stopFinding(false);
3607 range = frame->selectionRange();
3608 ASSERT_FALSE(range.isNull());
3609 EXPECT_EQ(5, range.startOffset());
3610 EXPECT_EQ(9, range.endOffset());
3611 EXPECT_TRUE(frame->document().focusedElement().hasHTMLTagName("input"));
3613 // Find in a <textarea> content.
3614 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0));
3615 // Confirm stopFinding(false) sets the selection on the found text.
3616 frame->stopFinding(false);
3617 range = frame->selectionRange();
3618 ASSERT_FALSE(range.isNull());
3619 EXPECT_EQ(5, range.startOffset());
3620 EXPECT_EQ(9, range.endOffset());
3621 EXPECT_TRUE(frame->document().focusedElement().hasHTMLTagName("textarea"));
3623 // Find in a contentEditable element.
3624 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0));
3625 // Confirm stopFinding(false) sets the selection on the found text.
3626 frame->stopFinding(false);
3627 range = frame->selectionRange();
3628 ASSERT_FALSE(range.isNull());
3629 EXPECT_EQ(0, range.startOffset());
3630 EXPECT_EQ(4, range.endOffset());
3631 // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>.
3632 EXPECT_TRUE(frame->document().focusedElement().hasHTMLTagName("div"));
3634 // Find in <select> content.
3635 EXPECT_FALSE(frame->find(findIdentifier, WebString::fromUTF8("bar5"), options, false, 0));
3636 // If there are any matches, stopFinding will set the selection on the found text.
3637 // However, we do not expect any matches, so check that the selection is null.
3638 frame->stopFinding(false);
3639 range = frame->selectionRange();
3640 ASSERT_TRUE(range.isNull());
3643 TEST_P(ParameterizedWebFrameTest, GetContentAsPlainText)
3645 FrameTestHelpers::WebViewHelper webViewHelper(this);
3646 webViewHelper.initializeAndLoad("about:blank", true);
3647 // We set the size because it impacts line wrapping, which changes the
3648 // resulting text value.
3649 webViewHelper.webView()->resize(WebSize(640, 480));
3650 WebFrame* frame = webViewHelper.webView()->mainFrame();
3652 // Generate a simple test case.
3653 const char simpleSource[] = "<div>Foo bar</div><div></div>baz";
3654 KURL testURL = toKURL("about:blank");
3655 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3657 // Make sure it comes out OK.
3658 const std::string expected("Foo bar\nbaz");
3659 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3660 EXPECT_EQ(expected, text.utf8());
3662 // Try reading the same one with clipping of the text.
3663 const int length = 5;
3664 text = frame->contentAsText(length);
3665 EXPECT_EQ(expected.substr(0, length), text.utf8());
3667 // Now do a new test with a subframe.
3668 const char outerFrameSource[] = "Hello<iframe></iframe> world";
3669 FrameTestHelpers::loadHTMLString(frame, outerFrameSource, testURL);
3671 // Load something into the subframe.
3672 WebFrame* subframe = frame->firstChild();
3673 ASSERT_TRUE(subframe);
3674 FrameTestHelpers::loadHTMLString(subframe, "sub<p>text", testURL);
3676 text = frame->contentAsText(std::numeric_limits<size_t>::max());
3677 EXPECT_EQ("Hello world\n\nsub\ntext", text.utf8());
3679 // Get the frame text where the subframe separator falls on the boundary of
3680 // what we'll take. There used to be a crash in this case.
3681 text = frame->contentAsText(12);
3682 EXPECT_EQ("Hello world", text.utf8());
3685 TEST_P(ParameterizedWebFrameTest, GetFullHtmlOfPage)
3687 FrameTestHelpers::WebViewHelper webViewHelper(this);
3688 webViewHelper.initializeAndLoad("about:blank", true);
3689 WebFrame* frame = webViewHelper.webView()->mainFrame();
3691 // Generate a simple test case.
3692 const char simpleSource[] = "<p>Hello</p><p>World</p>";
3693 KURL testURL = toKURL("about:blank");
3694 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3696 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3697 EXPECT_EQ("Hello\n\nWorld", text.utf8());
3699 const std::string html = frame->contentAsMarkup().utf8();
3701 // Load again with the output html.
3702 FrameTestHelpers::loadHTMLString(frame, html, testURL);
3704 EXPECT_EQ(html, frame->contentAsMarkup().utf8());
3706 text = frame->contentAsText(std::numeric_limits<size_t>::max());
3707 EXPECT_EQ("Hello\n\nWorld", text.utf8());
3709 // Test selection check
3710 EXPECT_FALSE(frame->hasSelection());
3711 frame->executeCommand(WebString::fromUTF8("SelectAll"));
3712 EXPECT_TRUE(frame->hasSelection());
3713 frame->executeCommand(WebString::fromUTF8("Unselect"));
3714 EXPECT_FALSE(frame->hasSelection());
3715 WebString selectionHtml = frame->selectionAsMarkup();
3716 EXPECT_TRUE(selectionHtml.isEmpty());
3719 class TestExecuteScriptDuringDidCreateScriptContext : public FrameTestHelpers::TestWebFrameClient {
3720 public:
3721 void didCreateScriptContext(WebLocalFrame* frame, v8::Local<v8::Context> context, int extensionGroup, int worldId) override
3723 frame->executeScript(WebScriptSource("window.history = 'replaced';"));
3727 TEST_P(ParameterizedWebFrameTest, ExecuteScriptDuringDidCreateScriptContext)
3729 registerMockedHttpURLLoad("hello_world.html");
3731 TestExecuteScriptDuringDidCreateScriptContext webFrameClient;
3732 FrameTestHelpers::WebViewHelper webViewHelper(this);
3733 webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient);
3735 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
3738 class FindUpdateWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3739 public:
3740 FindUpdateWebFrameClient()
3741 : m_findResultsAreReady(false)
3742 , m_count(-1)
3746 void reportFindInPageMatchCount(int, int count, bool finalUpdate) override
3748 m_count = count;
3749 if (finalUpdate)
3750 m_findResultsAreReady = true;
3753 bool findResultsAreReady() const { return m_findResultsAreReady; }
3754 int count() const { return m_count; }
3756 private:
3757 bool m_findResultsAreReady;
3758 int m_count;
3761 TEST_P(ParameterizedWebFrameTest, FindInPageMatchRects)
3763 registerMockedHttpURLLoad("find_in_page.html");
3764 registerMockedHttpURLLoad("find_in_page_frame.html");
3766 FindUpdateWebFrameClient client;
3767 FrameTestHelpers::WebViewHelper webViewHelper(this);
3768 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3769 webViewHelper.webView()->resize(WebSize(640, 480));
3770 webViewHelper.webView()->setMaximumLegibleScale(1.f);
3771 webViewHelper.webView()->layout();
3772 runPendingTasks();
3774 // Note that the 'result 19' in the <select> element is not expected to produce a match.
3775 static const char* kFindString = "result";
3776 static const int kFindIdentifier = 12345;
3777 static const int kNumResults = 19;
3779 WebFindOptions options;
3780 WebString searchText = WebString::fromUTF8(kFindString);
3781 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3782 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3784 mainFrame->resetMatchCount();
3786 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3787 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3789 runPendingTasks();
3790 EXPECT_TRUE(client.findResultsAreReady());
3792 WebVector<WebFloatRect> webMatchRects;
3793 mainFrame->findMatchRects(webMatchRects);
3794 ASSERT_EQ(webMatchRects.size(), static_cast<size_t>(kNumResults));
3795 int rectsVersion = mainFrame->findMatchMarkersVersion();
3797 for (int resultIndex = 0; resultIndex < kNumResults; ++resultIndex) {
3798 FloatRect resultRect = static_cast<FloatRect>(webMatchRects[resultIndex]);
3800 // Select the match by the center of its rect.
3801 EXPECT_EQ(mainFrame->selectNearestFindMatch(resultRect.center(), 0), resultIndex + 1);
3803 // Check that the find result ordering matches with our expectations.
3804 Range* result = mainFrame->activeMatchFrame()->activeMatch();
3805 ASSERT_TRUE(result);
3806 result->setEnd(result->endContainer(), result->endOffset() + 3);
3807 EXPECT_EQ(result->text(), String::format("%s %02d", kFindString, resultIndex));
3809 // Verify that the expected match rect also matches the currently active match.
3810 // Compare the enclosing rects to prevent precision issues caused by CSS transforms.
3811 FloatRect activeMatch = mainFrame->activeFindMatchRect();
3812 EXPECT_EQ(enclosingIntRect(activeMatch), enclosingIntRect(resultRect));
3814 // The rects version should not have changed.
3815 EXPECT_EQ(mainFrame->findMatchMarkersVersion(), rectsVersion);
3818 // All results after the first two ones should be below between them in find-in-page coordinates.
3819 // This is because results 2 to 9 are inside an iframe located between results 0 and 1. This applies to the fixed div too.
3820 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[1].y);
3821 for (int resultIndex = 2; resultIndex < kNumResults; ++resultIndex) {
3822 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[resultIndex].y);
3823 EXPECT_TRUE(webMatchRects[1].y > webMatchRects[resultIndex].y);
3826 // Result 3 should be below both 2 and 4. This is caused by the CSS transform in the containing div.
3827 // If the transform doesn't work then 3 will be between 2 and 4.
3828 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[2].y);
3829 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[4].y);
3831 // Results 6, 7, 8 and 9 should be one below the other in that same order.
3832 // If overflow:scroll is not properly handled then result 8 would be below result 9 or
3833 // result 7 above result 6 depending on the scroll.
3834 EXPECT_TRUE(webMatchRects[6].y < webMatchRects[7].y);
3835 EXPECT_TRUE(webMatchRects[7].y < webMatchRects[8].y);
3836 EXPECT_TRUE(webMatchRects[8].y < webMatchRects[9].y);
3838 // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are inside the table.
3839 EXPECT_TRUE(webMatchRects[11].y > webMatchRects[10].y);
3840 EXPECT_TRUE(webMatchRects[12].y > webMatchRects[10].y);
3841 EXPECT_TRUE(webMatchRects[13].y > webMatchRects[10].y);
3842 EXPECT_TRUE(webMatchRects[14].y > webMatchRects[10].y);
3843 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[15].y);
3844 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[15].y);
3845 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[15].y);
3846 EXPECT_TRUE(webMatchRects[14].y < webMatchRects[15].y);
3848 // Result 11 should be above 12, 13 and 14 as it's in the table header.
3849 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[12].y);
3850 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[13].y);
3851 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[14].y);
3853 // Result 11 should also be right to 12, 13 and 14 because of the colspan.
3854 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[12].x);
3855 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[13].x);
3856 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[14].x);
3858 // Result 12 should be left to results 11, 13 and 14 in the table layout.
3859 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[11].x);
3860 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[13].x);
3861 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[14].x);
3863 // Results 13, 12 and 14 should be one above the other in that order because of the rowspan
3864 // and vertical-align: middle by default.
3865 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[12].y);
3866 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[14].y);
3868 // Result 16 should be below result 15.
3869 EXPECT_TRUE(webMatchRects[15].y > webMatchRects[14].y);
3871 // Result 18 should be normalized with respect to the position:relative div, and not it's
3872 // immediate containing div. Consequently, result 18 should be above result 17.
3873 EXPECT_TRUE(webMatchRects[17].y > webMatchRects[18].y);
3875 // Resizing should update the rects version.
3876 webViewHelper.webView()->resize(WebSize(800, 600));
3877 webViewHelper.webView()->layout();
3878 runPendingTasks();
3879 EXPECT_TRUE(mainFrame->findMatchMarkersVersion() != rectsVersion);
3882 TEST_P(ParameterizedWebFrameTest, FindInPageSkipsHiddenFrames)
3884 registerMockedHttpURLLoad("find_in_hidden_frame.html");
3886 FindUpdateWebFrameClient client;
3887 FrameTestHelpers::WebViewHelper webViewHelper(this);
3888 webViewHelper.initializeAndLoad(m_baseURL + "find_in_hidden_frame.html", true, &client);
3889 webViewHelper.webView()->resize(WebSize(640, 480));
3890 webViewHelper.webView()->layout();
3891 runPendingTasks();
3893 static const char* kFindString = "hello";
3894 static const int kFindIdentifier = 12345;
3895 static const int kNumResults = 1;
3897 WebFindOptions options;
3898 WebString searchText = WebString::fromUTF8(kFindString);
3899 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3900 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3902 mainFrame->resetMatchCount();
3904 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3905 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3907 runPendingTasks();
3908 EXPECT_TRUE(client.findResultsAreReady());
3909 EXPECT_EQ(kNumResults, client.count());
3912 TEST_P(ParameterizedWebFrameTest, FindOnDetachedFrame)
3914 registerMockedHttpURLLoad("find_in_page.html");
3915 registerMockedHttpURLLoad("find_in_page_frame.html");
3917 FindUpdateWebFrameClient client;
3918 FrameTestHelpers::WebViewHelper webViewHelper(this);
3919 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3920 webViewHelper.webView()->resize(WebSize(640, 480));
3921 webViewHelper.webView()->layout();
3922 runPendingTasks();
3924 static const char* kFindString = "result";
3925 static const int kFindIdentifier = 12345;
3927 WebFindOptions options;
3928 WebString searchText = WebString::fromUTF8(kFindString);
3929 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3930 RefPtrWillBeRawPtr<WebLocalFrameImpl> secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3931 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
3933 // Detach the frame before finding.
3934 removeElementById(mainFrame, "frame");
3936 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3937 EXPECT_FALSE(secondFrame->find(kFindIdentifier, searchText, options, false, 0));
3939 runPendingTasks();
3940 EXPECT_FALSE(client.findResultsAreReady());
3942 mainFrame->resetMatchCount();
3944 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3945 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3947 runPendingTasks();
3948 EXPECT_TRUE(client.findResultsAreReady());
3951 TEST_P(ParameterizedWebFrameTest, FindDetachFrameBeforeScopeStrings)
3953 registerMockedHttpURLLoad("find_in_page.html");
3954 registerMockedHttpURLLoad("find_in_page_frame.html");
3956 FindUpdateWebFrameClient client;
3957 FrameTestHelpers::WebViewHelper webViewHelper(this);
3958 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3959 webViewHelper.webView()->resize(WebSize(640, 480));
3960 webViewHelper.webView()->layout();
3961 runPendingTasks();
3963 static const char* kFindString = "result";
3964 static const int kFindIdentifier = 12345;
3966 WebFindOptions options;
3967 WebString searchText = WebString::fromUTF8(kFindString);
3968 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3969 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3970 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
3972 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3973 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
3975 runPendingTasks();
3976 EXPECT_FALSE(client.findResultsAreReady());
3978 // Detach the frame between finding and scoping.
3979 removeElementById(mainFrame, "frame");
3981 mainFrame->resetMatchCount();
3983 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3984 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3986 runPendingTasks();
3987 EXPECT_TRUE(client.findResultsAreReady());
3990 TEST_P(ParameterizedWebFrameTest, FindDetachFrameWhileScopingStrings)
3992 registerMockedHttpURLLoad("find_in_page.html");
3993 registerMockedHttpURLLoad("find_in_page_frame.html");
3995 FindUpdateWebFrameClient client;
3996 FrameTestHelpers::WebViewHelper webViewHelper(this);
3997 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3998 webViewHelper.webView()->resize(WebSize(640, 480));
3999 webViewHelper.webView()->layout();
4000 runPendingTasks();
4002 static const char* kFindString = "result";
4003 static const int kFindIdentifier = 12345;
4005 WebFindOptions options;
4006 WebString searchText = WebString::fromUTF8(kFindString);
4007 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4008 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
4009 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
4011 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
4012 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
4014 runPendingTasks();
4015 EXPECT_FALSE(client.findResultsAreReady());
4017 mainFrame->resetMatchCount();
4019 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
4020 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
4022 // The first scopeStringMatches will have reset the state. Detach before it actually scopes.
4023 removeElementById(mainFrame, "frame");
4025 runPendingTasks();
4026 EXPECT_TRUE(client.findResultsAreReady());
4029 TEST_P(ParameterizedWebFrameTest, ResetMatchCount)
4031 registerMockedHttpURLLoad("find_in_generated_frame.html");
4033 FindUpdateWebFrameClient client;
4034 FrameTestHelpers::WebViewHelper webViewHelper(this);
4035 webViewHelper.initializeAndLoad(m_baseURL + "find_in_generated_frame.html", true, &client);
4036 webViewHelper.webView()->resize(WebSize(640, 480));
4037 webViewHelper.webView()->layout();
4038 runPendingTasks();
4040 static const char* kFindString = "result";
4041 static const int kFindIdentifier = 12345;
4043 WebFindOptions options;
4044 WebString searchText = WebString::fromUTF8(kFindString);
4045 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4047 // Check that child frame exists.
4048 EXPECT_TRUE(!!mainFrame->traverseNext(false));
4050 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) {
4051 EXPECT_FALSE(frame->find(kFindIdentifier, searchText, options, false, 0));
4054 runPendingTasks();
4055 EXPECT_FALSE(client.findResultsAreReady());
4057 mainFrame->resetMatchCount();
4060 TEST_P(ParameterizedWebFrameTest, SetTickmarks)
4062 registerMockedHttpURLLoad("find.html");
4064 FindUpdateWebFrameClient client;
4065 FrameTestHelpers::WebViewHelper webViewHelper(this);
4066 webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client);
4067 webViewHelper.webView()->resize(WebSize(640, 480));
4068 webViewHelper.webView()->layout();
4069 runPendingTasks();
4071 static const char* kFindString = "foo";
4072 static const int kFindIdentifier = 12345;
4074 WebFindOptions options;
4075 WebString searchText = WebString::fromUTF8(kFindString);
4076 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4077 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
4079 mainFrame->resetMatchCount();
4080 mainFrame->scopeStringMatches(kFindIdentifier, searchText, options, true);
4082 runPendingTasks();
4083 EXPECT_TRUE(client.findResultsAreReady());
4085 // Get the tickmarks for the original find request.
4086 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
4087 RefPtrWillBeRawPtr<Scrollbar> scrollbar = frameView->createScrollbar(HorizontalScrollbar);
4088 Vector<IntRect> originalTickmarks;
4089 scrollbar->getTickmarks(originalTickmarks);
4090 EXPECT_EQ(4u, originalTickmarks.size());
4092 // Override the tickmarks.
4093 Vector<IntRect> overridingTickmarksExpected;
4094 overridingTickmarksExpected.append(IntRect(0, 0, 100, 100));
4095 overridingTickmarksExpected.append(IntRect(0, 20, 100, 100));
4096 overridingTickmarksExpected.append(IntRect(0, 30, 100, 100));
4097 mainFrame->setTickmarks(overridingTickmarksExpected);
4099 // Check the tickmarks are overriden correctly.
4100 Vector<IntRect> overridingTickmarksActual;
4101 scrollbar->getTickmarks(overridingTickmarksActual);
4102 EXPECT_EQ(overridingTickmarksExpected, overridingTickmarksActual);
4104 // Reset the tickmark behavior.
4105 Vector<IntRect> resetTickmarks;
4106 mainFrame->setTickmarks(resetTickmarks);
4108 // Check that the original tickmarks are returned
4109 Vector<IntRect> originalTickmarksAfterReset;
4110 scrollbar->getTickmarks(originalTickmarksAfterReset);
4111 EXPECT_EQ(originalTickmarks, originalTickmarksAfterReset);
4114 static WebPoint topLeft(const WebRect& rect)
4116 return WebPoint(rect.x, rect.y);
4119 static WebPoint bottomRightMinusOne(const WebRect& rect)
4121 // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
4122 // selection bounds, selectRange() will select the *next* element. That's
4123 // strictly correct, as hit-testing checks the pixel to the lower-right of
4124 // the input coordinate, but it's a wart on the API.
4125 return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1);
4128 static WebRect elementBounds(WebFrame* frame, const WebString& id)
4130 return frame->document().getElementById(id).boundsInViewportSpace();
4133 static std::string selectionAsString(WebFrame* frame)
4135 return frame->selectionAsText().utf8();
4138 TEST_P(ParameterizedWebFrameTest, SelectRange)
4140 WebFrame* frame;
4141 WebRect startWebRect;
4142 WebRect endWebRect;
4144 registerMockedHttpURLLoad("select_range_basic.html");
4145 registerMockedHttpURLLoad("select_range_scroll.html");
4147 FrameTestHelpers::WebViewHelper webViewHelper(this);
4148 initializeTextSelectionWebView(m_baseURL + "select_range_basic.html", &webViewHelper);
4149 frame = webViewHelper.webView()->mainFrame();
4150 EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
4151 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4152 frame->executeCommand(WebString::fromUTF8("Unselect"));
4153 EXPECT_EQ("", selectionAsString(frame));
4154 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
4155 EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
4157 initializeTextSelectionWebView(m_baseURL + "select_range_scroll.html", &webViewHelper);
4158 frame = webViewHelper.webView()->mainFrame();
4159 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
4160 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4161 frame->executeCommand(WebString::fromUTF8("Unselect"));
4162 EXPECT_EQ("", selectionAsString(frame));
4163 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
4164 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
4167 TEST_P(ParameterizedWebFrameTest, SelectRangeInIframe)
4169 WebFrame* frame;
4170 WebRect startWebRect;
4171 WebRect endWebRect;
4173 registerMockedHttpURLLoad("select_range_iframe.html");
4174 registerMockedHttpURLLoad("select_range_basic.html");
4176 FrameTestHelpers::WebViewHelper webViewHelper(this);
4177 initializeTextSelectionWebView(m_baseURL + "select_range_iframe.html", &webViewHelper);
4178 frame = webViewHelper.webView()->mainFrame();
4179 WebFrame* subframe = frame->firstChild();
4180 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
4181 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4182 subframe->executeCommand(WebString::fromUTF8("Unselect"));
4183 EXPECT_EQ("", selectionAsString(subframe));
4184 subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
4185 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
4188 TEST_P(ParameterizedWebFrameTest, SelectRangeDivContentEditable)
4190 WebFrame* frame;
4191 WebRect startWebRect;
4192 WebRect endWebRect;
4194 registerMockedHttpURLLoad("select_range_div_editable.html");
4196 // Select the middle of an editable element, then try to extend the selection to the top of the document.
4197 // The selection range should be clipped to the bounds of the editable element.
4198 FrameTestHelpers::WebViewHelper webViewHelper(this);
4199 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
4200 frame = webViewHelper.webView()->mainFrame();
4201 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4202 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4204 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
4205 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
4207 // As above, but extending the selection to the bottom of the document.
4208 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
4209 frame = webViewHelper.webView()->mainFrame();
4211 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4212 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
4213 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4214 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4216 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4217 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
4218 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
4221 // positionForPoint returns the wrong values for contenteditable spans. See
4222 // http://crbug.com/238334.
4223 TEST_P(ParameterizedWebFrameTest, DISABLED_SelectRangeSpanContentEditable)
4225 WebFrame* frame;
4226 WebRect startWebRect;
4227 WebRect endWebRect;
4229 registerMockedHttpURLLoad("select_range_span_editable.html");
4231 // Select the middle of an editable element, then try to extend the selection to the top of the document.
4232 // The selection range should be clipped to the bounds of the editable element.
4233 FrameTestHelpers::WebViewHelper webViewHelper(this);
4234 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
4235 frame = webViewHelper.webView()->mainFrame();
4236 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4237 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4239 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
4240 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
4242 // As above, but extending the selection to the bottom of the document.
4243 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
4244 frame = webViewHelper.webView()->mainFrame();
4246 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4247 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
4248 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4249 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4251 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4252 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4253 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
4254 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
4257 TEST_P(ParameterizedWebFrameTest, SelectRangeCanMoveSelectionStart)
4259 registerMockedHttpURLLoad("text_selection.html");
4260 FrameTestHelpers::WebViewHelper webViewHelper(this);
4261 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
4262 WebFrame* frame = webViewHelper.webView()->mainFrame();
4264 // Select second span. We can move the start to include the first span.
4265 frame->executeScript(WebScriptSource("selectElement('header_2');"));
4266 EXPECT_EQ("Header 2.", selectionAsString(frame));
4267 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
4268 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
4270 // We can move the start and end together.
4271 frame->executeScript(WebScriptSource("selectElement('header_1');"));
4272 EXPECT_EQ("Header 1.", selectionAsString(frame));
4273 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1")));
4274 EXPECT_EQ("", selectionAsString(frame));
4275 // Selection is a caret, not empty.
4276 EXPECT_FALSE(frame->selectionRange().isNull());
4278 // We can move the start across the end.
4279 frame->executeScript(WebScriptSource("selectElement('header_1');"));
4280 EXPECT_EQ("Header 1.", selectionAsString(frame));
4281 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
4282 EXPECT_EQ(" Header 2.", selectionAsString(frame));
4284 // Can't extend the selection part-way into an editable element.
4285 frame->executeScript(WebScriptSource("selectElement('footer_2');"));
4286 EXPECT_EQ("Footer 2.", selectionAsString(frame));
4287 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2")));
4288 EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame));
4290 // Can extend the selection completely across editable elements.
4291 frame->executeScript(WebScriptSource("selectElement('footer_2');"));
4292 EXPECT_EQ("Footer 2.", selectionAsString(frame));
4293 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2")));
4294 EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame));
4296 // If the selection is editable text, we can't extend it into non-editable text.
4297 frame->executeScript(WebScriptSource("selectElement('editable_2');"));
4298 EXPECT_EQ("Editable 2.", selectionAsString(frame));
4299 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2")));
4300 // positionForPoint returns the wrong values for contenteditable spans. See
4301 // http://crbug.com/238334.
4302 // EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame));
4305 TEST_P(ParameterizedWebFrameTest, SelectRangeCanMoveSelectionEnd)
4307 registerMockedHttpURLLoad("text_selection.html");
4308 FrameTestHelpers::WebViewHelper webViewHelper(this);
4309 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
4310 WebFrame* frame = webViewHelper.webView()->mainFrame();
4312 // Select first span. We can move the end to include the second span.
4313 frame->executeScript(WebScriptSource("selectElement('header_1');"));
4314 EXPECT_EQ("Header 1.", selectionAsString(frame));
4315 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
4316 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
4318 // We can move the start and end together.
4319 frame->executeScript(WebScriptSource("selectElement('header_2');"));
4320 EXPECT_EQ("Header 2.", selectionAsString(frame));
4321 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2")));
4322 EXPECT_EQ("", selectionAsString(frame));
4323 // Selection is a caret, not empty.
4324 EXPECT_FALSE(frame->selectionRange().isNull());
4326 // We can move the end across the start.
4327 frame->executeScript(WebScriptSource("selectElement('header_2');"));
4328 EXPECT_EQ("Header 2.", selectionAsString(frame));
4329 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
4330 EXPECT_EQ("Header 1. ", selectionAsString(frame));
4332 // Can't extend the selection part-way into an editable element.
4333 frame->executeScript(WebScriptSource("selectElement('header_1');"));
4334 EXPECT_EQ("Header 1.", selectionAsString(frame));
4335 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1")));
4336 EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame));
4338 // Can extend the selection completely across editable elements.
4339 frame->executeScript(WebScriptSource("selectElement('header_1');"));
4340 EXPECT_EQ("Header 1.", selectionAsString(frame));
4341 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
4342 EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame));
4344 // If the selection is editable text, we can't extend it into non-editable text.
4345 frame->executeScript(WebScriptSource("selectElement('editable_1');"));
4346 EXPECT_EQ("Editable 1.", selectionAsString(frame));
4347 frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
4348 // positionForPoint returns the wrong values for contenteditable spans. See
4349 // http://crbug.com/238334.
4350 // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
4353 TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtent)
4355 WebLocalFrameImpl* frame;
4356 WebRect startWebRect;
4357 WebRect endWebRect;
4359 registerMockedHttpURLLoad("move_range_selection_extent.html");
4361 FrameTestHelpers::WebViewHelper webViewHelper(this);
4362 initializeTextSelectionWebView(m_baseURL + "move_range_selection_extent.html", &webViewHelper);
4363 frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4364 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4365 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4367 frame->moveRangeSelectionExtent(WebPoint(640, 480));
4368 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
4370 frame->moveRangeSelectionExtent(WebPoint(0, 0));
4371 EXPECT_EQ("16-char header. ", selectionAsString(frame));
4373 // Reset with swapped base and extent.
4374 frame->selectRange(topLeft(endWebRect), bottomRightMinusOne(startWebRect));
4375 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4377 frame->moveRangeSelectionExtent(WebPoint(640, 480));
4378 EXPECT_EQ(" 16-char footer.", selectionAsString(frame));
4380 frame->moveRangeSelectionExtent(WebPoint(0, 0));
4381 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
4383 frame->executeCommand(WebString::fromUTF8("Unselect"));
4384 EXPECT_EQ("", selectionAsString(frame));
4387 TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtentCannotCollapse)
4389 WebLocalFrameImpl* frame;
4390 WebRect startWebRect;
4391 WebRect endWebRect;
4393 registerMockedHttpURLLoad("move_range_selection_extent.html");
4395 FrameTestHelpers::WebViewHelper webViewHelper(this);
4396 initializeTextSelectionWebView(m_baseURL + "move_range_selection_extent.html", &webViewHelper);
4397 frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4398 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4399 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4401 frame->moveRangeSelectionExtent(bottomRightMinusOne(startWebRect));
4402 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4404 // Reset with swapped base and extent.
4405 frame->selectRange(topLeft(endWebRect), bottomRightMinusOne(startWebRect));
4406 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4408 frame->moveRangeSelectionExtent(bottomRightMinusOne(endWebRect));
4409 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
4412 TEST_P(ParameterizedWebFrameTest, MoveRangeSelectionExtentScollsInputField)
4414 WebLocalFrameImpl* frame;
4415 WebRect startWebRect;
4416 WebRect endWebRect;
4418 registerMockedHttpURLLoad("move_range_selection_extent_input_field.html");
4420 FrameTestHelpers::WebViewHelper webViewHelper(this);
4421 initializeTextSelectionWebView(m_baseURL + "move_range_selection_extent_input_field.html", &webViewHelper);
4422 frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4423 EXPECT_EQ("Length", selectionAsString(frame));
4424 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
4426 EXPECT_EQ(0, frame->frame()->selection().rootEditableElement()->scrollLeft());
4427 frame->moveRangeSelectionExtent(WebPoint(endWebRect.x + 500, endWebRect.y));
4428 EXPECT_GE(frame->frame()->selection().rootEditableElement()->scrollLeft(), 1);
4429 EXPECT_EQ("Lengthy text goes here.", selectionAsString(frame));
4432 static int computeOffset(LayoutObject* layoutObject, int x, int y)
4434 return createVisiblePosition(layoutObject->positionForPoint(LayoutPoint(x, y))).deepEquivalent().computeOffsetInContainerNode();
4437 // positionForPoint returns the wrong values for contenteditable spans. See
4438 // http://crbug.com/238334.
4439 TEST_P(ParameterizedWebFrameTest, DISABLED_PositionForPointTest)
4441 registerMockedHttpURLLoad("select_range_span_editable.html");
4442 FrameTestHelpers::WebViewHelper webViewHelper(this);
4443 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
4444 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4445 LayoutObject* layoutObject = mainFrame->frame()->selection().rootEditableElement()->layoutObject();
4446 EXPECT_EQ(0, computeOffset(layoutObject, -1, -1));
4447 EXPECT_EQ(64, computeOffset(layoutObject, 1000, 1000));
4449 registerMockedHttpURLLoad("select_range_div_editable.html");
4450 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
4451 mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4452 layoutObject = mainFrame->frame()->selection().rootEditableElement()->layoutObject();
4453 EXPECT_EQ(0, computeOffset(layoutObject, -1, -1));
4454 EXPECT_EQ(64, computeOffset(layoutObject, 1000, 1000));
4457 #if !OS(MACOSX) && !OS(LINUX)
4458 TEST_P(ParameterizedWebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved)
4460 registerMockedHttpURLLoad("move_caret.html");
4462 FrameTestHelpers::WebViewHelper webViewHelper(this);
4463 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
4464 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4466 WebRect initialStartRect;
4467 WebRect initialEndRect;
4468 WebRect startRect;
4469 WebRect endRect;
4471 frame->executeScript(WebScriptSource("selectRange();"));
4472 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
4473 WebPoint movedStart(topLeft(initialStartRect));
4475 movedStart.y += 40;
4476 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
4477 webViewHelper.webView()->selectionBounds(startRect, endRect);
4478 EXPECT_EQ(startRect, initialStartRect);
4479 EXPECT_EQ(endRect, initialEndRect);
4481 movedStart.y -= 80;
4482 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
4483 webViewHelper.webView()->selectionBounds(startRect, endRect);
4484 EXPECT_EQ(startRect, initialStartRect);
4485 EXPECT_EQ(endRect, initialEndRect);
4487 WebPoint movedEnd(bottomRightMinusOne(initialEndRect));
4489 movedEnd.y += 40;
4490 frame->selectRange(topLeft(initialStartRect), movedEnd);
4491 webViewHelper.webView()->selectionBounds(startRect, endRect);
4492 EXPECT_EQ(startRect, initialStartRect);
4493 EXPECT_EQ(endRect, initialEndRect);
4495 movedEnd.y -= 80;
4496 frame->selectRange(topLeft(initialStartRect), movedEnd);
4497 webViewHelper.webView()->selectionBounds(startRect, endRect);
4498 EXPECT_EQ(startRect, initialStartRect);
4499 EXPECT_EQ(endRect, initialEndRect);
4502 TEST_P(ParameterizedWebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved)
4504 WebLocalFrameImpl* frame;
4505 registerMockedHttpURLLoad("move_caret.html");
4507 FrameTestHelpers::WebViewHelper webViewHelper(this);
4508 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
4509 frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
4511 WebRect initialStartRect;
4512 WebRect initialEndRect;
4513 WebRect startRect;
4514 WebRect endRect;
4516 frame->executeScript(WebScriptSource("selectCaret();"));
4517 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
4518 WebPoint moveTo(topLeft(initialStartRect));
4520 moveTo.y += 40;
4521 frame->moveCaretSelection(moveTo);
4522 webViewHelper.webView()->selectionBounds(startRect, endRect);
4523 EXPECT_EQ(startRect, initialStartRect);
4524 EXPECT_EQ(endRect, initialEndRect);
4526 moveTo.y -= 80;
4527 frame->moveCaretSelection(moveTo);
4528 webViewHelper.webView()->selectionBounds(startRect, endRect);
4529 EXPECT_EQ(startRect, initialStartRect);
4530 EXPECT_EQ(endRect, initialEndRect);
4532 #endif
4534 class CompositedSelectionBoundsTestLayerTreeView : public WebLayerTreeView {
4535 public:
4536 CompositedSelectionBoundsTestLayerTreeView() : m_selectionCleared(false) { }
4537 ~CompositedSelectionBoundsTestLayerTreeView() override { }
4539 void registerSelection(const WebSelection& selection) override
4541 m_selection = adoptPtr(new WebSelection(selection));
4544 void clearSelection() override
4546 m_selectionCleared = true;
4547 m_selection.clear();
4550 bool getAndResetSelectionCleared()
4552 bool selectionCleared = m_selectionCleared;
4553 m_selectionCleared = false;
4554 return selectionCleared;
4557 const WebSelection* selection() const { return m_selection.get(); }
4558 const WebSelectionBound* start() const { return m_selection ? &m_selection->start() : nullptr; }
4559 const WebSelectionBound* end() const { return m_selection ? &m_selection->end() : nullptr; }
4561 private:
4562 bool m_selectionCleared;
4563 OwnPtr<WebSelection> m_selection;
4566 class CompositedSelectionBoundsTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
4567 public:
4568 ~CompositedSelectionBoundsTestWebViewClient() override {}
4569 WebLayerTreeView* layerTreeView() override { return &m_testLayerTreeView; }
4571 CompositedSelectionBoundsTestLayerTreeView& selectionLayerTreeView() { return m_testLayerTreeView; }
4573 private:
4574 CompositedSelectionBoundsTestLayerTreeView m_testLayerTreeView;
4577 class CompositedSelectionBoundsTest : public WebFrameTest {
4578 protected:
4579 CompositedSelectionBoundsTest()
4580 : m_fakeSelectionLayerTreeView(m_fakeSelectionWebViewClient.selectionLayerTreeView())
4582 RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
4583 registerMockedHttpURLLoad("Ahem.ttf");
4585 m_webViewHelper.initialize(true, 0, &m_fakeSelectionWebViewClient);
4586 m_webViewHelper.webView()->settings()->setDefaultFontSize(12);
4587 m_webViewHelper.webView()->setDefaultPageScaleLimits(1, 1);
4588 m_webViewHelper.webView()->resize(WebSize(640, 480));
4591 void runTest(const char* testFile)
4593 registerMockedHttpURLLoad(testFile);
4594 FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), m_baseURL + testFile);
4595 m_webViewHelper.webView()->layout();
4597 const WebSelection* selection = m_fakeSelectionLayerTreeView.selection();
4598 const WebSelectionBound* selectStart = m_fakeSelectionLayerTreeView.start();
4599 const WebSelectionBound* selectEnd = m_fakeSelectionLayerTreeView.end();
4601 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
4602 v8::Local<v8::Value> result = m_webViewHelper.webView()->mainFrame()->toWebLocalFrame()->executeScriptAndReturnValue(WebScriptSource("expectedResult"));
4603 if (result.IsEmpty() || (*result)->IsUndefined()) {
4604 EXPECT_FALSE(selection);
4605 EXPECT_FALSE(selectStart);
4606 EXPECT_FALSE(selectEnd);
4607 return;
4610 ASSERT_TRUE(selection);
4611 ASSERT_TRUE(selectStart);
4612 ASSERT_TRUE(selectEnd);
4614 EXPECT_FALSE(selection->isNone());
4616 ASSERT_TRUE((*result)->IsArray());
4617 v8::Array& expectedResult = *v8::Array::Cast(*result);
4618 ASSERT_GE(expectedResult.Length(), 10u);
4620 blink::Node* layerOwnerNodeForStart = V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(0));
4621 ASSERT_TRUE(layerOwnerNodeForStart);
4622 EXPECT_EQ(layerOwnerNodeForStart->layoutObject()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectStart->layerId);
4623 v8::Local<v8::Context> context = v8::Isolate::GetCurrent()->GetCurrentContext();
4624 EXPECT_EQ(expectedResult.Get(context, 1).ToLocalChecked().As<v8::Int32>()->Value(), selectStart->edgeTopInLayer.x);
4625 EXPECT_EQ(expectedResult.Get(context, 2).ToLocalChecked().As<v8::Int32>()->Value(), selectStart->edgeTopInLayer.y);
4626 EXPECT_EQ(expectedResult.Get(context, 3).ToLocalChecked().As<v8::Int32>()->Value(), selectStart->edgeBottomInLayer.x);
4628 blink::Node* layerOwnerNodeForEnd = V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(context, 5).ToLocalChecked());
4630 ASSERT_TRUE(layerOwnerNodeForEnd);
4631 EXPECT_EQ(layerOwnerNodeForEnd->layoutObject()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectEnd->layerId);
4632 EXPECT_EQ(expectedResult.Get(context, 6).ToLocalChecked().As<v8::Int32>()->Value(), selectEnd->edgeTopInLayer.x);
4633 EXPECT_EQ(expectedResult.Get(context, 7).ToLocalChecked().As<v8::Int32>()->Value(), selectEnd->edgeTopInLayer.y);
4634 EXPECT_EQ(expectedResult.Get(context, 8).ToLocalChecked().As<v8::Int32>()->Value(), selectEnd->edgeBottomInLayer.x);
4636 // Platform differences can introduce small stylistic deviations in
4637 // y-axis positioning, the details of which aren't relevant to
4638 // selection behavior. However, such deviations from the expected value
4639 // should be consistent for the corresponding y coordinates.
4640 int yBottomEpsilon = 0;
4641 if (expectedResult.Length() == 13)
4642 yBottomEpsilon = expectedResult.Get(context, 12).ToLocalChecked().As<v8::Int32>()->Value();
4643 int yBottomDeviation = expectedResult.Get(context, 4).ToLocalChecked().As<v8::Int32>()->Value() - selectStart->edgeBottomInLayer.y;
4644 EXPECT_GE(yBottomEpsilon, std::abs(yBottomDeviation));
4645 EXPECT_EQ(yBottomDeviation, expectedResult.Get(context, 9).ToLocalChecked().As<v8::Int32>()->Value() - selectEnd->edgeBottomInLayer.y);
4647 if (expectedResult.Length() >= 12) {
4648 EXPECT_EQ(expectedResult.Get(context, 10).ToLocalChecked().As<v8::Boolean>()->Value(), m_fakeSelectionLayerTreeView.selection()->isEditable());
4649 EXPECT_EQ(expectedResult.Get(context, 11).ToLocalChecked().As<v8::Boolean>()->Value(), m_fakeSelectionLayerTreeView.selection()->isEmptyTextFormControl());
4653 void runTestWithMultipleFiles(const char* testFile, ...)
4655 va_list auxFiles;
4656 va_start(auxFiles, testFile);
4657 while (const char* auxFile = va_arg(auxFiles, const char*))
4658 registerMockedHttpURLLoad(auxFile);
4659 va_end(auxFiles);
4661 runTest(testFile);
4664 CompositedSelectionBoundsTestWebViewClient m_fakeSelectionWebViewClient;
4665 CompositedSelectionBoundsTestLayerTreeView& m_fakeSelectionLayerTreeView;
4666 FrameTestHelpers::WebViewHelper m_webViewHelper;
4669 TEST_F(CompositedSelectionBoundsTest, None) { runTest("composited_selection_bounds_none.html"); }
4670 TEST_F(CompositedSelectionBoundsTest, NoneReadonlyCaret) { runTest("composited_selection_bounds_none_readonly_caret.html"); }
4671 TEST_F(CompositedSelectionBoundsTest, Basic) { runTest("composited_selection_bounds_basic.html"); }
4672 TEST_F(CompositedSelectionBoundsTest, Transformed) { runTest("composited_selection_bounds_transformed.html"); }
4673 TEST_F(CompositedSelectionBoundsTest, SplitLayer) { runTest("composited_selection_bounds_split_layer.html"); }
4674 TEST_F(CompositedSelectionBoundsTest, EmptyLayer) { runTest("composited_selection_bounds_empty_layer.html"); }
4675 TEST_F(CompositedSelectionBoundsTest, Iframe) { runTestWithMultipleFiles("composited_selection_bounds_iframe.html", "composited_selection_bounds_basic.html", nullptr); }
4676 TEST_F(CompositedSelectionBoundsTest, DetachedFrame) { runTest("composited_selection_bounds_detached_frame.html"); }
4677 TEST_F(CompositedSelectionBoundsTest, Editable) { runTest("composited_selection_bounds_editable.html"); }
4678 TEST_F(CompositedSelectionBoundsTest, EditableDiv) { runTest("composited_selection_bounds_editable_div.html"); }
4679 TEST_F(CompositedSelectionBoundsTest, EmptyEditableInput) { runTest("composited_selection_bounds_empty_editable_input.html"); }
4680 TEST_F(CompositedSelectionBoundsTest, EmptyEditableArea) { runTest("composited_selection_bounds_empty_editable_area.html"); }
4682 TEST_P(ParameterizedWebFrameTest, CompositedSelectionBoundsCleared)
4684 RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
4686 registerMockedHttpURLLoad("select_range_basic.html");
4687 registerMockedHttpURLLoad("select_range_scroll.html");
4689 int viewWidth = 500;
4690 int viewHeight = 500;
4692 CompositedSelectionBoundsTestWebViewClient fakeSelectionWebViewClient;
4693 CompositedSelectionBoundsTestLayerTreeView& fakeSelectionLayerTreeView = fakeSelectionWebViewClient.selectionLayerTreeView();
4695 FrameTestHelpers::WebViewHelper webViewHelper(this);
4696 webViewHelper.initialize(true, 0, &fakeSelectionWebViewClient);
4697 webViewHelper.webView()->settings()->setDefaultFontSize(12);
4698 webViewHelper.webView()->setDefaultPageScaleLimits(1, 1);
4699 webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
4700 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_basic.html");
4702 // The frame starts with a non-empty selection.
4703 WebFrame* frame = webViewHelper.webView()->mainFrame();
4704 ASSERT_TRUE(frame->hasSelection());
4705 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4707 // The selection cleared notification should be triggered upon layout.
4708 frame->executeCommand(WebString::fromUTF8("Unselect"));
4709 ASSERT_FALSE(frame->hasSelection());
4710 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4711 webViewHelper.webView()->layout();
4712 EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4714 frame->executeCommand(WebString::fromUTF8("SelectAll"));
4715 webViewHelper.webView()->layout();
4716 ASSERT_TRUE(frame->hasSelection());
4717 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4719 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_scroll.html");
4720 ASSERT_TRUE(frame->hasSelection());
4721 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4723 // Transitions between non-empty selections should not trigger a clearing.
4724 WebRect startWebRect;
4725 WebRect endWebRect;
4726 webViewHelper.webViewImpl()->selectionBounds(startWebRect, endWebRect);
4727 WebPoint movedEnd(bottomRightMinusOne(endWebRect));
4728 endWebRect.x -= 20;
4729 frame->selectRange(topLeft(startWebRect), movedEnd);
4730 webViewHelper.webView()->layout();
4731 ASSERT_TRUE(frame->hasSelection());
4732 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4734 frame = webViewHelper.webView()->mainFrame();
4735 frame->executeCommand(WebString::fromUTF8("Unselect"));
4736 webViewHelper.webView()->layout();
4737 ASSERT_FALSE(frame->hasSelection());
4738 EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4741 class DisambiguationPopupTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
4742 public:
4743 bool didTapMultipleTargets(const WebSize&, const WebRect&, const WebVector<WebRect>& targetRects) override
4745 EXPECT_GE(targetRects.size(), 2u);
4746 m_triggered = true;
4747 return true;
4750 bool triggered() const { return m_triggered; }
4751 void resetTriggered() { m_triggered = false; }
4752 bool m_triggered;
4755 static WebGestureEvent fatTap(int x, int y)
4757 WebGestureEvent event;
4758 event.type = WebInputEvent::GestureTap;
4759 event.x = x;
4760 event.y = y;
4761 event.data.tap.width = 50;
4762 event.data.tap.height = 50;
4763 return event;
4766 TEST_P(ParameterizedWebFrameTest, DisambiguationPopup)
4768 const std::string htmlFile = "disambiguation_popup.html";
4769 registerMockedHttpURLLoad(htmlFile);
4771 DisambiguationPopupTestWebViewClient client;
4773 // Make sure we initialize to minimum scale, even if the window size
4774 // only becomes available after the load begins.
4775 FrameTestHelpers::WebViewHelper webViewHelper(this);
4776 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4777 webViewHelper.webView()->resize(WebSize(1000, 1000));
4778 webViewHelper.webView()->layout();
4780 client.resetTriggered();
4781 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4782 EXPECT_FALSE(client.triggered());
4784 client.resetTriggered();
4785 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4786 EXPECT_FALSE(client.triggered());
4788 for (int i = 0; i <= 46; i++) {
4789 client.resetTriggered();
4790 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4792 int j = i % 10;
4793 if (j >= 7 && j <= 9)
4794 EXPECT_TRUE(client.triggered());
4795 else
4796 EXPECT_FALSE(client.triggered());
4799 for (int i = 0; i <= 46; i++) {
4800 client.resetTriggered();
4801 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4803 int j = i % 10;
4804 if (j >= 7 && j <= 9)
4805 EXPECT_TRUE(client.triggered());
4806 else
4807 EXPECT_FALSE(client.triggered());
4810 // The same taps shouldn't trigger didTapMultipleTargets() after disabling the notification for
4811 // multi-target-tap.
4812 webViewHelper.webView()->settings()->setMultiTargetTapNotificationEnabled(false);
4814 for (int i = 0; i <= 46; i++) {
4815 client.resetTriggered();
4816 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4817 EXPECT_FALSE(client.triggered());
4821 TEST_P(ParameterizedWebFrameTest, DisambiguationPopupNoContainer)
4823 registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
4825 DisambiguationPopupTestWebViewClient client;
4827 // Make sure we initialize to minimum scale, even if the window size
4828 // only becomes available after the load begins.
4829 FrameTestHelpers::WebViewHelper webViewHelper(this);
4830 webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_no_container.html", true, 0, &client);
4831 webViewHelper.webView()->resize(WebSize(1000, 1000));
4832 webViewHelper.webView()->layout();
4834 client.resetTriggered();
4835 webViewHelper.webView()->handleInputEvent(fatTap(50, 50));
4836 EXPECT_FALSE(client.triggered());
4839 TEST_P(ParameterizedWebFrameTest, DisambiguationPopupMobileSite)
4841 UseMockScrollbarSettings mockScrollbarSettings;
4842 const std::string htmlFile = "disambiguation_popup_mobile_site.html";
4843 registerMockedHttpURLLoad(htmlFile);
4845 DisambiguationPopupTestWebViewClient client;
4847 // Make sure we initialize to minimum scale, even if the window size
4848 // only becomes available after the load begins.
4849 FrameTestHelpers::WebViewHelper webViewHelper(this);
4850 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4851 webViewHelper.webView()->resize(WebSize(1000, 1000));
4852 webViewHelper.webView()->layout();
4854 client.resetTriggered();
4855 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4856 EXPECT_FALSE(client.triggered());
4858 client.resetTriggered();
4859 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4860 EXPECT_FALSE(client.triggered());
4862 for (int i = 0; i <= 46; i++) {
4863 client.resetTriggered();
4864 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4865 EXPECT_FALSE(client.triggered());
4868 for (int i = 0; i <= 46; i++) {
4869 client.resetTriggered();
4870 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4871 EXPECT_FALSE(client.triggered());
4875 TEST_P(ParameterizedWebFrameTest, DisambiguationPopupViewportSite)
4877 UseMockScrollbarSettings mockScrollbarSettings;
4878 const std::string htmlFile = "disambiguation_popup_viewport_site.html";
4879 registerMockedHttpURLLoad(htmlFile);
4881 DisambiguationPopupTestWebViewClient client;
4883 // Make sure we initialize to minimum scale, even if the window size
4884 // only becomes available after the load begins.
4885 FrameTestHelpers::WebViewHelper webViewHelper(this);
4886 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4887 webViewHelper.webView()->resize(WebSize(1000, 1000));
4888 webViewHelper.webView()->layout();
4890 client.resetTriggered();
4891 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4892 EXPECT_FALSE(client.triggered());
4894 client.resetTriggered();
4895 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4896 EXPECT_FALSE(client.triggered());
4898 for (int i = 0; i <= 46; i++) {
4899 client.resetTriggered();
4900 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4901 EXPECT_FALSE(client.triggered());
4904 for (int i = 0; i <= 46; i++) {
4905 client.resetTriggered();
4906 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4907 EXPECT_FALSE(client.triggered());
4911 TEST_F(WebFrameTest, DisambiguationPopupVisualViewport)
4913 UseMockScrollbarSettings mockScrollbarSettings;
4914 const std::string htmlFile = "disambiguation_popup_200_by_800.html";
4915 registerMockedHttpURLLoad(htmlFile);
4917 DisambiguationPopupTestWebViewClient client;
4919 FrameTestHelpers::WebViewHelper webViewHelper;
4920 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, configureAndroid);
4922 WebViewImpl* webViewImpl = webViewHelper.webViewImpl();
4923 ASSERT_TRUE(webViewImpl);
4924 LocalFrame* frame = webViewImpl->mainFrameImpl()->frame();
4925 ASSERT_TRUE(frame);
4927 webViewHelper.webView()->resize(WebSize(100, 200));
4929 // Scroll main frame to the bottom of the document
4930 webViewImpl->mainFrame()->setScrollOffset(WebSize(0, 400));
4931 EXPECT_POINT_EQ(IntPoint(0, 400), frame->view()->scrollPosition());
4933 webViewImpl->setPageScaleFactor(2.0);
4935 // Scroll visual viewport to the top of the main frame.
4936 VisualViewport& visualViewport = frame->page()->frameHost().visualViewport();
4937 visualViewport.setLocation(FloatPoint(0, 0));
4938 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), visualViewport.location());
4940 // Tap at the top: there is nothing there.
4941 client.resetTriggered();
4942 webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4943 EXPECT_FALSE(client.triggered());
4945 // Scroll visual viewport to the bottom of the main frame.
4946 visualViewport.setLocation(FloatPoint(0, 200));
4947 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 200), visualViewport.location());
4949 // Now the tap with the same coordinates should hit two elements.
4950 client.resetTriggered();
4951 webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4952 EXPECT_TRUE(client.triggered());
4954 // The same tap shouldn't trigger didTapMultipleTargets() after disabling the notification for
4955 // multi-target-tap.
4956 webViewHelper.webView()->settings()->setMultiTargetTapNotificationEnabled(false);
4957 client.resetTriggered();
4958 webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4959 EXPECT_FALSE(client.triggered());
4962 TEST_P(ParameterizedWebFrameTest, DisambiguationPopupBlacklist)
4964 const unsigned viewportWidth = 500;
4965 const unsigned viewportHeight = 1000;
4966 const unsigned divHeight = 100;
4967 const std::string htmlFile = "disambiguation_popup_blacklist.html";
4968 registerMockedHttpURLLoad(htmlFile);
4970 DisambiguationPopupTestWebViewClient client;
4972 // Make sure we initialize to minimum scale, even if the window size
4973 // only becomes available after the load begins.
4974 FrameTestHelpers::WebViewHelper webViewHelper(this);
4975 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4976 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
4977 webViewHelper.webView()->layout();
4979 // Click somewhere where the popup shouldn't appear.
4980 client.resetTriggered();
4981 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, 0));
4982 EXPECT_FALSE(client.triggered());
4984 // Click directly in between two container divs with click handlers, with children that don't handle clicks.
4985 client.resetTriggered();
4986 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight));
4987 EXPECT_TRUE(client.triggered());
4989 // The third div container should be blacklisted if you click on the link it contains.
4990 client.resetTriggered();
4991 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight * 3.25));
4992 EXPECT_FALSE(client.triggered());
4995 TEST_P(ParameterizedWebFrameTest, DisambiguationPopupPageScale)
4997 registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
4999 DisambiguationPopupTestWebViewClient client;
5001 // Make sure we initialize to minimum scale, even if the window size
5002 // only becomes available after the load begins.
5003 FrameTestHelpers::WebViewHelper webViewHelper(this);
5004 webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_page_scale.html", true, 0, &client);
5005 webViewHelper.webView()->resize(WebSize(1000, 1000));
5006 webViewHelper.webView()->layout();
5008 client.resetTriggered();
5009 webViewHelper.webView()->handleInputEvent(fatTap(80, 80));
5010 EXPECT_TRUE(client.triggered());
5012 client.resetTriggered();
5013 webViewHelper.webView()->handleInputEvent(fatTap(230, 190));
5014 EXPECT_TRUE(client.triggered());
5016 webViewHelper.webView()->setPageScaleFactor(3.0f);
5017 webViewHelper.webView()->layout();
5019 client.resetTriggered();
5020 webViewHelper.webView()->handleInputEvent(fatTap(240, 240));
5021 EXPECT_TRUE(client.triggered());
5023 client.resetTriggered();
5024 webViewHelper.webView()->handleInputEvent(fatTap(690, 570));
5025 EXPECT_FALSE(client.triggered());
5028 class TestSubstituteDataWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5029 public:
5030 TestSubstituteDataWebFrameClient()
5031 : m_commitCalled(false)
5035 virtual void didFailProvisionalLoad(WebLocalFrame* frame, const WebURLError& error, WebHistoryCommitType)
5037 frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true);
5040 virtual void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType)
5042 if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank")))
5043 m_commitCalled = true;
5046 bool commitCalled() const { return m_commitCalled; }
5048 private:
5049 bool m_commitCalled;
5052 TEST_P(ParameterizedWebFrameTest, ReplaceNavigationAfterHistoryNavigation)
5054 TestSubstituteDataWebFrameClient webFrameClient;
5056 FrameTestHelpers::WebViewHelper webViewHelper(this);
5057 webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
5058 WebFrame* frame = webViewHelper.webView()->mainFrame();
5060 // Load a url as a history navigation that will return an error. TestSubstituteDataWebFrameClient
5061 // will start a SubstituteData load in response to the load failure, which should get fully committed.
5062 // Due to https://bugs.webkit.org/show_bug.cgi?id=91685, FrameLoader::didReceiveData() wasn't getting
5063 // called in this case, which resulted in the SubstituteData document not getting displayed.
5064 WebURLError error;
5065 error.reason = 1337;
5066 error.domain = "WebFrameTest";
5067 std::string errorURL = "http://0.0.0.0";
5068 WebURLResponse response;
5069 response.initialize();
5070 response.setURL(URLTestHelpers::toKURL(errorURL));
5071 response.setMIMEType("text/html");
5072 response.setHTTPStatusCode(500);
5073 WebHistoryItem errorHistoryItem;
5074 errorHistoryItem.initialize();
5075 errorHistoryItem.setURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
5076 Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
5077 FrameTestHelpers::loadHistoryItem(frame, errorHistoryItem, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5079 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
5080 EXPECT_EQ("This should appear", text.utf8());
5081 EXPECT_TRUE(webFrameClient.commitCalled());
5084 class TestWillInsertBodyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5085 public:
5086 TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false)
5090 void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) override
5092 m_numBodies = 0;
5093 m_didLoad = true;
5096 void didCreateDocumentElement(WebLocalFrame*) override
5098 EXPECT_EQ(0, m_numBodies);
5101 void willInsertBody(WebLocalFrame*) override
5103 m_numBodies++;
5106 int m_numBodies;
5107 bool m_didLoad;
5110 TEST_P(ParameterizedWebFrameTest, HTMLDocument)
5112 registerMockedHttpURLLoad("clipped-body.html");
5114 TestWillInsertBodyWebFrameClient webFrameClient;
5115 FrameTestHelpers::WebViewHelper webViewHelper(this);
5116 webViewHelper.initializeAndLoad(m_baseURL + "clipped-body.html", false, &webFrameClient);
5118 EXPECT_TRUE(webFrameClient.m_didLoad);
5119 EXPECT_EQ(1, webFrameClient.m_numBodies);
5122 TEST_P(ParameterizedWebFrameTest, EmptyDocument)
5124 registerMockedHttpURLLoad("pageserializer/svg/green_rectangle.svg");
5126 TestWillInsertBodyWebFrameClient webFrameClient;
5127 FrameTestHelpers::WebViewHelper webViewHelper(this);
5128 webViewHelper.initialize(false, &webFrameClient);
5130 EXPECT_FALSE(webFrameClient.m_didLoad);
5131 EXPECT_EQ(1, webFrameClient.m_numBodies); // The empty document that a new frame starts with triggers this.
5134 TEST_P(ParameterizedWebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection)
5136 FrameTestHelpers::WebViewHelper webViewHelper(this);
5137 webViewHelper.initializeAndLoad("about:blank", true);
5138 WebFrame* frame = webViewHelper.webView()->mainFrame();
5140 // This test passes if this doesn't crash.
5141 frame->moveCaretSelection(WebPoint(0, 0));
5144 class SpellCheckClient : public WebSpellCheckClient {
5145 public:
5146 explicit SpellCheckClient(uint32_t hash = 0) : m_numberOfTimesChecked(0), m_hash(hash) { }
5147 virtual ~SpellCheckClient() { }
5148 void requestCheckingOfText(const WebString&, const WebVector<uint32_t>&, const WebVector<unsigned>&, WebTextCheckingCompletion* completion) override
5150 ++m_numberOfTimesChecked;
5151 Vector<WebTextCheckingResult> results;
5152 const int misspellingStartOffset = 1;
5153 const int misspellingLength = 8;
5154 results.append(WebTextCheckingResult(WebTextDecorationTypeSpelling, misspellingStartOffset, misspellingLength, WebString(), m_hash));
5155 completion->didFinishCheckingText(results);
5157 int numberOfTimesChecked() const { return m_numberOfTimesChecked; }
5158 private:
5159 int m_numberOfTimesChecked;
5160 uint32_t m_hash;
5163 TEST_P(ParameterizedWebFrameTest, ReplaceMisspelledRange)
5165 registerMockedHttpURLLoad("spell.html");
5166 FrameTestHelpers::WebViewHelper webViewHelper(this);
5167 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5168 SpellCheckClient spellcheck;
5169 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5171 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5172 Document* document = frame->frame()->document();
5173 Element* element = document->getElementById("data");
5175 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5176 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5177 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5179 element->focus();
5180 NonThrowableExceptionState exceptionState;
5181 document->execCommand("InsertText", false, "_wellcome_.", exceptionState);
5182 EXPECT_FALSE(exceptionState.hadException());
5184 const int allTextBeginOffset = 0;
5185 const int allTextLength = 11;
5186 frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
5187 EphemeralRange selectionRange = frame->frame()->selection().selection().toNormalizedEphemeralRange();
5189 EXPECT_EQ(1, spellcheck.numberOfTimesChecked());
5190 EXPECT_EQ(1U, document->markers().markersInRange(selectionRange, DocumentMarker::Spelling).size());
5192 frame->replaceMisspelledRange("welcome");
5193 EXPECT_EQ("_welcome_.", frame->contentAsText(std::numeric_limits<size_t>::max()).utf8());
5196 TEST_P(ParameterizedWebFrameTest, RemoveSpellingMarkers)
5198 registerMockedHttpURLLoad("spell.html");
5199 FrameTestHelpers::WebViewHelper webViewHelper(this);
5200 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5201 SpellCheckClient spellcheck;
5202 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5204 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5205 Document* document = frame->frame()->document();
5206 Element* element = document->getElementById("data");
5208 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5209 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5210 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5212 element->focus();
5213 NonThrowableExceptionState exceptionState;
5214 document->execCommand("InsertText", false, "_wellcome_.", exceptionState);
5215 EXPECT_FALSE(exceptionState.hadException());
5217 frame->removeSpellingMarkers();
5219 const int allTextBeginOffset = 0;
5220 const int allTextLength = 11;
5221 frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
5222 EphemeralRange selectionRange = frame->frame()->selection().selection().toNormalizedEphemeralRange();
5224 EXPECT_EQ(0U, document->markers().markersInRange(selectionRange, DocumentMarker::Spelling).size());
5227 TEST_P(ParameterizedWebFrameTest, RemoveSpellingMarkersUnderWords)
5229 registerMockedHttpURLLoad("spell.html");
5230 FrameTestHelpers::WebViewHelper webViewHelper(this);
5231 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5232 SpellCheckClient spellcheck;
5233 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5235 LocalFrame* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame())->frame();
5236 Document* document = frame->document();
5237 Element* element = document->getElementById("data");
5239 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5240 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5241 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5243 element->focus();
5244 NonThrowableExceptionState exceptionState;
5245 document->execCommand("InsertText", false, " wellcome ", exceptionState);
5246 EXPECT_FALSE(exceptionState.hadException());
5248 WebVector<uint32_t> documentMarkers1;
5249 webViewHelper.webView()->spellingMarkers(&documentMarkers1);
5250 EXPECT_EQ(1U, documentMarkers1.size());
5252 Vector<String> words;
5253 words.append("wellcome");
5254 frame->removeSpellingMarkersUnderWords(words);
5256 WebVector<uint32_t> documentMarkers2;
5257 webViewHelper.webView()->spellingMarkers(&documentMarkers2);
5258 EXPECT_EQ(0U, documentMarkers2.size());
5261 TEST_P(ParameterizedWebFrameTest, MarkerHashIdentifiers)
5263 registerMockedHttpURLLoad("spell.html");
5264 FrameTestHelpers::WebViewHelper webViewHelper(this);
5265 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5267 static const uint32_t kHash = 42;
5268 SpellCheckClient spellcheck(kHash);
5269 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5271 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5272 Document* document = frame->frame()->document();
5273 Element* element = document->getElementById("data");
5275 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5276 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5277 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5279 element->focus();
5280 NonThrowableExceptionState exceptionState;
5281 document->execCommand("InsertText", false, "wellcome.", exceptionState);
5282 EXPECT_FALSE(exceptionState.hadException());
5284 WebVector<uint32_t> documentMarkers;
5285 webViewHelper.webView()->spellingMarkers(&documentMarkers);
5286 EXPECT_EQ(1U, documentMarkers.size());
5287 EXPECT_EQ(kHash, documentMarkers[0]);
5290 class StubbornSpellCheckClient : public WebSpellCheckClient {
5291 public:
5292 StubbornSpellCheckClient() : m_completion(0) { }
5293 virtual ~StubbornSpellCheckClient() { }
5295 virtual void requestCheckingOfText(
5296 const WebString&,
5297 const WebVector<uint32_t>&,
5298 const WebVector<unsigned>&,
5299 WebTextCheckingCompletion* completion) override
5301 m_completion = completion;
5304 void kickNoResults()
5306 kick(-1, -1, WebTextDecorationTypeSpelling);
5309 void kick()
5311 kick(1, 8, WebTextDecorationTypeSpelling);
5314 void kickGrammar()
5316 kick(1, 8, WebTextDecorationTypeGrammar);
5319 void kickInvisibleSpellcheck()
5321 kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck);
5324 private:
5325 void kick(int misspellingStartOffset, int misspellingLength, WebTextDecorationType type)
5327 if (!m_completion)
5328 return;
5329 Vector<WebTextCheckingResult> results;
5330 if (misspellingStartOffset >= 0 && misspellingLength > 0)
5331 results.append(WebTextCheckingResult(type, misspellingStartOffset, misspellingLength));
5332 m_completion->didFinishCheckingText(results);
5333 m_completion = 0;
5336 WebTextCheckingCompletion* m_completion;
5339 TEST_P(ParameterizedWebFrameTest, SlowSpellcheckMarkerPosition)
5341 registerMockedHttpURLLoad("spell.html");
5342 FrameTestHelpers::WebViewHelper webViewHelper(this);
5343 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5345 StubbornSpellCheckClient spellcheck;
5346 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5348 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5349 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
5350 Document* document = frame->frame()->document();
5351 Element* element = document->getElementById("data");
5353 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5354 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5355 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5357 element->focus();
5358 NonThrowableExceptionState exceptionState;
5359 document->execCommand("InsertText", false, "wellcome ", exceptionState);
5360 EXPECT_FALSE(exceptionState.hadException());
5361 webInputElement.setSelectionRange(0, 0);
5362 document->execCommand("InsertText", false, "he", exceptionState);
5363 EXPECT_FALSE(exceptionState.hadException());
5365 spellcheck.kick();
5367 WebVector<uint32_t> documentMarkers;
5368 webViewHelper.webView()->spellingMarkers(&documentMarkers);
5369 EXPECT_EQ(0U, documentMarkers.size());
5372 // This test verifies that cancelling spelling request does not cause a
5373 // write-after-free when there's no spellcheck client set.
5374 TEST_P(ParameterizedWebFrameTest, CancelSpellingRequestCrash)
5376 registerMockedHttpURLLoad("spell.html");
5377 FrameTestHelpers::WebViewHelper webViewHelper(this);
5378 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5379 webViewHelper.webView()->setSpellCheckClient(0);
5381 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5382 Document* document = frame->frame()->document();
5383 Element* element = document->getElementById("data");
5385 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5386 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5387 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5389 element->focus();
5390 frame->frame()->editor().replaceSelectionWithText("A", false, false);
5391 frame->frame()->spellChecker().cancelCheck();
5394 TEST_P(ParameterizedWebFrameTest, SpellcheckResultErasesMarkers)
5396 registerMockedHttpURLLoad("spell.html");
5397 FrameTestHelpers::WebViewHelper webViewHelper(this);
5398 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5400 StubbornSpellCheckClient spellcheck;
5401 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5403 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5404 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
5405 Document* document = frame->frame()->document();
5406 Element* element = document->getElementById("data");
5408 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5409 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5410 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5412 element->focus();
5413 NonThrowableExceptionState exceptionState;
5414 document->execCommand("InsertText", false, "welcome ", exceptionState);
5415 EXPECT_FALSE(exceptionState.hadException());
5416 auto range = EphemeralRange::rangeOfContents(*element);
5417 document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::Spelling);
5418 document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::Grammar);
5419 document->markers().addMarker(range.startPosition(), range.endPosition(), DocumentMarker::InvisibleSpellcheck);
5420 EXPECT_EQ(3U, document->markers().markers().size());
5422 spellcheck.kickNoResults();
5423 EXPECT_EQ(0U, document->markers().markers().size());
5426 TEST_P(ParameterizedWebFrameTest, SpellcheckResultsSavedInDocument)
5428 registerMockedHttpURLLoad("spell.html");
5429 FrameTestHelpers::WebViewHelper webViewHelper(this);
5430 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
5432 StubbornSpellCheckClient spellcheck;
5433 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
5435 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
5436 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
5437 Document* document = frame->frame()->document();
5438 Element* element = document->getElementById("data");
5440 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
5441 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
5442 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
5444 element->focus();
5445 NonThrowableExceptionState exceptionState;
5446 document->execCommand("InsertText", false, "wellcome ", exceptionState);
5447 EXPECT_FALSE(exceptionState.hadException());
5449 spellcheck.kick();
5450 ASSERT_EQ(1U, document->markers().markers().size());
5451 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
5452 EXPECT_EQ(DocumentMarker::Spelling, document->markers().markers()[0]->type());
5454 document->execCommand("InsertText", false, "wellcome ", exceptionState);
5455 EXPECT_FALSE(exceptionState.hadException());
5457 spellcheck.kickGrammar();
5458 ASSERT_EQ(1U, document->markers().markers().size());
5459 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
5460 EXPECT_EQ(DocumentMarker::Grammar, document->markers().markers()[0]->type());
5462 document->execCommand("InsertText", false, "wellcome ", exceptionState);
5463 EXPECT_FALSE(exceptionState.hadException());
5465 spellcheck.kickInvisibleSpellcheck();
5466 ASSERT_EQ(1U, document->markers().markers().size());
5467 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
5468 EXPECT_EQ(DocumentMarker::InvisibleSpellcheck, document->markers().markers()[0]->type());
5471 class TestAccessInitialDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5472 public:
5473 TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false)
5477 virtual void didAccessInitialDocument(WebLocalFrame* frame)
5479 EXPECT_TRUE(!m_didAccessInitialDocument);
5480 m_didAccessInitialDocument = true;
5483 bool m_didAccessInitialDocument;
5486 TEST_P(ParameterizedWebFrameTest, DidAccessInitialDocumentBody)
5488 // FIXME: Why is this local webViewClient needed instead of the default
5489 // WebViewHelper one? With out it there's some mysterious crash in the
5490 // WebViewHelper destructor.
5491 FrameTestHelpers::TestWebViewClient webViewClient;
5492 TestAccessInitialDocumentWebFrameClient webFrameClient;
5493 FrameTestHelpers::WebViewHelper webViewHelper(this);
5494 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
5495 runPendingTasks();
5496 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5498 // Create another window that will try to access it.
5499 FrameTestHelpers::WebViewHelper newWebViewHelper(this);
5500 WebView* newView = newWebViewHelper.initialize(true);
5501 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
5502 runPendingTasks();
5503 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5505 // Access the initial document by modifying the body.
5506 newView->mainFrame()->executeScript(
5507 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
5508 runPendingTasks();
5509 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5511 // Access the initial document again, to ensure we don't notify twice.
5512 newView->mainFrame()->executeScript(
5513 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
5514 runPendingTasks();
5515 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5518 TEST_P(ParameterizedWebFrameTest, DidAccessInitialDocumentNavigator)
5520 // FIXME: Why is this local webViewClient needed instead of the default
5521 // WebViewHelper one? With out it there's some mysterious crash in the
5522 // WebViewHelper destructor.
5523 FrameTestHelpers::TestWebViewClient webViewClient;
5524 TestAccessInitialDocumentWebFrameClient webFrameClient;
5525 FrameTestHelpers::WebViewHelper webViewHelper(this);
5526 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
5527 runPendingTasks();
5528 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5530 // Create another window that will try to access it.
5531 FrameTestHelpers::WebViewHelper newWebViewHelper(this);
5532 WebView* newView = newWebViewHelper.initialize(true);
5533 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
5534 runPendingTasks();
5535 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5537 // Access the initial document to get to the navigator object.
5538 newView->mainFrame()->executeScript(
5539 WebScriptSource("console.log(window.opener.navigator);"));
5540 runPendingTasks();
5541 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5544 TEST_P(ParameterizedWebFrameTest, DidAccessInitialDocumentViaJavascriptUrl)
5546 TestAccessInitialDocumentWebFrameClient webFrameClient;
5547 FrameTestHelpers::WebViewHelper webViewHelper(this);
5548 webViewHelper.initialize(true, &webFrameClient);
5549 runPendingTasks();
5550 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5552 // Access the initial document from a javascript: URL.
5553 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Modified'))");
5554 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5557 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
5558 #if OS(WIN)
5559 TEST_P(ParameterizedWebFrameTest, DISABLED_DidAccessInitialDocumentBodyBeforeModalDialog)
5560 #else
5561 TEST_P(ParameterizedWebFrameTest, DidAccessInitialDocumentBodyBeforeModalDialog)
5562 #endif
5564 // FIXME: Why is this local webViewClient needed instead of the default
5565 // WebViewHelper one? With out it there's some mysterious crash in the
5566 // WebViewHelper destructor.
5567 FrameTestHelpers::TestWebViewClient webViewClient;
5568 TestAccessInitialDocumentWebFrameClient webFrameClient;
5569 FrameTestHelpers::WebViewHelper webViewHelper(this);
5570 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
5571 runPendingTasks();
5572 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5574 // Create another window that will try to access it.
5575 FrameTestHelpers::WebViewHelper newWebViewHelper(this);
5576 WebView* newView = newWebViewHelper.initialize(true);
5577 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
5578 runPendingTasks();
5579 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5581 // Access the initial document by modifying the body. We normally set a
5582 // timer to notify the client.
5583 newView->mainFrame()->executeScript(
5584 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
5585 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5587 // Make sure that a modal dialog forces us to notify right away.
5588 newView->mainFrame()->executeScript(
5589 WebScriptSource("window.opener.confirm('Modal');"));
5590 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5592 // Ensure that we don't notify again later.
5593 runPendingTasks();
5594 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5597 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
5598 #if OS(WIN)
5599 TEST_P(ParameterizedWebFrameTest, DISABLED_DidWriteToInitialDocumentBeforeModalDialog)
5600 #else
5601 TEST_P(ParameterizedWebFrameTest, DidWriteToInitialDocumentBeforeModalDialog)
5602 #endif
5604 // FIXME: Why is this local webViewClient needed instead of the default
5605 // WebViewHelper one? With out it there's some mysterious crash in the
5606 // WebViewHelper destructor.
5607 FrameTestHelpers::TestWebViewClient webViewClient;
5608 TestAccessInitialDocumentWebFrameClient webFrameClient;
5609 FrameTestHelpers::WebViewHelper webViewHelper(this);
5610 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
5611 runPendingTasks();
5612 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5614 // Create another window that will try to access it.
5615 FrameTestHelpers::WebViewHelper newWebViewHelper(this);
5616 WebView* newView = newWebViewHelper.initialize(true);
5617 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
5618 runPendingTasks();
5619 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5621 // Access the initial document with document.write, which moves us past the
5622 // initial empty document state of the state machine. We normally set a
5623 // timer to notify the client.
5624 newView->mainFrame()->executeScript(
5625 WebScriptSource("window.opener.document.write('Modified'); window.opener.document.close();"));
5626 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
5628 // Make sure that a modal dialog forces us to notify right away.
5629 newView->mainFrame()->executeScript(
5630 WebScriptSource("window.opener.confirm('Modal');"));
5631 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5633 // Ensure that we don't notify again later.
5634 runPendingTasks();
5635 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
5638 class TestScrolledFrameClient : public FrameTestHelpers::TestWebFrameClient {
5639 public:
5640 TestScrolledFrameClient() { reset(); }
5641 void reset()
5643 m_didScrollFrame = false;
5645 bool wasFrameScrolled() const { return m_didScrollFrame; }
5647 // WebFrameClient:
5648 void didChangeScrollOffset(WebLocalFrame* frame) override
5650 if (frame->parent())
5651 return;
5652 EXPECT_FALSE(m_didScrollFrame);
5653 FrameView* view = toWebLocalFrameImpl(frame)->frameView();
5654 // FrameView can be scrolled in FrameView::setFixedVisibleContentRect
5655 // which is called from LocalFrame::createView (before the frame is associated
5656 // with the the view).
5657 if (view)
5658 m_didScrollFrame = true;
5660 private:
5661 bool m_didScrollFrame;
5664 TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage)
5666 registerMockedHttpURLLoad("long_scroll.html");
5667 TestScrolledFrameClient client;
5669 // Make sure we initialize to minimum scale, even if the window size
5670 // only becomes available after the load begins.
5671 FrameTestHelpers::WebViewHelper webViewHelper;
5672 webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, &client);
5673 webViewHelper.webView()->resize(WebSize(1000, 1000));
5674 webViewHelper.webView()->layout();
5676 WebLocalFrameImpl* frameImpl = webViewHelper.webViewImpl()->mainFrameImpl();
5677 DocumentLoader::InitialScrollState& initialScrollState =
5678 frameImpl->frame()->loader().documentLoader()->initialScrollState();
5680 EXPECT_FALSE(client.wasFrameScrolled());
5681 EXPECT_FALSE(initialScrollState.wasScrolledByUser);
5683 // Do a compositor scroll, verify that this is counted as a user scroll.
5684 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(0, 1), WebFloatSize(), 1.7f, 0);
5685 EXPECT_TRUE(client.wasFrameScrolled());
5686 EXPECT_TRUE(initialScrollState.wasScrolledByUser);
5688 client.reset();
5689 initialScrollState.wasScrolledByUser = false;
5691 // The page scale 1.0f and scroll.
5692 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(0, 1), WebFloatSize(), 1.0f, 0);
5693 EXPECT_TRUE(client.wasFrameScrolled());
5694 EXPECT_TRUE(initialScrollState.wasScrolledByUser);
5695 client.reset();
5696 initialScrollState.wasScrolledByUser = false;
5698 // No scroll event if there is no scroll delta.
5699 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 0);
5700 EXPECT_FALSE(client.wasFrameScrolled());
5701 EXPECT_FALSE(initialScrollState.wasScrolledByUser);
5702 client.reset();
5704 // Non zero page scale and scroll.
5705 webViewHelper.webViewImpl()->applyViewportDeltas(WebFloatSize(), WebFloatSize(9, 13), WebFloatSize(), 0.6f, 0);
5706 EXPECT_TRUE(client.wasFrameScrolled());
5707 EXPECT_TRUE(initialScrollState.wasScrolledByUser);
5708 client.reset();
5709 initialScrollState.wasScrolledByUser = false;
5711 // Programmatic scroll.
5712 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5713 EXPECT_TRUE(client.wasFrameScrolled());
5714 EXPECT_FALSE(initialScrollState.wasScrolledByUser);
5715 client.reset();
5717 // Programmatic scroll to same offset. No scroll event should be generated.
5718 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5719 EXPECT_FALSE(client.wasFrameScrolled());
5720 EXPECT_FALSE(initialScrollState.wasScrolledByUser);
5721 client.reset();
5724 TEST_P(ParameterizedWebFrameTest, FirstPartyForCookiesForRedirect)
5726 WTF::String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
5727 filePath.append("/Source/web/tests/data/first_party.html");
5729 WebURL testURL(toKURL("http://internal.test/first_party_redirect.html"));
5730 char redirect[] = "http://internal.test/first_party.html";
5731 WebURL redirectURL(toKURL(redirect));
5732 WebURLResponse redirectResponse;
5733 redirectResponse.initialize();
5734 redirectResponse.setMIMEType("text/html");
5735 redirectResponse.setHTTPStatusCode(302);
5736 redirectResponse.setHTTPHeaderField("Location", redirect);
5737 Platform::current()->unitTestSupport()->registerMockedURL(testURL, redirectResponse, filePath);
5739 WebURLResponse finalResponse;
5740 finalResponse.initialize();
5741 finalResponse.setMIMEType("text/html");
5742 Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, finalResponse, filePath);
5744 FrameTestHelpers::WebViewHelper webViewHelper(this);
5745 webViewHelper.initializeAndLoad(m_baseURL + "first_party_redirect.html", true);
5746 EXPECT_TRUE(webViewHelper.webView()->mainFrame()->document().firstPartyForCookies() == redirectURL);
5749 class TestNavigationPolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5750 public:
5752 void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) override
5754 EXPECT_TRUE(false);
5758 TEST_P(ParameterizedWebFrameTest, SimulateFragmentAnchorMiddleClick)
5760 registerMockedHttpURLLoad("fragment_middle_click.html");
5761 TestNavigationPolicyWebFrameClient client;
5762 FrameTestHelpers::WebViewHelper webViewHelper(this);
5763 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true, &client);
5765 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5766 KURL destination = document->url();
5767 destination.setFragmentIdentifier("test");
5769 RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5770 document->domWindow(), 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 1, 0, nullptr);
5771 FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5772 frameRequest.setTriggeringEvent(event);
5773 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5776 class TestNewWindowWebViewClient : public FrameTestHelpers::TestWebViewClient {
5777 public:
5778 virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&,
5779 const WebString&, WebNavigationPolicy, bool) override
5781 EXPECT_TRUE(false);
5782 return 0;
5786 class TestNewWindowWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5787 public:
5788 TestNewWindowWebFrameClient()
5789 : m_decidePolicyCallCount(0)
5793 WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) override
5795 m_decidePolicyCallCount++;
5796 return info.defaultPolicy;
5799 int decidePolicyCallCount() const { return m_decidePolicyCallCount; }
5801 private:
5802 int m_decidePolicyCallCount;
5805 TEST_P(ParameterizedWebFrameTest, ModifiedClickNewWindow)
5807 registerMockedHttpURLLoad("ctrl_click.html");
5808 registerMockedHttpURLLoad("hello_world.html");
5809 TestNewWindowWebViewClient webViewClient;
5810 TestNewWindowWebFrameClient webFrameClient;
5811 FrameTestHelpers::WebViewHelper webViewHelper(this);
5812 webViewHelper.initializeAndLoad(m_baseURL + "ctrl_click.html", true, &webFrameClient, &webViewClient);
5814 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5815 KURL destination = toKURL(m_baseURL + "hello_world.html");
5817 // ctrl+click event
5818 RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5819 document->domWindow(), 0, 0, 0, 0, 0, 0, 0, true, false, false, false, 0, 0, nullptr);
5820 FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5821 frameRequest.setTriggeringEvent(event);
5822 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5823 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5824 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5826 // decidePolicyForNavigation should be called both for the original request and the ctrl+click.
5827 EXPECT_EQ(2, webFrameClient.decidePolicyCallCount());
5830 TEST_P(ParameterizedWebFrameTest, BackToReload)
5832 registerMockedHttpURLLoad("fragment_middle_click.html");
5833 FrameTestHelpers::WebViewHelper webViewHelper(this);
5834 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5835 WebFrame* frame = webViewHelper.webView()->mainFrame();
5836 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5837 RefPtrWillBePersistent<HistoryItem> firstItem = mainFrameLoader.currentItem();
5838 EXPECT_TRUE(firstItem);
5840 registerMockedHttpURLLoad("white-1x1.png");
5841 FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5842 EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5844 FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem.get()), WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5845 EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5847 FrameTestHelpers::reloadFrame(frame);
5848 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5851 TEST_P(ParameterizedWebFrameTest, BackDuringChildFrameReload)
5853 registerMockedHttpURLLoad("page_with_blank_iframe.html");
5854 FrameTestHelpers::WebViewHelper webViewHelper(this);
5855 webViewHelper.initializeAndLoad(m_baseURL + "page_with_blank_iframe.html", true);
5856 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
5857 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5858 WebFrame* childFrame = mainFrame->firstChild();
5859 ASSERT_TRUE(childFrame);
5861 // Start a history navigation, then have a different frame commit a navigation.
5862 // In this case, reload an about:blank frame, which will commit synchronously.
5863 // After the history navigation completes, both the appropriate document url and
5864 // the current history item should reflect the history navigation.
5865 registerMockedHttpURLLoad("white-1x1.png");
5866 WebHistoryItem item;
5867 item.initialize();
5868 WebURL historyURL(toKURL(m_baseURL + "white-1x1.png"));
5869 item.setURLString(historyURL.string());
5870 mainFrame->loadHistoryItem(item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5872 FrameTestHelpers::reloadFrame(childFrame);
5873 EXPECT_EQ(item.urlString(), mainFrame->document().url().string());
5874 EXPECT_EQ(item.urlString(), WebString(mainFrameLoader.currentItem()->urlString()));
5877 TEST_P(ParameterizedWebFrameTest, ReloadPost)
5879 registerMockedHttpURLLoad("reload_post.html");
5880 FrameTestHelpers::WebViewHelper webViewHelper(this);
5881 webViewHelper.initializeAndLoad(m_baseURL + "reload_post.html", true);
5882 WebFrame* frame = webViewHelper.webView()->mainFrame();
5884 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.forms[0].submit()");
5885 // Pump requests one more time after the javascript URL has executed to
5886 // trigger the actual POST load request.
5887 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5888 EXPECT_EQ(WebString::fromUTF8("POST"), frame->dataSource()->request().httpMethod());
5890 FrameTestHelpers::reloadFrame(frame);
5891 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5892 EXPECT_EQ(WebNavigationTypeFormResubmitted, frame->dataSource()->navigationType());
5895 TEST_P(ParameterizedWebFrameTest, LoadHistoryItemReload)
5897 registerMockedHttpURLLoad("fragment_middle_click.html");
5898 FrameTestHelpers::WebViewHelper webViewHelper(this);
5899 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5900 WebFrame* frame = webViewHelper.webView()->mainFrame();
5901 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5902 RefPtrWillBePersistent<HistoryItem> firstItem = mainFrameLoader.currentItem();
5903 EXPECT_TRUE(firstItem);
5905 registerMockedHttpURLLoad("white-1x1.png");
5906 FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5907 EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5909 // Cache policy overrides should take.
5910 FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem), WebHistoryDifferentDocumentLoad, WebURLRequest::ReloadIgnoringCacheData);
5911 EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5912 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5916 class TestCachePolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5917 public:
5918 explicit TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient* parentClient)
5919 : m_parentClient(parentClient)
5920 , m_policy(WebURLRequest::UseProtocolCachePolicy)
5921 , m_childClient(0)
5922 , m_willSendRequestCallCount(0)
5923 , m_childFrameCreationCount(0)
5927 void setChildWebFrameClient(TestCachePolicyWebFrameClient* client) { m_childClient = client; }
5928 WebURLRequest::CachePolicy cachePolicy() const { return m_policy; }
5929 int willSendRequestCallCount() const { return m_willSendRequestCallCount; }
5930 int childFrameCreationCount() const { return m_childFrameCreationCount; }
5932 virtual WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString&, WebSandboxFlags)
5934 ASSERT(m_childClient);
5935 m_childFrameCreationCount++;
5936 WebFrame* frame = WebLocalFrame::create(scope, m_childClient);
5937 parent->appendChild(frame);
5938 return frame;
5941 virtual void didStartLoading(bool toDifferentDocument)
5943 if (m_parentClient) {
5944 m_parentClient->didStartLoading(toDifferentDocument);
5945 return;
5947 TestWebFrameClient::didStartLoading(toDifferentDocument);
5950 virtual void didStopLoading()
5952 if (m_parentClient) {
5953 m_parentClient->didStopLoading();
5954 return;
5956 TestWebFrameClient::didStopLoading();
5959 void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) override
5961 m_policy = request.cachePolicy();
5962 m_willSendRequestCallCount++;
5965 private:
5966 TestCachePolicyWebFrameClient* m_parentClient;
5968 WebURLRequest::CachePolicy m_policy;
5969 TestCachePolicyWebFrameClient* m_childClient;
5970 int m_willSendRequestCallCount;
5971 int m_childFrameCreationCount;
5974 TEST_P(ParameterizedWebFrameTest, ReloadIframe)
5976 registerMockedHttpURLLoad("iframe_reload.html");
5977 registerMockedHttpURLLoad("visible_iframe.html");
5978 TestCachePolicyWebFrameClient mainClient(0);
5979 TestCachePolicyWebFrameClient childClient(&mainClient);
5980 mainClient.setChildWebFrameClient(&childClient);
5982 FrameTestHelpers::WebViewHelper webViewHelper(this);
5983 webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, &mainClient);
5985 WebLocalFrameImpl* mainFrame = webViewHelper.webViewImpl()->mainFrameImpl();
5986 RefPtrWillBeRawPtr<WebLocalFrameImpl> childFrame = toWebLocalFrameImpl(mainFrame->firstChild());
5987 ASSERT_EQ(childFrame->client(), &childClient);
5988 EXPECT_EQ(mainClient.childFrameCreationCount(), 1);
5989 EXPECT_EQ(childClient.willSendRequestCallCount(), 1);
5990 EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::UseProtocolCachePolicy);
5992 FrameTestHelpers::reloadFrame(mainFrame);
5994 // A new WebFrame should have been created, but the child WebFrameClient should be reused.
5995 ASSERT_NE(childFrame, toWebLocalFrameImpl(mainFrame->firstChild()));
5996 ASSERT_EQ(toWebLocalFrameImpl(mainFrame->firstChild())->client(), &childClient);
5998 EXPECT_EQ(mainClient.childFrameCreationCount(), 2);
5999 EXPECT_EQ(childClient.willSendRequestCallCount(), 2);
6000 EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::ReloadIgnoringCacheData);
6003 class TestSameDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6004 public:
6005 TestSameDocumentWebFrameClient()
6006 : m_frameLoadTypeSameSeen(false)
6010 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest&, const WebURLResponse&)
6012 if (toWebLocalFrameImpl(frame)->frame()->loader().loadType() == FrameLoadTypeSame)
6013 m_frameLoadTypeSameSeen = true;
6016 bool frameLoadTypeSameSeen() const { return m_frameLoadTypeSameSeen; }
6018 private:
6019 bool m_frameLoadTypeSameSeen;
6022 TEST_P(ParameterizedWebFrameTest, NavigateToSame)
6024 registerMockedHttpURLLoad("navigate_to_same.html");
6025 TestSameDocumentWebFrameClient client;
6026 FrameTestHelpers::WebViewHelper webViewHelper(this);
6027 webViewHelper.initializeAndLoad(m_baseURL + "navigate_to_same.html", true, &client);
6028 EXPECT_FALSE(client.frameLoadTypeSameSeen());
6030 FrameLoadRequest frameRequest(0, ResourceRequest(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document()->url()));
6031 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
6032 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
6034 EXPECT_TRUE(client.frameLoadTypeSameSeen());
6037 class TestSameDocumentWithImageWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6038 public:
6039 TestSameDocumentWithImageWebFrameClient()
6040 : m_numOfImageRequests(0)
6044 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&)
6046 if (request.requestContext() == WebURLRequest::RequestContextImage) {
6047 m_numOfImageRequests++;
6048 EXPECT_EQ(WebURLRequest::UseProtocolCachePolicy, request.cachePolicy());
6052 int numOfImageRequests() const { return m_numOfImageRequests; }
6054 private:
6055 int m_numOfImageRequests;
6058 TEST_P(ParameterizedWebFrameTest, NavigateToSameNoConditionalRequestForSubresource)
6060 registerMockedHttpURLLoad("foo_with_image.html");
6061 registerMockedHttpURLLoad("white-1x1.png");
6062 TestSameDocumentWithImageWebFrameClient client;
6063 FrameTestHelpers::WebViewHelper webViewHelper(this);
6064 webViewHelper.initializeAndLoad(m_baseURL + "foo_with_image.html", true, &client, 0, &configureLoadsImagesAutomatically);
6066 WebCache::clear();
6067 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "foo_with_image.html");
6069 EXPECT_EQ(client.numOfImageRequests(), 2);
6072 TEST_P(ParameterizedWebFrameTest, WebNodeImageContents)
6074 FrameTestHelpers::WebViewHelper webViewHelper(this);
6075 webViewHelper.initializeAndLoad("about:blank", true);
6076 WebFrame* frame = webViewHelper.webView()->mainFrame();
6078 static const char bluePNG[] = "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYV2NkYPj/n4EIwDiqEF8oUT94AFIQE/cCn90IAAAAAElFTkSuQmCC\">";
6080 // Load up the image and test that we can extract the contents.
6081 KURL testURL = toKURL("about:blank");
6082 FrameTestHelpers::loadHTMLString(frame, bluePNG, testURL);
6084 WebNode node = frame->document().body().firstChild();
6085 EXPECT_TRUE(node.isElementNode());
6086 WebElement element = node.to<WebElement>();
6087 WebImage image = element.imageContents();
6088 ASSERT_FALSE(image.isNull());
6089 EXPECT_EQ(image.size().width, 10);
6090 EXPECT_EQ(image.size().height, 10);
6091 // FIXME: The rest of this test is disabled since the ImageDecodeCache state may be inconsistent when this test runs.
6092 // crbug.com/266088
6093 // SkBitmap bitmap = image.getSkBitmap();
6094 // SkAutoLockPixels locker(bitmap);
6095 // EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorBLUE);
6098 class TestStartStopCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6099 public:
6100 TestStartStopCallbackWebFrameClient()
6101 : m_startLoadingCount(0)
6102 , m_stopLoadingCount(0)
6103 , m_differentDocumentStartCount(0)
6107 void didStartLoading(bool toDifferentDocument) override
6109 TestWebFrameClient::didStartLoading(toDifferentDocument);
6110 m_startLoadingCount++;
6111 if (toDifferentDocument)
6112 m_differentDocumentStartCount++;
6115 void didStopLoading() override
6117 TestWebFrameClient::didStopLoading();
6118 m_stopLoadingCount++;
6121 int startLoadingCount() const { return m_startLoadingCount; }
6122 int stopLoadingCount() const { return m_stopLoadingCount; }
6123 int differentDocumentStartCount() const { return m_differentDocumentStartCount; }
6125 private:
6126 int m_startLoadingCount;
6127 int m_stopLoadingCount;
6128 int m_differentDocumentStartCount;
6131 TEST_P(ParameterizedWebFrameTest, PushStateStartsAndStops)
6133 registerMockedHttpURLLoad("push_state.html");
6134 TestStartStopCallbackWebFrameClient client;
6135 FrameTestHelpers::WebViewHelper webViewHelper(this);
6136 webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
6138 EXPECT_EQ(client.startLoadingCount(), 2);
6139 EXPECT_EQ(client.stopLoadingCount(), 2);
6140 EXPECT_EQ(client.differentDocumentStartCount(), 1);
6143 class TestDidNavigateCommitTypeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6144 public:
6145 TestDidNavigateCommitTypeWebFrameClient()
6146 : m_lastCommitType(WebHistoryInertCommit)
6150 void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType type) override
6152 m_lastCommitType = type;
6155 WebHistoryCommitType lastCommitType() const { return m_lastCommitType; }
6157 private:
6158 WebHistoryCommitType m_lastCommitType;
6161 TEST_P(ParameterizedWebFrameTest, SameDocumentHistoryNavigationCommitType)
6163 registerMockedHttpURLLoad("push_state.html");
6164 TestDidNavigateCommitTypeWebFrameClient client;
6165 FrameTestHelpers::WebViewHelper webViewHelper(this);
6166 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
6167 RefPtrWillBePersistent<HistoryItem> item = toLocalFrame(webViewImpl->page()->mainFrame())->loader().currentItem();
6168 runPendingTasks();
6170 toLocalFrame(webViewImpl->page()->mainFrame())->loader().load(
6171 FrameLoadRequest(nullptr, FrameLoader::resourceRequestFromHistoryItem(
6172 item.get(), UseProtocolCachePolicy)),
6173 FrameLoadTypeBackForward, item.get(), HistorySameDocumentLoad);
6174 EXPECT_EQ(WebBackForwardCommit, client.lastCommitType());
6177 class TestHistoryWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6178 public:
6179 TestHistoryWebFrameClient()
6181 m_replacesCurrentHistoryItem = false;
6182 m_frame = nullptr;
6185 void didStartProvisionalLoad(WebLocalFrame* frame, double)
6187 WebDataSource* ds = frame->provisionalDataSource();
6188 m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem();
6189 m_frame = frame;
6192 bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; }
6193 WebFrame* frame() { return m_frame; }
6195 private:
6196 bool m_replacesCurrentHistoryItem;
6197 WebFrame* m_frame;
6200 // Tests that the first navigation in an initially blank subframe will result in
6201 // a history entry being replaced and not a new one being added.
6202 TEST_P(ParameterizedWebFrameTest, FirstBlankSubframeNavigation)
6204 registerMockedHttpURLLoad("history.html");
6205 registerMockedHttpURLLoad("find.html");
6207 FrameTestHelpers::WebViewHelper webViewHelper(this);
6208 TestHistoryWebFrameClient client;
6209 webViewHelper.initializeAndLoad("about:blank", true, &client);
6211 WebFrame* frame = webViewHelper.webView()->mainFrame();
6213 frame->executeScript(WebScriptSource(WebString::fromUTF8(
6214 "document.body.appendChild(document.createElement('iframe'))")));
6216 WebFrame* iframe = frame->firstChild();
6217 ASSERT_EQ(&client, toWebLocalFrameImpl(iframe)->client());
6218 EXPECT_EQ(iframe, client.frame());
6220 std::string url1 = m_baseURL + "history.html";
6221 FrameTestHelpers::loadFrame(iframe, url1);
6222 EXPECT_EQ(iframe, client.frame());
6223 EXPECT_EQ(url1, iframe->document().url().string().utf8());
6224 EXPECT_TRUE(client.replacesCurrentHistoryItem());
6226 std::string url2 = m_baseURL + "find.html";
6227 FrameTestHelpers::loadFrame(iframe, url2);
6228 EXPECT_EQ(iframe, client.frame());
6229 EXPECT_EQ(url2, iframe->document().url().string().utf8());
6230 EXPECT_FALSE(client.replacesCurrentHistoryItem());
6233 // Tests that a navigation in a frame with a non-blank initial URL will create
6234 // a new history item, unlike the case above.
6235 TEST_P(ParameterizedWebFrameTest, FirstNonBlankSubframeNavigation)
6237 registerMockedHttpURLLoad("history.html");
6238 registerMockedHttpURLLoad("find.html");
6240 FrameTestHelpers::WebViewHelper webViewHelper(this);
6241 TestHistoryWebFrameClient client;
6242 webViewHelper.initializeAndLoad("about:blank", true, &client);
6244 WebFrame* frame = webViewHelper.webView()->mainFrame();
6246 std::string url1 = m_baseURL + "history.html";
6247 FrameTestHelpers::loadFrame(frame,
6248 "javascript:var f = document.createElement('iframe'); "
6249 "f.src = '" + url1 + "';"
6250 "document.body.appendChild(f)");
6252 WebFrame* iframe = frame->firstChild();
6253 EXPECT_EQ(iframe, client.frame());
6254 EXPECT_EQ(url1, iframe->document().url().string().utf8());
6256 std::string url2 = m_baseURL + "find.html";
6257 FrameTestHelpers::loadFrame(iframe, url2);
6258 EXPECT_EQ(iframe, client.frame());
6259 EXPECT_EQ(url2, iframe->document().url().string().utf8());
6260 EXPECT_FALSE(client.replacesCurrentHistoryItem());
6263 // Test verifies that layout will change a layer's scrollable attibutes
6264 TEST_F(WebFrameTest, overflowHiddenRewrite)
6266 registerMockedHttpURLLoad("non-scrollable.html");
6267 OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
6268 FrameTestHelpers::WebViewHelper webViewHelper;
6269 webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
6271 webViewHelper.webView()->resize(WebSize(100, 100));
6272 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "non-scrollable.html");
6274 DeprecatedPaintLayerCompositor* compositor = webViewHelper.webViewImpl()->compositor();
6275 ASSERT_TRUE(compositor->scrollLayer());
6277 // Verify that the WebLayer is not scrollable initially.
6278 GraphicsLayer* scrollLayer = compositor->scrollLayer();
6279 WebLayer* webScrollLayer = scrollLayer->platformLayer();
6280 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
6281 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
6283 // Call javascript to make the layer scrollable, and verify it.
6284 WebLocalFrameImpl* frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
6285 frame->executeScript(WebScriptSource("allowScroll();"));
6286 webViewHelper.webView()->layout();
6287 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
6288 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
6291 // Test that currentHistoryItem reflects the current page, not the provisional load.
6292 TEST_P(ParameterizedWebFrameTest, CurrentHistoryItem)
6294 registerMockedHttpURLLoad("fixed_layout.html");
6295 std::string url = m_baseURL + "fixed_layout.html";
6297 FrameTestHelpers::WebViewHelper webViewHelper(this);
6298 webViewHelper.initialize();
6299 WebFrame* frame = webViewHelper.webView()->mainFrame();
6300 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
6301 WebURLRequest request;
6302 request.initialize();
6303 request.setURL(toKURL(url));
6304 frame->loadRequest(request);
6306 // Before commit, there is no history item.
6307 EXPECT_FALSE(mainFrameLoader.currentItem());
6309 FrameTestHelpers::pumpPendingRequestsDoNotUse(frame);
6311 // After commit, there is.
6312 HistoryItem* item = mainFrameLoader.currentItem();
6313 ASSERT_TRUE(item);
6314 EXPECT_EQ(WTF::String(url.data()), item->urlString());
6317 class FailCreateChildFrame : public FrameTestHelpers::TestWebFrameClient {
6318 public:
6319 FailCreateChildFrame() : m_callCount(0) { }
6321 WebFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType scope, const WebString& frameName, WebSandboxFlags sandboxFlags) override
6323 ++m_callCount;
6324 return 0;
6327 int callCount() const { return m_callCount; }
6329 private:
6330 int m_callCount;
6333 // Test that we don't crash if WebFrameClient::createChildFrame() fails.
6334 TEST_P(ParameterizedWebFrameTest, CreateChildFrameFailure)
6336 registerMockedHttpURLLoad("create_child_frame_fail.html");
6337 FailCreateChildFrame client;
6338 FrameTestHelpers::WebViewHelper webViewHelper(this);
6339 webViewHelper.initializeAndLoad(m_baseURL + "create_child_frame_fail.html", true, &client);
6341 EXPECT_EQ(1, client.callCount());
6344 TEST_P(ParameterizedWebFrameTest, fixedPositionInFixedViewport)
6346 UseMockScrollbarSettings mockScrollbarSettings;
6347 registerMockedHttpURLLoad("fixed-position-in-fixed-viewport.html");
6348 FrameTestHelpers::WebViewHelper webViewHelper(this);
6349 webViewHelper.initializeAndLoad(m_baseURL + "fixed-position-in-fixed-viewport.html", true, 0, 0, enableViewportSettings);
6351 WebView* webView = webViewHelper.webView();
6352 webView->resize(WebSize(100, 100));
6354 Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
6355 Element* bottomFixed = document->getElementById("bottom-fixed");
6356 Element* topBottomFixed = document->getElementById("top-bottom-fixed");
6357 Element* rightFixed = document->getElementById("right-fixed");
6358 Element* leftRightFixed = document->getElementById("left-right-fixed");
6360 // The layout viewport will hit the min-scale limit of 0.25, so it'll be 400x800.
6361 webView->resize(WebSize(100, 200));
6362 EXPECT_EQ(800, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
6363 EXPECT_EQ(800, topBottomFixed->offsetHeight());
6365 // Now the layout viewport hits the content width limit of 500px so it'll be 500x500.
6366 webView->resize(WebSize(200, 200));
6367 EXPECT_EQ(500, rightFixed->offsetLeft() + rightFixed->offsetWidth());
6368 EXPECT_EQ(500, leftRightFixed->offsetWidth());
6371 TEST_P(ParameterizedWebFrameTest, FrameViewMoveWithSetFrameRect)
6373 FrameTestHelpers::WebViewHelper webViewHelper(this);
6374 webViewHelper.initializeAndLoad("about:blank");
6375 webViewHelper.webViewImpl()->resize(WebSize(200, 200));
6376 webViewHelper.webViewImpl()->layout();
6378 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
6379 EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), frameView->frameRect());
6380 frameView->setFrameRect(IntRect(100, 100, 200, 200));
6381 EXPECT_RECT_EQ(IntRect(100, 100, 200, 200), frameView->frameRect());
6384 TEST_F(WebFrameTest, FrameViewScrollAccountsForTopControls)
6386 FakeCompositingWebViewClient client;
6387 registerMockedHttpURLLoad("long_scroll.html");
6388 UseMockScrollbarSettings mockScrollbarSettings;
6389 FrameTestHelpers::WebViewHelper webViewHelper;
6390 webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, 0, &client, configureAndroid);
6392 WebViewImpl* webView = webViewHelper.webViewImpl();
6393 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
6395 float topControlsHeight = 40;
6396 webView->setTopControlsHeight(topControlsHeight, false);
6397 webView->resize(WebSize(100, 100));
6398 webView->setPageScaleFactor(2.0f);
6399 webView->layout();
6401 webView->mainFrame()->setScrollOffset(WebSize(0, 2000));
6402 EXPECT_POINT_EQ(IntPoint(0, 1900), IntPoint(frameView->scrollOffset()));
6404 // Simulate the top controls showing by 20px, thus shrinking the viewport
6405 // and allowing it to scroll an additional 20px.
6406 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 20.0f / topControlsHeight);
6407 EXPECT_POINT_EQ(IntPoint(0, 1920), frameView->maximumScrollPosition());
6409 // Show more, make sure the scroll actually gets clamped.
6410 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 20.0f / topControlsHeight);
6411 webView->mainFrame()->setScrollOffset(WebSize(0, 2000));
6412 EXPECT_POINT_EQ(IntPoint(0, 1940), IntPoint(frameView->scrollOffset()));
6414 // Hide until there's 10px showing.
6415 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, -30.0f / topControlsHeight);
6416 EXPECT_POINT_EQ(IntPoint(0, 1910), frameView->maximumScrollPosition());
6418 // Simulate a LayoutPart::resize. The frame is resized to accomodate
6419 // the top controls and Blink's view of the top controls matches that of
6420 // the CC
6421 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 30.0f / topControlsHeight);
6422 webView->setTopControlsHeight(40.0f, true);
6423 webView->resize(WebSize(100, 60));
6424 webView->layout();
6425 EXPECT_POINT_EQ(IntPoint(0, 1940), frameView->maximumScrollPosition());
6427 // Now simulate hiding.
6428 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, -10.0f / topControlsHeight);
6429 EXPECT_POINT_EQ(IntPoint(0, 1930), frameView->maximumScrollPosition());
6431 // Reset to original state: 100px widget height, top controls fully hidden.
6432 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, -30.0f / topControlsHeight);
6433 webView->setTopControlsHeight(topControlsHeight, false);
6434 webView->resize(WebSize(100, 100));
6435 webView->layout();
6436 EXPECT_POINT_EQ(IntPoint(0, 1900), frameView->maximumScrollPosition());
6438 // Show the top controls by just 1px, since we're zoomed in to 2X, that
6439 // should allow an extra 0.5px of scrolling in the visual viewport. Make
6440 // sure we're not losing any pixels when applying the adjustment on the
6441 // main frame.
6442 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 1.0f / topControlsHeight);
6443 EXPECT_POINT_EQ(IntPoint(0, 1901), frameView->maximumScrollPosition());
6445 webView->applyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 2.0f / topControlsHeight);
6446 EXPECT_POINT_EQ(IntPoint(0, 1903), frameView->maximumScrollPosition());
6449 TEST_F(WebFrameTest, MaximumScrollPositionCanBeNegative)
6451 UseMockScrollbarSettings mockScrollbarSettings;
6452 registerMockedHttpURLLoad("rtl-overview-mode.html");
6454 FixedLayoutTestWebViewClient client;
6455 client.m_screenInfo.deviceScaleFactor = 1;
6456 int viewportWidth = 640;
6457 int viewportHeight = 480;
6459 FrameTestHelpers::WebViewHelper webViewHelper;
6460 webViewHelper.initializeAndLoad(m_baseURL + "rtl-overview-mode.html", true, 0, &client, enableViewportSettings);
6461 webViewHelper.webView()->setInitialPageScaleOverride(-1);
6462 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
6463 webViewHelper.webView()->settings()->setLoadWithOverviewMode(true);
6464 webViewHelper.webView()->settings()->setUseWideViewport(true);
6465 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
6466 webViewHelper.webView()->layout();
6468 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
6469 EXPECT_LT(frameView->maximumScrollPosition().x(), 0);
6472 TEST_P(ParameterizedWebFrameTest, FullscreenLayerSize)
6474 FakeCompositingWebViewClient client;
6475 registerMockedHttpURLLoad("fullscreen_div.html");
6476 FrameTestHelpers::WebViewHelper webViewHelper(this);
6477 int viewportWidth = 640;
6478 int viewportHeight = 480;
6479 client.m_screenInfo.rect.width = viewportWidth;
6480 client.m_screenInfo.rect.height = viewportHeight;
6481 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, configureAndroid);
6482 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6483 webViewImpl->layout();
6485 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
6486 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6487 Element* divFullscreen = document->getElementById("div1");
6488 Fullscreen::from(*document).requestFullscreen(*divFullscreen, Fullscreen::PrefixedRequest);
6489 webViewImpl->didEnterFullScreen();
6490 webViewImpl->layout();
6491 ASSERT_TRUE(Fullscreen::isFullScreen(*document));
6493 // Verify that the element is sized to the viewport.
6494 LayoutFullScreen* fullscreenLayoutObject = Fullscreen::from(*document).fullScreenLayoutObject();
6495 EXPECT_EQ(viewportWidth, fullscreenLayoutObject->logicalWidth().toInt());
6496 EXPECT_EQ(viewportHeight, fullscreenLayoutObject->logicalHeight().toInt());
6498 // Verify it's updated after a device rotation.
6499 client.m_screenInfo.rect.width = viewportHeight;
6500 client.m_screenInfo.rect.height = viewportWidth;
6501 webViewImpl->resize(WebSize(viewportHeight, viewportWidth));
6502 webViewImpl->layout();
6503 EXPECT_EQ(viewportHeight, fullscreenLayoutObject->logicalWidth().toInt());
6504 EXPECT_EQ(viewportWidth, fullscreenLayoutObject->logicalHeight().toInt());
6507 TEST_F(WebFrameTest, FullscreenLayerNonScrollable)
6509 FakeCompositingWebViewClient client;
6510 registerMockedHttpURLLoad("fullscreen_div.html");
6511 FrameTestHelpers::WebViewHelper webViewHelper;
6512 int viewportWidth = 640;
6513 int viewportHeight = 480;
6514 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, configureAndroid);
6515 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6516 webViewImpl->layout();
6518 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
6519 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6520 Element* divFullscreen = document->getElementById("div1");
6521 Fullscreen::from(*document).requestFullscreen(*divFullscreen, Fullscreen::PrefixedRequest);
6522 webViewImpl->didEnterFullScreen();
6523 webViewImpl->layout();
6525 // Verify that the viewports are nonscrollable.
6526 ASSERT_TRUE(Fullscreen::isFullScreen(*document));
6527 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
6528 WebLayer* layoutViewportScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
6529 WebLayer* visualViewportScrollLayer = frameView->page()->frameHost().visualViewport().scrollLayer()->platformLayer();
6530 ASSERT_FALSE(layoutViewportScrollLayer->userScrollableHorizontal());
6531 ASSERT_FALSE(layoutViewportScrollLayer->userScrollableVertical());
6532 ASSERT_FALSE(visualViewportScrollLayer->userScrollableHorizontal());
6533 ASSERT_FALSE(visualViewportScrollLayer->userScrollableVertical());
6535 // Verify that the viewports are scrollable upon exiting fullscreen.
6536 webViewImpl->didExitFullScreen();
6537 webViewImpl->layout();
6538 ASSERT_FALSE(Fullscreen::isFullScreen(*document));
6539 ASSERT_TRUE(layoutViewportScrollLayer->userScrollableHorizontal());
6540 ASSERT_TRUE(layoutViewportScrollLayer->userScrollableVertical());
6541 ASSERT_TRUE(visualViewportScrollLayer->userScrollableHorizontal());
6542 ASSERT_TRUE(visualViewportScrollLayer->userScrollableVertical());
6545 TEST_P(ParameterizedWebFrameTest, FullscreenMainFrame)
6547 FakeCompositingWebViewClient client;
6548 registerMockedHttpURLLoad("fullscreen_div.html");
6549 FrameTestHelpers::WebViewHelper webViewHelper(this);
6550 int viewportWidth = 640;
6551 int viewportHeight = 480;
6552 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, configureAndroid);
6553 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6554 webViewImpl->layout();
6556 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
6557 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6558 Fullscreen::from(*document).requestFullscreen(*document->documentElement(), Fullscreen::PrefixedRequest);
6559 webViewImpl->didEnterFullScreen();
6560 webViewImpl->layout();
6562 // Verify that the main frame is still scrollable.
6563 ASSERT_TRUE(Fullscreen::isFullScreen(*document));
6564 WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
6565 ASSERT_TRUE(webScrollLayer->scrollable());
6566 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
6567 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
6569 // Verify the main frame still behaves correctly after a resize.
6570 webViewImpl->resize(WebSize(viewportHeight, viewportWidth));
6571 ASSERT_TRUE(webScrollLayer->scrollable());
6572 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
6573 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
6576 TEST_P(ParameterizedWebFrameTest, FullscreenSubframe)
6578 FakeCompositingWebViewClient client;
6579 registerMockedHttpURLLoad("fullscreen_iframe.html");
6580 registerMockedHttpURLLoad("fullscreen_div.html");
6581 FrameTestHelpers::WebViewHelper webViewHelper(this);
6582 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_iframe.html", true, 0, &client, configureAndroid);
6583 int viewportWidth = 640;
6584 int viewportHeight = 480;
6585 client.m_screenInfo.rect.width = viewportWidth;
6586 client.m_screenInfo.rect.height = viewportHeight;
6587 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6588 webViewImpl->layout();
6590 Document* document = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()->firstChild())->frame()->document();
6591 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6592 Element* divFullscreen = document->getElementById("div1");
6593 Fullscreen::from(*document).requestFullscreen(*divFullscreen, Fullscreen::PrefixedRequest);
6594 webViewImpl->didEnterFullScreen();
6595 webViewImpl->layout();
6597 // Verify that the element is sized to the viewport.
6598 LayoutFullScreen* fullscreenLayoutObject = Fullscreen::from(*document).fullScreenLayoutObject();
6599 EXPECT_EQ(viewportWidth, fullscreenLayoutObject->logicalWidth().toInt());
6600 EXPECT_EQ(viewportHeight, fullscreenLayoutObject->logicalHeight().toInt());
6602 // Verify it's updated after a device rotation.
6603 client.m_screenInfo.rect.width = viewportHeight;
6604 client.m_screenInfo.rect.height = viewportWidth;
6605 webViewImpl->resize(WebSize(viewportHeight, viewportWidth));
6606 webViewImpl->layout();
6607 EXPECT_EQ(viewportHeight, fullscreenLayoutObject->logicalWidth().toInt());
6608 EXPECT_EQ(viewportWidth, fullscreenLayoutObject->logicalHeight().toInt());
6611 TEST_P(ParameterizedWebFrameTest, FullscreenWithTinyViewport)
6613 FakeCompositingWebViewClient client;
6614 registerMockedHttpURLLoad("viewport-tiny.html");
6615 FrameTestHelpers::WebViewHelper webViewHelper(this);
6616 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "viewport-tiny.html", true, 0, &client, configureAndroid);
6617 int viewportWidth = 384;
6618 int viewportHeight = 640;
6619 client.m_screenInfo.rect.width = viewportWidth;
6620 client.m_screenInfo.rect.height = viewportHeight;
6621 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6622 webViewImpl->layout();
6624 LayoutView* layoutView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutView();
6625 EXPECT_EQ(320, layoutView->logicalWidth().floor());
6626 EXPECT_EQ(533, layoutView->logicalHeight().floor());
6627 EXPECT_FLOAT_EQ(1.2, webViewImpl->pageScaleFactor());
6628 EXPECT_FLOAT_EQ(1.2, webViewImpl->minimumPageScaleFactor());
6629 EXPECT_FLOAT_EQ(5.0, webViewImpl->maximumPageScaleFactor());
6631 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
6632 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6633 Fullscreen::from(*document).requestFullscreen(*document->documentElement(), Fullscreen::PrefixedRequest);
6634 webViewImpl->didEnterFullScreen();
6635 webViewImpl->layout();
6636 EXPECT_EQ(384, layoutView->logicalWidth().floor());
6637 EXPECT_EQ(640, layoutView->logicalHeight().floor());
6638 EXPECT_FLOAT_EQ(1.0, webViewImpl->pageScaleFactor());
6639 EXPECT_FLOAT_EQ(1.0, webViewImpl->minimumPageScaleFactor());
6640 EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
6642 webViewImpl->didExitFullScreen();
6643 webViewImpl->layout();
6644 EXPECT_EQ(320, layoutView->logicalWidth().floor());
6645 EXPECT_EQ(533, layoutView->logicalHeight().floor());
6646 EXPECT_FLOAT_EQ(1.2, webViewImpl->pageScaleFactor());
6647 EXPECT_FLOAT_EQ(1.2, webViewImpl->minimumPageScaleFactor());
6648 EXPECT_FLOAT_EQ(5.0, webViewImpl->maximumPageScaleFactor());
6651 TEST_P(ParameterizedWebFrameTest, FullscreenResizeWithTinyViewport)
6653 FakeCompositingWebViewClient client;
6654 registerMockedHttpURLLoad("viewport-tiny.html");
6655 FrameTestHelpers::WebViewHelper webViewHelper(this);
6656 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "viewport-tiny.html", true, 0, &client, configureAndroid);
6657 int viewportWidth = 384;
6658 int viewportHeight = 640;
6659 client.m_screenInfo.rect.width = viewportWidth;
6660 client.m_screenInfo.rect.height = viewportHeight;
6661 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6662 webViewImpl->layout();
6664 LayoutView* layoutView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutView();
6665 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
6666 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
6667 Fullscreen::from(*document).requestFullscreen(*document->documentElement(), Fullscreen::PrefixedRequest);
6668 webViewImpl->didEnterFullScreen();
6669 webViewImpl->layout();
6670 EXPECT_EQ(384, layoutView->logicalWidth().floor());
6671 EXPECT_EQ(640, layoutView->logicalHeight().floor());
6672 EXPECT_FLOAT_EQ(1.0, webViewImpl->pageScaleFactor());
6673 EXPECT_FLOAT_EQ(1.0, webViewImpl->minimumPageScaleFactor());
6674 EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
6676 viewportWidth = 640;
6677 viewportHeight = 384;
6678 client.m_screenInfo.rect.width = viewportWidth;
6679 client.m_screenInfo.rect.height = viewportHeight;
6680 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
6681 webViewImpl->layout();
6682 EXPECT_EQ(640, layoutView->logicalWidth().floor());
6683 EXPECT_EQ(384, layoutView->logicalHeight().floor());
6684 EXPECT_FLOAT_EQ(1.0, webViewImpl->pageScaleFactor());
6685 EXPECT_FLOAT_EQ(1.0, webViewImpl->minimumPageScaleFactor());
6686 EXPECT_FLOAT_EQ(1.0, webViewImpl->maximumPageScaleFactor());
6688 webViewImpl->didExitFullScreen();
6689 webViewImpl->layout();
6690 EXPECT_EQ(320, layoutView->logicalWidth().floor());
6691 EXPECT_EQ(192, layoutView->logicalHeight().floor());
6692 EXPECT_FLOAT_EQ(2, webViewImpl->pageScaleFactor());
6693 EXPECT_FLOAT_EQ(2, webViewImpl->minimumPageScaleFactor());
6694 EXPECT_FLOAT_EQ(5.0, webViewImpl->maximumPageScaleFactor());
6697 TEST_P(ParameterizedWebFrameTest, LayoutBlockPercentHeightDescendants)
6699 registerMockedHttpURLLoad("percent-height-descendants.html");
6700 FrameTestHelpers::WebViewHelper webViewHelper(this);
6701 webViewHelper.initializeAndLoad(m_baseURL + "percent-height-descendants.html");
6703 WebView* webView = webViewHelper.webView();
6704 webView->resize(WebSize(800, 800));
6705 webView->layout();
6707 Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
6708 LayoutBlock* container = toLayoutBlock(document->getElementById("container")->layoutObject());
6709 LayoutBox* percentHeightInAnonymous = toLayoutBox(document->getElementById("percent-height-in-anonymous")->layoutObject());
6710 LayoutBox* percentHeightDirectChild = toLayoutBox(document->getElementById("percent-height-direct-child")->layoutObject());
6712 EXPECT_TRUE(LayoutBlock::hasPercentHeightDescendant(percentHeightInAnonymous));
6713 EXPECT_TRUE(LayoutBlock::hasPercentHeightDescendant(percentHeightDirectChild));
6715 ASSERT_TRUE(container->percentHeightDescendants());
6716 ASSERT_TRUE(container->hasPercentHeightDescendants());
6717 EXPECT_EQ(2U, container->percentHeightDescendants()->size());
6718 EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightInAnonymous));
6719 EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightDirectChild));
6721 LayoutBlock* anonymousBlock = percentHeightInAnonymous->containingBlock();
6722 EXPECT_TRUE(anonymousBlock->isAnonymous());
6723 EXPECT_FALSE(anonymousBlock->hasPercentHeightDescendants());
6726 TEST_P(ParameterizedWebFrameTest, HasVisibleContentOnVisibleFrames)
6728 registerMockedHttpURLLoad("visible_frames.html");
6729 FrameTestHelpers::WebViewHelper webViewHelper(this);
6730 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "visible_frames.html");
6731 for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
6732 EXPECT_TRUE(frame->hasVisibleContent());
6736 TEST_P(ParameterizedWebFrameTest, HasVisibleContentOnHiddenFrames)
6738 registerMockedHttpURLLoad("hidden_frames.html");
6739 FrameTestHelpers::WebViewHelper webViewHelper(this);
6740 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "hidden_frames.html");
6741 for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
6742 EXPECT_FALSE(frame->hasVisibleContent());
6746 class ManifestChangeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6747 public:
6748 ManifestChangeWebFrameClient() : m_manifestChangeCount(0) { }
6749 void didChangeManifest(WebLocalFrame*) override
6751 ++m_manifestChangeCount;
6754 int manifestChangeCount() { return m_manifestChangeCount; }
6756 private:
6757 int m_manifestChangeCount;
6760 TEST_P(ParameterizedWebFrameTest, NotifyManifestChange)
6762 registerMockedHttpURLLoad("link-manifest-change.html");
6764 ManifestChangeWebFrameClient webFrameClient;
6765 FrameTestHelpers::WebViewHelper webViewHelper(this);
6766 webViewHelper.initializeAndLoad(m_baseURL + "link-manifest-change.html", true, &webFrameClient);
6768 EXPECT_EQ(14, webFrameClient.manifestChangeCount());
6771 static ResourcePtr<Resource> fetchManifest(Document* document, const KURL& url)
6773 FetchRequest fetchRequest = FetchRequest(ResourceRequest(url), FetchInitiatorInfo());
6774 fetchRequest.mutableResourceRequest().setRequestContext(WebURLRequest::RequestContextManifest);
6776 return RawResource::fetchSynchronously(fetchRequest, document->fetcher());
6779 TEST_P(ParameterizedWebFrameTest, ManifestFetch)
6781 registerMockedHttpURLLoad("foo.html");
6782 registerMockedHttpURLLoad("link-manifest-fetch.json");
6784 FrameTestHelpers::WebViewHelper webViewHelper(this);
6785 webViewHelper.initializeAndLoad(m_baseURL + "foo.html");
6786 Document* document = toWebLocalFrameImpl(webViewHelper.webViewImpl()->mainFrame())->frame()->document();
6788 ResourcePtr<Resource> resource = fetchManifest(document, toKURL(m_baseURL + "link-manifest-fetch.json"));
6790 EXPECT_TRUE(resource->isLoaded());
6793 TEST_P(ParameterizedWebFrameTest, ManifestCSPFetchAllow)
6795 URLTestHelpers::registerMockedURLLoad(toKURL(m_notBaseURL + "link-manifest-fetch.json"), "link-manifest-fetch.json");
6796 registerMockedHttpURLLoadWithCSP("foo.html", "manifest-src *");
6798 FrameTestHelpers::WebViewHelper webViewHelper(this);
6799 webViewHelper.initializeAndLoad(m_baseURL + "foo.html");
6800 Document* document = toWebLocalFrameImpl(webViewHelper.webViewImpl()->mainFrame())->frame()->document();
6802 ResourcePtr<Resource> resource = fetchManifest(document, toKURL(m_notBaseURL + "link-manifest-fetch.json"));
6804 EXPECT_TRUE(resource->isLoaded());
6807 TEST_P(ParameterizedWebFrameTest, ManifestCSPFetchSelf)
6809 URLTestHelpers::registerMockedURLLoad(toKURL(m_notBaseURL + "link-manifest-fetch.json"), "link-manifest-fetch.json");
6810 registerMockedHttpURLLoadWithCSP("foo.html", "manifest-src 'self'");
6812 FrameTestHelpers::WebViewHelper webViewHelper(this);
6813 webViewHelper.initializeAndLoad(m_baseURL + "foo.html");
6814 Document* document = toWebLocalFrameImpl(webViewHelper.webViewImpl()->mainFrame())->frame()->document();
6816 ResourcePtr<Resource> resource = fetchManifest(document, toKURL(m_notBaseURL + "link-manifest-fetch.json"));
6818 EXPECT_EQ(0, resource.get()); // Fetching resource wasn't allowed.
6821 TEST_P(ParameterizedWebFrameTest, ManifestCSPFetchSelfReportOnly)
6823 URLTestHelpers::registerMockedURLLoad(toKURL(m_notBaseURL + "link-manifest-fetch.json"), "link-manifest-fetch.json");
6824 registerMockedHttpURLLoadWithCSP("foo.html", "manifest-src 'self'", /* report only */ true);
6826 FrameTestHelpers::WebViewHelper webViewHelper(this);
6827 webViewHelper.initializeAndLoad(m_baseURL + "foo.html");
6828 Document* document = toWebLocalFrameImpl(webViewHelper.webViewImpl()->mainFrame())->frame()->document();
6830 ResourcePtr<Resource> resource = fetchManifest(document, toKURL(m_notBaseURL + "link-manifest-fetch.json"));
6832 EXPECT_TRUE(resource->isLoaded());
6835 TEST_P(ParameterizedWebFrameTest, ReloadBypassingCache)
6837 // Check that a reload ignoring cache on a frame will result in the cache
6838 // policy of the request being set to ReloadBypassingCache.
6839 registerMockedHttpURLLoad("foo.html");
6840 FrameTestHelpers::WebViewHelper webViewHelper(this);
6841 webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
6842 WebFrame* frame = webViewHelper.webView()->mainFrame();
6843 FrameTestHelpers::reloadFrameIgnoringCache(frame);
6844 EXPECT_EQ(WebURLRequest::ReloadBypassingCache, frame->dataSource()->request().cachePolicy());
6847 static void nodeImageTestValidation(const IntSize& referenceBitmapSize, DragImage* dragImage)
6849 // Prepare the reference bitmap.
6850 SkBitmap bitmap;
6851 bitmap.allocN32Pixels(referenceBitmapSize.width(), referenceBitmapSize.height());
6852 SkCanvas canvas(bitmap);
6853 canvas.drawColor(SK_ColorGREEN);
6855 EXPECT_EQ(referenceBitmapSize.width(), dragImage->size().width());
6856 EXPECT_EQ(referenceBitmapSize.height(), dragImage->size().height());
6857 const SkBitmap& dragBitmap = dragImage->bitmap();
6858 SkAutoLockPixels lockPixel(dragBitmap);
6859 EXPECT_EQ(0, memcmp(bitmap.getPixels(), dragBitmap.getPixels(), bitmap.getSize()));
6862 TEST_P(ParameterizedWebFrameTest, NodeImageTestCSSTransform)
6864 FrameTestHelpers::WebViewHelper webViewHelper(this);
6865 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-transform"));
6866 EXPECT_TRUE(dragImage);
6868 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
6871 TEST_P(ParameterizedWebFrameTest, NodeImageTestCSS3DTransform)
6873 FrameTestHelpers::WebViewHelper webViewHelper(this);
6874 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-3dtransform"));
6875 EXPECT_TRUE(dragImage);
6877 nodeImageTestValidation(IntSize(20, 40), dragImage.get());
6880 TEST_P(ParameterizedWebFrameTest, NodeImageTestInlineBlock)
6882 FrameTestHelpers::WebViewHelper webViewHelper(this);
6883 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-inlineblock"));
6884 EXPECT_TRUE(dragImage);
6886 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
6889 TEST_P(ParameterizedWebFrameTest, NodeImageTestFloatLeft)
6891 FrameTestHelpers::WebViewHelper webViewHelper(this);
6892 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-float-left-overflow-hidden"));
6893 EXPECT_TRUE(dragImage);
6895 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
6898 // Crashes on Android: http://crbug.com/403804
6899 #if OS(ANDROID)
6900 TEST_P(ParameterizedWebFrameTest, DISABLED_PrintingBasic)
6901 #else
6902 TEST_P(ParameterizedWebFrameTest, PrintingBasic)
6903 #endif
6905 FrameTestHelpers::WebViewHelper webViewHelper(this);
6906 webViewHelper.initializeAndLoad("data:text/html,Hello, world.");
6908 WebFrame* frame = webViewHelper.webView()->mainFrame();
6910 WebPrintParams printParams;
6911 printParams.printContentArea.width = 500;
6912 printParams.printContentArea.height = 500;
6914 int pageCount = frame->printBegin(printParams);
6915 EXPECT_EQ(1, pageCount);
6916 frame->printEnd();
6919 class ThemeColorTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6920 public:
6921 ThemeColorTestWebFrameClient()
6922 : m_didNotify(false)
6926 void reset()
6928 m_didNotify = false;
6931 bool didNotify() const
6933 return m_didNotify;
6936 private:
6937 virtual void didChangeThemeColor()
6939 m_didNotify = true;
6942 bool m_didNotify;
6945 TEST_P(ParameterizedWebFrameTest, ThemeColor)
6947 registerMockedHttpURLLoad("theme_color_test.html");
6948 FrameTestHelpers::WebViewHelper webViewHelper(this);
6949 ThemeColorTestWebFrameClient client;
6950 webViewHelper.initializeAndLoad(m_baseURL + "theme_color_test.html", true, &client);
6951 EXPECT_TRUE(client.didNotify());
6952 WebLocalFrameImpl* frame = webViewHelper.webViewImpl()->mainFrameImpl();
6953 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6954 // Change color by rgb.
6955 client.reset();
6956 frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'rgb(0, 0, 0)');"));
6957 EXPECT_TRUE(client.didNotify());
6958 EXPECT_EQ(0xff000000, frame->document().themeColor());
6959 // Change color by hsl.
6960 client.reset();
6961 frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'hsl(240,100%, 50%)');"));
6962 EXPECT_TRUE(client.didNotify());
6963 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6964 // Change of second theme-color meta tag will not change frame's theme
6965 // color.
6966 client.reset();
6967 frame->executeScript(WebScriptSource("document.getElementById('tc2').setAttribute('content', '#00FF00');"));
6968 EXPECT_TRUE(client.didNotify());
6969 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6972 // Make sure that an embedder-triggered detach with a remote frame parent
6973 // doesn't leave behind dangling pointers.
6974 TEST_P(ParameterizedWebFrameTest, EmbedderTriggeredDetachWithRemoteMainFrame)
6976 // FIXME: Refactor some of this logic into WebViewHelper to make it easier to
6977 // write tests with a top-level remote frame.
6978 FrameTestHelpers::TestWebViewClient viewClient;
6979 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
6980 WebView* view = WebView::create(&viewClient);
6981 view->setMainFrame(remoteClient.frame());
6982 FrameTestHelpers::TestWebFrameClient childFrameClient;
6983 WebLocalFrame* childFrame = view->mainFrame()->toWebRemoteFrame()->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient, nullptr);
6985 // Purposely keep the LocalFrame alive so it's the last thing to be destroyed.
6986 RefPtrWillBePersistent<Frame> childCoreFrame = toCoreFrame(childFrame);
6987 view->close();
6988 childCoreFrame.clear();
6991 class WebFrameSwapTest : public WebFrameTest {
6992 protected:
6993 WebFrameSwapTest()
6995 registerMockedHttpURLLoad("frame-a-b-c.html");
6996 registerMockedHttpURLLoad("subframe-a.html");
6997 registerMockedHttpURLLoad("subframe-b.html");
6998 registerMockedHttpURLLoad("subframe-c.html");
6999 registerMockedHttpURLLoad("subframe-hello.html");
7001 m_webViewHelper.initializeAndLoad(m_baseURL + "frame-a-b-c.html", true);
7004 void reset() { m_webViewHelper.reset(); }
7005 WebFrame* mainFrame() const { return m_webViewHelper.webView()->mainFrame(); }
7007 private:
7008 FrameTestHelpers::WebViewHelper m_webViewHelper;
7011 TEST_F(WebFrameSwapTest, SwapMainFrame)
7013 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, nullptr);
7014 mainFrame()->swap(remoteFrame);
7016 FrameTestHelpers::TestWebFrameClient client;
7017 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7018 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7019 remoteFrame->swap(localFrame);
7021 // Finally, make sure an embedder triggered load in the local frame swapped
7022 // back in works.
7023 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7024 std::string content = localFrame->contentAsText(1024).utf8();
7025 EXPECT_EQ("hello", content);
7027 // Manually reset to break WebViewHelper's dependency on the stack allocated
7028 // TestWebFrameClient.
7029 reset();
7030 remoteFrame->close();
7033 namespace {
7035 class SwapMainFrameWhenTitleChangesWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
7036 public:
7037 SwapMainFrameWhenTitleChangesWebFrameClient() {}
7038 ~SwapMainFrameWhenTitleChangesWebFrameClient() override {}
7040 void didReceiveTitle(WebLocalFrame* frame, const WebString&, WebTextDirection) override
7042 if (!frame->parent())
7043 frame->swap(WebRemoteFrame::create(WebTreeScopeType::Document, nullptr));
7047 } // anonymous namespace
7049 TEST_F(WebFrameTest, SwapMainFrameWhileLoading)
7051 SwapMainFrameWhenTitleChangesWebFrameClient frameClient;
7053 FrameTestHelpers::WebViewHelper webViewHelper;
7054 registerMockedHttpURLLoad("frame-a-b-c.html");
7055 registerMockedHttpURLLoad("subframe-a.html");
7056 registerMockedHttpURLLoad("subframe-b.html");
7057 registerMockedHttpURLLoad("subframe-c.html");
7058 registerMockedHttpURLLoad("subframe-hello.html");
7060 webViewHelper.initializeAndLoad(m_baseURL + "frame-a-b-c.html", true, &frameClient);
7063 void swapAndVerifyFirstChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
7065 SCOPED_TRACE(message);
7066 parent->firstChild()->swap(newChild);
7068 EXPECT_EQ(newChild, parent->firstChild());
7069 EXPECT_EQ(newChild->parent(), parent);
7070 EXPECT_EQ(newChild, parent->lastChild()->previousSibling()->previousSibling());
7071 EXPECT_EQ(newChild->nextSibling(), parent->lastChild()->previousSibling());
7074 TEST_F(WebFrameSwapTest, SwapFirstChild)
7076 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
7077 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient);
7078 swapAndVerifyFirstChildConsistency("local->remote", mainFrame(), remoteFrame);
7080 FrameTestHelpers::TestWebFrameClient client;
7081 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7082 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7083 swapAndVerifyFirstChildConsistency("remote->local", mainFrame(), localFrame);
7085 // FIXME: This almost certainly fires more load events on the iframe element
7086 // than it should.
7087 // Finally, make sure an embedder triggered load in the local frame swapped
7088 // back in works.
7089 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7090 std::string content = localFrame->contentAsText(1024).utf8();
7091 EXPECT_EQ("hello", content);
7093 // Manually reset to break WebViewHelper's dependency on the stack allocated
7094 // TestWebFrameClient.
7095 reset();
7096 remoteFrame->close();
7099 void swapAndVerifyMiddleChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
7101 SCOPED_TRACE(message);
7102 parent->firstChild()->nextSibling()->swap(newChild);
7104 EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
7105 EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
7106 EXPECT_EQ(newChild->parent(), parent);
7107 EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
7108 EXPECT_EQ(newChild->previousSibling(), parent->firstChild());
7109 EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
7110 EXPECT_EQ(newChild->nextSibling(), parent->lastChild());
7113 TEST_F(WebFrameSwapTest, SwapMiddleChild)
7115 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
7116 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient);
7117 swapAndVerifyMiddleChildConsistency("local->remote", mainFrame(), remoteFrame);
7119 FrameTestHelpers::TestWebFrameClient client;
7120 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7121 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7122 swapAndVerifyMiddleChildConsistency("remote->local", mainFrame(), localFrame);
7124 // FIXME: This almost certainly fires more load events on the iframe element
7125 // than it should.
7126 // Finally, make sure an embedder triggered load in the local frame swapped
7127 // back in works.
7128 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7129 std::string content = localFrame->contentAsText(1024).utf8();
7130 EXPECT_EQ("hello", content);
7132 // Manually reset to break WebViewHelper's dependency on the stack allocated
7133 // TestWebFrameClient.
7134 reset();
7135 remoteFrame->close();
7138 void swapAndVerifyLastChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
7140 SCOPED_TRACE(message);
7141 parent->lastChild()->swap(newChild);
7143 EXPECT_EQ(newChild, parent->lastChild());
7144 EXPECT_EQ(newChild->parent(), parent);
7145 EXPECT_EQ(newChild, parent->firstChild()->nextSibling()->nextSibling());
7146 EXPECT_EQ(newChild->previousSibling(), parent->firstChild()->nextSibling());
7149 TEST_F(WebFrameSwapTest, SwapLastChild)
7151 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
7152 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient);
7153 swapAndVerifyLastChildConsistency("local->remote", mainFrame(), remoteFrame);
7155 FrameTestHelpers::TestWebFrameClient client;
7156 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7157 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7158 swapAndVerifyLastChildConsistency("remote->local", mainFrame(), localFrame);
7160 // FIXME: This almost certainly fires more load events on the iframe element
7161 // than it should.
7162 // Finally, make sure an embedder triggered load in the local frame swapped
7163 // back in works.
7164 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7165 std::string content = localFrame->contentAsText(1024).utf8();
7166 EXPECT_EQ("hello", content);
7168 // Manually reset to break WebViewHelper's dependency on the stack allocated
7169 // TestWebFrameClient.
7170 reset();
7171 remoteFrame->close();
7174 void swapAndVerifySubframeConsistency(const char* const message, WebFrame* oldFrame, WebFrame* newFrame)
7176 SCOPED_TRACE(message);
7178 EXPECT_TRUE(oldFrame->firstChild());
7179 oldFrame->swap(newFrame);
7181 EXPECT_FALSE(newFrame->firstChild());
7182 EXPECT_FALSE(newFrame->lastChild());
7185 TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren)
7187 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient1;
7188 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient1);
7189 WebFrame* targetFrame = mainFrame()->firstChild()->nextSibling();
7190 EXPECT_TRUE(targetFrame);
7191 swapAndVerifySubframeConsistency("local->remote", targetFrame, remoteFrame);
7193 targetFrame = mainFrame()->firstChild()->nextSibling();
7194 EXPECT_TRUE(targetFrame);
7196 // Create child frames in the target frame before testing the swap.
7197 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient2;
7198 WebRemoteFrame* childRemoteFrame = remoteFrame->createRemoteChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &remoteFrameClient2);
7200 FrameTestHelpers::TestWebFrameClient client;
7201 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7202 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7203 swapAndVerifySubframeConsistency("remote->local", targetFrame, localFrame);
7205 // FIXME: This almost certainly fires more load events on the iframe element
7206 // than it should.
7207 // Finally, make sure an embedder triggered load in the local frame swapped
7208 // back in works.
7209 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7210 std::string content = localFrame->contentAsText(1024).utf8();
7211 EXPECT_EQ("hello", content);
7213 // Manually reset to break WebViewHelper's dependency on the stack allocated
7214 // TestWebFrameClient.
7215 reset();
7216 remoteFrame->close();
7217 childRemoteFrame->close();
7220 TEST_F(WebFrameSwapTest, SwapPreservesGlobalContext)
7222 v8::HandleScope scope(v8::Isolate::GetCurrent());
7223 v8::Local<v8::Value> windowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window"));
7224 ASSERT_TRUE(windowTop->IsObject());
7225 v8::Local<v8::Value> originalWindow = mainFrame()->executeScriptAndReturnValue(WebScriptSource(
7226 "document.querySelector('#frame2').contentWindow;"));
7227 ASSERT_TRUE(originalWindow->IsObject());
7229 // Make sure window reference stays the same when swapping to a remote frame.
7230 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7231 WebRemoteFrame* remoteFrame = remoteClient.frame();
7232 WebFrame* targetFrame = mainFrame()->firstChild()->nextSibling();
7233 targetFrame->swap(remoteFrame);
7234 remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7235 v8::Local<v8::Value> remoteWindow = mainFrame()->executeScriptAndReturnValue(WebScriptSource(
7236 "document.querySelector('#frame2').contentWindow;"));
7237 EXPECT_TRUE(originalWindow->StrictEquals(remoteWindow));
7238 // Check that its view is consistent with the world.
7239 v8::Local<v8::Value> remoteWindowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource(
7240 "document.querySelector('#frame2').contentWindow.top;"));
7241 EXPECT_TRUE(windowTop->StrictEquals(remoteWindowTop));
7243 // Now check that remote -> local works too, since it goes through a different code path.
7244 FrameTestHelpers::TestWebFrameClient client;
7245 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7246 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7247 remoteFrame->swap(localFrame);
7248 v8::Local<v8::Value> localWindow = mainFrame()->executeScriptAndReturnValue(WebScriptSource(
7249 "document.querySelector('#frame2').contentWindow;"));
7250 EXPECT_TRUE(originalWindow->StrictEquals(localWindow));
7251 v8::Local<v8::Value> localWindowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource(
7252 "document.querySelector('#frame2').contentWindow.top;"));
7253 EXPECT_TRUE(windowTop->StrictEquals(localWindowTop));
7255 // Manually reset to break WebViewHelper's dependency on the stack allocated
7256 // TestWebFrameClient.
7257 reset();
7260 TEST_F(WebFrameSwapTest, SwapInitializesGlobal)
7262 v8::HandleScope scope(v8::Isolate::GetCurrent());
7264 v8::Local<v8::Value> windowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window"));
7265 ASSERT_TRUE(windowTop->IsObject());
7267 v8::Local<v8::Value> lastChild = mainFrame()->executeScriptAndReturnValue(WebScriptSource("saved = window[2]"));
7268 ASSERT_TRUE(lastChild->IsObject());
7270 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7271 WebRemoteFrame* remoteFrame = remoteClient.frame();
7272 mainFrame()->lastChild()->swap(remoteFrame);
7273 remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7274 v8::Local<v8::Value> remoteWindowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource("saved.top"));
7275 EXPECT_TRUE(remoteWindowTop->IsObject());
7276 EXPECT_TRUE(windowTop->StrictEquals(remoteWindowTop));
7278 FrameTestHelpers::TestWebFrameClient client;
7279 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7280 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7281 remoteFrame->swap(localFrame);
7282 v8::Local<v8::Value> localWindowTop = mainFrame()->executeScriptAndReturnValue(WebScriptSource("saved.top"));
7283 EXPECT_TRUE(localWindowTop->IsObject());
7284 EXPECT_TRUE(windowTop->StrictEquals(localWindowTop));
7286 reset();
7289 TEST_F(WebFrameSwapTest, RemoteFramesAreIndexable)
7291 v8::HandleScope scope(v8::Isolate::GetCurrent());
7293 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7294 WebRemoteFrame* remoteFrame = remoteClient.frame();
7295 mainFrame()->lastChild()->swap(remoteFrame);
7296 remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7297 v8::Local<v8::Value> remoteWindow = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window[2]"));
7298 EXPECT_TRUE(remoteWindow->IsObject());
7299 v8::Local<v8::Value> windowLength = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window.length"));
7300 ASSERT_TRUE(windowLength->IsInt32());
7301 EXPECT_EQ(3, windowLength.As<v8::Int32>()->Value());
7303 reset();
7306 TEST_F(WebFrameSwapTest, RemoteFrameLengthAccess)
7308 v8::HandleScope scope(v8::Isolate::GetCurrent());
7310 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7311 WebRemoteFrame* remoteFrame = remoteClient.frame();
7312 mainFrame()->lastChild()->swap(remoteFrame);
7313 remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7314 v8::Local<v8::Value> remoteWindowLength = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window[2].length"));
7315 ASSERT_TRUE(remoteWindowLength->IsInt32());
7316 EXPECT_EQ(0, remoteWindowLength.As<v8::Int32>()->Value());
7318 reset();
7321 TEST_F(WebFrameSwapTest, RemoteWindowNamedAccess)
7323 v8::HandleScope scope(v8::Isolate::GetCurrent());
7325 // FIXME: Once OOPIF unit test infrastructure is in place, test that named
7326 // window access on a remote window works. For now, just test that accessing
7327 // a named property doesn't crash.
7328 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7329 WebRemoteFrame* remoteFrame = remoteClient.frame();
7330 mainFrame()->lastChild()->swap(remoteFrame);
7331 remoteFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7332 v8::Local<v8::Value> remoteWindowProperty = mainFrame()->executeScriptAndReturnValue(WebScriptSource("window[2].foo"));
7333 EXPECT_TRUE(remoteWindowProperty.IsEmpty());
7335 reset();
7338 // TODO(alexmos, dcheng): This test and some other OOPIF tests use
7339 // very little of the test fixture support in WebFrameSwapTest. We should
7340 // clean these tests up.
7341 TEST_F(WebFrameSwapTest, FramesOfRemoteParentAreIndexable)
7343 v8::HandleScope scope(v8::Isolate::GetCurrent());
7345 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7346 WebRemoteFrame* remoteParentFrame = remoteClient.frame();
7347 mainFrame()->swap(remoteParentFrame);
7348 remoteParentFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7350 FrameTestHelpers::TestWebFrameClient childFrameClient;
7351 WebLocalFrame* childFrame = remoteParentFrame->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient, nullptr);
7352 FrameTestHelpers::loadFrame(childFrame, m_baseURL + "subframe-hello.html");
7354 v8::Local<v8::Value> window = childFrame->executeScriptAndReturnValue(WebScriptSource("window"));
7355 v8::Local<v8::Value> childOfRemoteParent = childFrame->executeScriptAndReturnValue(WebScriptSource("parent.frames[0]"));
7356 EXPECT_TRUE(childOfRemoteParent->IsObject());
7357 EXPECT_TRUE(window->StrictEquals(childOfRemoteParent));
7359 v8::Local<v8::Value> windowLength = childFrame->executeScriptAndReturnValue(WebScriptSource("parent.frames.length"));
7360 ASSERT_TRUE(windowLength->IsInt32());
7361 EXPECT_EQ(1, windowLength.As<v8::Int32>()->Value());
7363 // Manually reset to break WebViewHelper's dependency on the stack allocated clients.
7364 reset();
7367 // Check that frames with a remote parent don't crash while accessing window.frameElement.
7368 TEST_F(WebFrameSwapTest, FrameElementInFramesWithRemoteParent)
7370 v8::HandleScope scope(v8::Isolate::GetCurrent());
7372 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7373 WebRemoteFrame* remoteParentFrame = remoteClient.frame();
7374 mainFrame()->swap(remoteParentFrame);
7375 remoteParentFrame->setReplicatedOrigin(SecurityOrigin::createUnique());
7377 FrameTestHelpers::TestWebFrameClient childFrameClient;
7378 WebLocalFrame* childFrame = remoteParentFrame->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient, nullptr);
7379 FrameTestHelpers::loadFrame(childFrame, m_baseURL + "subframe-hello.html");
7381 v8::Local<v8::Value> frameElement = childFrame->executeScriptAndReturnValue(WebScriptSource("window.frameElement"));
7382 // frameElement shouldn't be accessible cross-origin.
7383 EXPECT_TRUE(frameElement.IsEmpty());
7385 // Manually reset to break WebViewHelper's dependency on the stack allocated clients.
7386 reset();
7389 class RemoteToLocalSwapWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
7390 public:
7391 explicit RemoteToLocalSwapWebFrameClient(WebRemoteFrame* remoteFrame)
7392 : m_historyCommitType(WebHistoryInertCommit)
7393 , m_remoteFrame(remoteFrame)
7397 void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType historyCommitType) override
7399 m_historyCommitType = historyCommitType;
7400 m_remoteFrame->swap(frame);
7403 WebHistoryCommitType historyCommitType() const { return m_historyCommitType; }
7405 WebHistoryCommitType m_historyCommitType;
7406 WebRemoteFrame* m_remoteFrame;
7409 // The commit type should be Initial if we are swapping a RemoteFrame to a
7410 // LocalFrame as it is first being created. This happens when another frame
7411 // exists in the same process, such that we create the RemoteFrame before the
7412 // first navigation occurs.
7413 TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterNewRemoteToLocalSwap)
7415 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
7416 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient);
7417 WebFrame* targetFrame = mainFrame()->firstChild();
7418 ASSERT_TRUE(targetFrame);
7419 targetFrame->swap(remoteFrame);
7420 ASSERT_TRUE(mainFrame()->firstChild());
7421 ASSERT_EQ(mainFrame()->firstChild(), remoteFrame);
7423 RemoteToLocalSwapWebFrameClient client(remoteFrame);
7424 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7425 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7426 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7427 EXPECT_EQ(WebInitialCommitInChildFrame, client.historyCommitType());
7429 // Manually reset to break WebViewHelper's dependency on the stack allocated
7430 // TestWebFrameClient.
7431 reset();
7432 remoteFrame->close();
7435 // The commit type should be Standard if we are swapping a RemoteFrame to a
7436 // LocalFrame after commits have already happened in the frame. The browser
7437 // process will inform us via setCommittedFirstRealLoad.
7438 TEST_F(WebFrameSwapTest, HistoryCommitTypeAfterExistingRemoteToLocalSwap)
7440 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
7441 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(WebTreeScopeType::Document, &remoteFrameClient);
7442 WebFrame* targetFrame = mainFrame()->firstChild();
7443 ASSERT_TRUE(targetFrame);
7444 targetFrame->swap(remoteFrame);
7445 ASSERT_TRUE(mainFrame()->firstChild());
7446 ASSERT_EQ(mainFrame()->firstChild(), remoteFrame);
7448 RemoteToLocalSwapWebFrameClient client(remoteFrame);
7449 WebLocalFrame* localFrame = WebLocalFrame::create(WebTreeScopeType::Document, &client);
7450 localFrame->initializeToReplaceRemoteFrame(remoteFrame, "", WebSandboxFlags::None);
7451 localFrame->setCommittedFirstRealLoad();
7452 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
7453 EXPECT_EQ(WebStandardCommit, client.historyCommitType());
7455 // Manually reset to break WebViewHelper's dependency on the stack allocated
7456 // TestWebFrameClient.
7457 reset();
7458 remoteFrame->close();
7461 class RemoteNavigationClient : public FrameTestHelpers::TestWebRemoteFrameClient {
7462 public:
7463 void navigate(const WebURLRequest& request, bool shouldReplaceCurrentEntry) override
7465 m_lastRequest = request;
7468 const WebURLRequest& lastRequest() const { return m_lastRequest; }
7470 private:
7471 WebURLRequest m_lastRequest;
7474 TEST_F(WebFrameSwapTest, NavigateRemoteFrameViaLocation)
7476 RemoteNavigationClient client;
7477 WebRemoteFrame* remoteFrame = client.frame();
7478 WebFrame* targetFrame = mainFrame()->firstChild();
7479 ASSERT_TRUE(targetFrame);
7480 targetFrame->swap(remoteFrame);
7481 ASSERT_TRUE(mainFrame()->firstChild());
7482 ASSERT_EQ(mainFrame()->firstChild(), remoteFrame);
7484 remoteFrame->setReplicatedOrigin(WebSecurityOrigin::createFromString("http://127.0.0.1"));
7485 mainFrame()->executeScript(WebScriptSource(
7486 "document.getElementsByTagName('iframe')[0].contentWindow.location = 'data:text/html,hi'"));
7487 ASSERT_FALSE(client.lastRequest().isNull());
7488 EXPECT_EQ(WebURL(toKURL("data:text/html,hi")), client.lastRequest().url());
7490 // Manually reset to break WebViewHelper's dependency on the stack allocated
7491 // TestWebFrameClient.
7492 reset();
7495 TEST_F(WebFrameSwapTest, WindowOpenOnRemoteFrame)
7497 RemoteNavigationClient remoteClient;
7498 WebRemoteFrame* remoteFrame = remoteClient.frame();
7499 mainFrame()->firstChild()->swap(remoteFrame);
7500 remoteFrame->setReplicatedOrigin(WebSecurityOrigin::createFromString("http://127.0.0.1"));
7502 ASSERT_TRUE(mainFrame()->isWebLocalFrame());
7503 ASSERT_TRUE(mainFrame()->firstChild()->isWebRemoteFrame());
7504 LocalDOMWindow* mainWindow = toWebLocalFrameImpl(mainFrame())->frame()->localDOMWindow();
7506 KURL destination = toKURL("data:text/html:destination");
7507 mainWindow->open(destination.string(), "frame1", "", mainWindow, mainWindow);
7508 ASSERT_FALSE(remoteClient.lastRequest().isNull());
7509 EXPECT_EQ(remoteClient.lastRequest().url(), WebURL(destination));
7511 // Pointing a named frame to an empty URL should just return a reference to
7512 // the frame's window without navigating it.
7513 RefPtrWillBeRawPtr<DOMWindow> result = mainWindow->open("", "frame1", "", mainWindow, mainWindow);
7514 EXPECT_EQ(remoteClient.lastRequest().url(), WebURL(destination));
7515 EXPECT_EQ(result, toCoreFrame(remoteFrame)->domWindow());
7517 reset();
7520 class RemoteWindowCloseClient : public FrameTestHelpers::TestWebViewClient {
7521 public:
7522 RemoteWindowCloseClient()
7523 : m_closed(false)
7527 void closeWidgetSoon() override
7529 m_closed = true;
7532 bool closed() const { return m_closed; }
7534 private:
7535 bool m_closed;
7538 TEST_F(WebFrameTest, WindowOpenRemoteClose)
7540 FrameTestHelpers::WebViewHelper mainWebView;
7541 mainWebView.initialize(true);
7543 // Create a remote window that will be closed later in the test.
7544 RemoteWindowCloseClient viewClient;
7545 FrameTestHelpers::TestWebRemoteFrameClient frameClient;
7546 WebRemoteFrame* webRemoteFrame = frameClient.frame();
7548 WebView* view = WebView::create(&viewClient);
7549 view->setMainFrame(webRemoteFrame);
7550 view->mainFrame()->setOpener(mainWebView.webView()->mainFrame());
7551 webRemoteFrame->setReplicatedOrigin(WebSecurityOrigin::createFromString("http://127.0.0.1"));
7553 LocalFrame* localFrame = toLocalFrame(toCoreFrame(mainWebView.webView()->mainFrame()));
7554 RemoteFrame* remoteFrame = toRemoteFrame(toCoreFrame(frameClient.frame()));
7556 // Attempt to close the window, which should fail as it isn't opened
7557 // by a script.
7558 remoteFrame->domWindow()->close(localFrame->document());
7559 EXPECT_FALSE(viewClient.closed());
7561 // Marking it as opened by a script should now allow it to be closed.
7562 remoteFrame->page()->setOpenedByDOM();
7563 remoteFrame->domWindow()->close(localFrame->document());
7564 EXPECT_TRUE(viewClient.closed());
7566 view->close();
7569 TEST_F(WebFrameTest, NavigateRemoteToLocalWithOpener)
7571 FrameTestHelpers::WebViewHelper mainWebView;
7572 mainWebView.initialize(true);
7573 WebFrame* mainFrame = mainWebView.webView()->mainFrame();
7575 // Create a popup with a remote frame and set its opener to the main frame.
7576 FrameTestHelpers::TestWebViewClient popupViewClient;
7577 WebView* popupView = WebView::create(&popupViewClient);
7578 FrameTestHelpers::TestWebRemoteFrameClient popupRemoteClient;
7579 WebRemoteFrame* popupRemoteFrame = popupRemoteClient.frame();
7580 popupView->setMainFrame(popupRemoteFrame);
7581 popupRemoteFrame->setOpener(mainFrame);
7582 popupRemoteFrame->setReplicatedOrigin(WebSecurityOrigin::createFromString("http://foo.com"));
7583 EXPECT_FALSE(mainFrame->securityOrigin().canAccess(popupView->mainFrame()->securityOrigin()));
7585 // Do a remote-to-local swap in the popup.
7586 FrameTestHelpers::TestWebFrameClient popupLocalClient;
7587 WebLocalFrame* popupLocalFrame = WebLocalFrame::create(WebTreeScopeType::Document, &popupLocalClient);
7588 popupLocalFrame->initializeToReplaceRemoteFrame(popupRemoteFrame, "", WebSandboxFlags::None);
7589 popupRemoteFrame->swap(popupLocalFrame);
7591 // The initial document created during the remote-to-local swap should have
7592 // inherited its opener's SecurityOrigin.
7593 EXPECT_TRUE(mainFrame->securityOrigin().canAccess(popupView->mainFrame()->securityOrigin()));
7595 popupView->close();
7598 class CommitTypeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
7599 public:
7600 explicit CommitTypeWebFrameClient()
7601 : m_historyCommitType(WebHistoryInertCommit)
7605 void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType historyCommitType) override
7607 m_historyCommitType = historyCommitType;
7610 WebHistoryCommitType historyCommitType() const { return m_historyCommitType; }
7612 private:
7613 WebHistoryCommitType m_historyCommitType;
7616 TEST_P(ParameterizedWebFrameTest, RemoteFrameInitialCommitType)
7618 FrameTestHelpers::TestWebViewClient viewClient;
7619 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7620 WebView* view = WebView::create(&viewClient);
7621 view->setMainFrame(remoteClient.frame());
7622 toRemoteFrame(toCoreFrame(view->mainFrame()))->securityContext()->setReplicatedOrigin(SecurityOrigin::create(toKURL(m_baseURL)));
7624 // If an iframe has a remote main frame, ensure the inital commit is correctly identified as WebInitialCommitInChildFrame.
7625 CommitTypeWebFrameClient childFrameClient;
7626 WebLocalFrame* childFrame = view->mainFrame()->toWebRemoteFrame()->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient, nullptr);
7627 registerMockedHttpURLLoad("foo.html");
7628 FrameTestHelpers::loadFrame(childFrame, m_baseURL + "foo.html");
7629 EXPECT_EQ(WebInitialCommitInChildFrame, childFrameClient.historyCommitType());
7630 view->close();
7633 class GestureEventTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
7634 public:
7635 GestureEventTestWebViewClient() : m_didHandleGestureEvent(false) { }
7636 void didHandleGestureEvent(const WebGestureEvent& event, bool eventCancelled) override { m_didHandleGestureEvent = true; }
7637 bool didHandleGestureEvent() const { return m_didHandleGestureEvent; }
7639 private:
7640 bool m_didHandleGestureEvent;
7643 TEST_P(ParameterizedWebFrameTest, FrameWidgetTest)
7645 FrameTestHelpers::TestWebViewClient viewClient;
7646 WebView* view = WebView::create(&viewClient);
7648 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7649 view->setMainFrame(remoteClient.frame());
7651 FrameTestHelpers::TestWebFrameClient childFrameClient;
7652 WebLocalFrame* childFrame = view->mainFrame()->toWebRemoteFrame()->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient, nullptr);
7654 GestureEventTestWebViewClient childViewClient;
7655 WebFrameWidget* widget = WebFrameWidget::create(&childViewClient, childFrame);
7657 view->resize(WebSize(1000, 1000));
7658 view->layout();
7660 widget->handleInputEvent(fatTap(20, 20));
7661 EXPECT_TRUE(childViewClient.didHandleGestureEvent());
7663 widget->close();
7664 view->close();
7667 class MockDocumentThreadableLoaderClient : public DocumentThreadableLoaderClient {
7668 public:
7669 MockDocumentThreadableLoaderClient() : m_failed(false) { }
7670 void didFail(const ResourceError&) override { m_failed = true;}
7672 void reset() { m_failed = false; }
7673 bool failed() { return m_failed; }
7675 bool m_failed;
7678 // FIXME: This would be better as a unittest on DocumentThreadableLoader but it
7679 // requires spin-up of a frame. It may be possible to remove that requirement
7680 // and convert it to a unittest.
7681 TEST_P(ParameterizedWebFrameTest, LoaderOriginAccess)
7683 FrameTestHelpers::WebViewHelper webViewHelper(this);
7684 webViewHelper.initializeAndLoad("about:blank");
7686 SchemeRegistry::registerURLSchemeAsDisplayIsolated("chrome");
7688 // Cross-origin request.
7689 KURL resourceUrl(ParsedURLString, "chrome://test.pdf");
7690 registerMockedChromeURLLoad("test.pdf");
7692 RefPtrWillBeRawPtr<LocalFrame> frame(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame()));
7694 MockDocumentThreadableLoaderClient client;
7695 ThreadableLoaderOptions options;
7697 // First try to load the request with regular access. Should fail.
7698 options.crossOriginRequestPolicy = UseAccessControl;
7699 ResourceLoaderOptions resourceLoaderOptions;
7700 DocumentThreadableLoader::loadResourceSynchronously(
7701 *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
7702 EXPECT_TRUE(client.failed());
7704 client.reset();
7705 // Try to load the request with cross origin access. Should succeed.
7706 options.crossOriginRequestPolicy = AllowCrossOriginRequests;
7707 DocumentThreadableLoader::loadResourceSynchronously(
7708 *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
7709 EXPECT_FALSE(client.failed());
7712 TEST_P(ParameterizedWebFrameTest, DetachRemoteFrame)
7714 FrameTestHelpers::TestWebViewClient viewClient;
7715 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7716 WebView* view = WebView::create(&viewClient);
7717 view->setMainFrame(remoteClient.frame());
7718 FrameTestHelpers::TestWebRemoteFrameClient childFrameClient;
7719 WebRemoteFrame* childFrame = view->mainFrame()->toWebRemoteFrame()->createRemoteChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &childFrameClient);
7720 childFrame->detach();
7721 view->close();
7722 childFrame->close();
7725 class TestConsoleMessageWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
7726 public:
7727 virtual void didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine, const WebString& stackTrace)
7729 messages.push_back(message);
7732 std::vector<WebConsoleMessage> messages;
7735 TEST_P(ParameterizedWebFrameTest, CrossDomainAccessErrorsUseCallingWindow)
7737 registerMockedHttpURLLoad("hidden_frames.html");
7738 registerMockedChromeURLLoad("hello_world.html");
7740 FrameTestHelpers::WebViewHelper webViewHelper(this);
7741 TestConsoleMessageWebFrameClient webFrameClient;
7742 FrameTestHelpers::TestWebViewClient webViewClient;
7743 webViewHelper.initializeAndLoad(m_baseURL + "hidden_frames.html", true, &webFrameClient, &webViewClient);
7745 // Create another window with a cross-origin page, and point its opener to
7746 // first window.
7747 FrameTestHelpers::WebViewHelper popupWebViewHelper(this);
7748 TestConsoleMessageWebFrameClient popupWebFrameClient;
7749 WebView* popupView = popupWebViewHelper.initializeAndLoad(m_chromeURL + "hello_world.html", true, &popupWebFrameClient);
7750 popupView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
7752 // Attempt a blocked navigation of an opener's subframe, and ensure that
7753 // the error shows up on the popup (calling) window's console, rather than
7754 // the target window.
7755 popupView->mainFrame()->executeScript(WebScriptSource("opener.frames[1].location.href='data:text/html,foo'"));
7756 EXPECT_TRUE(webFrameClient.messages.empty());
7757 ASSERT_EQ(1u, popupWebFrameClient.messages.size());
7758 EXPECT_TRUE(std::string::npos != popupWebFrameClient.messages[0].text.utf8().find("Unsafe JavaScript attempt to initiate navigation"));
7760 // Try setting a cross-origin iframe element's source to a javascript: URL,
7761 // and check that this error is also printed on the calling window.
7762 popupView->mainFrame()->executeScript(WebScriptSource("opener.document.querySelectorAll('iframe')[1].src='javascript:alert()'"));
7763 EXPECT_TRUE(webFrameClient.messages.empty());
7764 ASSERT_EQ(2u, popupWebFrameClient.messages.size());
7765 EXPECT_TRUE(std::string::npos != popupWebFrameClient.messages[1].text.utf8().find("Blocked a frame"));
7767 // Manually reset to break WebViewHelpers' dependencies on the stack
7768 // allocated WebFrameClients.
7769 webViewHelper.reset();
7770 popupWebViewHelper.reset();
7773 class DeviceEmulationTest : public ParameterizedWebFrameTest {
7774 protected:
7775 DeviceEmulationTest()
7776 : m_webViewHelper(this)
7778 registerMockedHttpURLLoad("device_emulation.html");
7779 m_client.m_screenInfo.deviceScaleFactor = 1;
7780 m_webViewHelper.initializeAndLoad(m_baseURL + "device_emulation.html", true, 0, &m_client);
7783 void testResize(const WebSize size, const String& expectedSize)
7785 m_client.m_screenInfo.rect = WebRect(0, 0, size.width, size.height);
7786 m_client.m_screenInfo.availableRect = m_client.m_screenInfo.rect;
7787 m_webViewHelper.webView()->resize(size);
7788 m_webViewHelper.webView()->layout();
7789 EXPECT_EQ(expectedSize, dumpSize("test"));
7792 String dumpSize(const String& id)
7794 String code = "dumpSize('" + id + "')";
7795 v8::HandleScope scope(v8::Isolate::GetCurrent());
7796 ScriptExecutionCallbackHelper callbackHelper(m_webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
7797 m_webViewHelper.webView()->mainFrame()->toWebLocalFrame()->requestExecuteScriptAndReturnValue(WebScriptSource(WebString(code)), false, &callbackHelper);
7798 runPendingTasks();
7799 EXPECT_TRUE(callbackHelper.didComplete());
7800 return callbackHelper.stringValue();
7803 FixedLayoutTestWebViewClient m_client;
7804 FrameTestHelpers::WebViewHelper m_webViewHelper;
7807 INSTANTIATE_TEST_CASE_P(All, DeviceEmulationTest, ::testing::Values(
7808 ParameterizedWebFrameTestConfig::Default,
7809 ParameterizedWebFrameTestConfig::RootLayerScrolls));
7811 TEST_P(DeviceEmulationTest, DeviceSizeInvalidatedOnResize)
7813 WebDeviceEmulationParams params;
7814 params.screenPosition = WebDeviceEmulationParams::Mobile;
7815 m_webViewHelper.webView()->enableDeviceEmulation(params);
7817 testResize(WebSize(700, 500), "300x300");
7818 testResize(WebSize(710, 500), "400x300");
7819 testResize(WebSize(690, 500), "200x300");
7820 testResize(WebSize(700, 510), "300x400");
7821 testResize(WebSize(700, 490), "300x200");
7822 testResize(WebSize(710, 510), "400x400");
7823 testResize(WebSize(690, 490), "200x200");
7824 testResize(WebSize(800, 600), "400x400");
7826 m_webViewHelper.webView()->disableDeviceEmulation();
7829 TEST_P(DeviceEmulationTest, PointerAndHoverTypes)
7831 WebDeviceEmulationParams params;
7832 params.screenPosition = WebDeviceEmulationParams::Mobile;
7833 m_webViewHelper.webView()->enableDeviceEmulation(params);
7834 EXPECT_EQ("20x20", dumpSize("pointer"));
7835 m_webViewHelper.webView()->disableDeviceEmulation();
7838 class WebLocalFrameScope final {
7839 public:
7840 WebLocalFrameScope(WebLocalFrame* localFrame)
7841 : m_localFrame(localFrame)
7845 operator WebLocalFrame*() const
7847 return m_localFrame;
7850 WebLocalFrame* operator->() const
7852 return m_localFrame;
7855 ~WebLocalFrameScope()
7857 m_localFrame->close();
7859 private:
7860 WebLocalFrame* m_localFrame;
7864 TEST_P(ParameterizedWebFrameTest, CreateLocalChildWithPreviousSibling)
7866 FrameTestHelpers::TestWebViewClient viewClient;
7867 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7868 WebView* view = WebView::create(&viewClient);
7869 view->setMainFrame(remoteClient.frame());
7870 WebRemoteFrame* parent = view->mainFrame()->toWebRemoteFrame();
7872 WebLocalFrameScope secondFrame = parent->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, nullptr, nullptr);
7873 WebLocalFrameScope fourthFrame = parent->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, nullptr, secondFrame);
7874 WebLocalFrameScope thirdFrame = parent->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, nullptr, secondFrame);
7875 WebLocalFrameScope firstFrame = parent->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, nullptr, nullptr);
7877 EXPECT_EQ(firstFrame, parent->firstChild());
7878 EXPECT_EQ(nullptr, firstFrame->previousSibling());
7879 EXPECT_EQ(secondFrame, firstFrame->nextSibling());
7881 EXPECT_EQ(firstFrame, secondFrame->previousSibling());
7882 EXPECT_EQ(thirdFrame, secondFrame->nextSibling());
7884 EXPECT_EQ(secondFrame, thirdFrame->previousSibling());
7885 EXPECT_EQ(fourthFrame, thirdFrame->nextSibling());
7887 EXPECT_EQ(thirdFrame, fourthFrame->previousSibling());
7888 EXPECT_EQ(nullptr, fourthFrame->nextSibling());
7889 EXPECT_EQ(fourthFrame, parent->lastChild());
7891 EXPECT_EQ(parent, firstFrame->parent());
7892 EXPECT_EQ(parent, secondFrame->parent());
7893 EXPECT_EQ(parent, thirdFrame->parent());
7894 EXPECT_EQ(parent, fourthFrame->parent());
7896 view->close();
7899 TEST_P(ParameterizedWebFrameTest, SendBeaconFromChildWithRemoteMainFrame)
7901 FrameTestHelpers::TestWebViewClient viewClient;
7902 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7903 WebView* view = WebView::create(&viewClient);
7904 view->settings()->setJavaScriptEnabled(true);
7905 view->setMainFrame(remoteClient.frame());
7906 WebRemoteFrame* root = view->mainFrame()->toWebRemoteFrame();
7907 root->setReplicatedOrigin(SecurityOrigin::createUnique());
7909 FrameTestHelpers::TestWebFrameClient localFrameClient;
7910 WebLocalFrame* localFrame = root->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &localFrameClient, nullptr);
7912 // Finally, make sure an embedder triggered load in the local frame swapped
7913 // back in works.
7914 registerMockedHttpURLLoad("send_beacon.html");
7915 registerMockedHttpURLLoad("reload_post.html"); // url param to sendBeacon()
7916 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "send_beacon.html");
7918 view->close();
7921 // See https://crbug.com/525285.
7922 TEST_P(ParameterizedWebFrameTest, RemoteToLocalSwapOnMainFrameInitializesCoreFrame)
7924 FrameTestHelpers::TestWebViewClient viewClient;
7925 FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
7926 WebView* view = WebView::create(&viewClient);
7927 view->setMainFrame(remoteClient.frame());
7928 WebRemoteFrame* remoteRoot = view->mainFrame()->toWebRemoteFrame();
7929 remoteRoot->setReplicatedOrigin(SecurityOrigin::createUnique());
7931 FrameTestHelpers::TestWebFrameClient localFrameClient;
7932 remoteRoot->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &localFrameClient, nullptr);
7934 // Do a remote-to-local swap of the top frame.
7935 FrameTestHelpers::TestWebFrameClient localClient;
7936 WebLocalFrame* localRoot = WebLocalFrame::create(WebTreeScopeType::Document, &localClient);
7937 localRoot->initializeToReplaceRemoteFrame(remoteRoot, "", WebSandboxFlags::None);
7938 remoteRoot->swap(localRoot);
7940 // Load a page with a child frame in the new root to make sure this doesn't
7941 // crash when the child frame invokes setCoreFrame.
7942 registerMockedHttpURLLoad("single_iframe.html");
7943 registerMockedHttpURLLoad("visible_iframe.html");
7944 FrameTestHelpers::loadFrame(localRoot, m_baseURL + "single_iframe.html");
7946 view->close();
7949 class OverscrollWebViewClient : public FrameTestHelpers::TestWebViewClient {
7950 public:
7951 MOCK_METHOD4(didOverscroll, void(const WebFloatSize&, const WebFloatSize&, const WebFloatPoint&, const WebFloatSize&));
7954 class WebFrameOverscrollTest : public WebFrameTest {
7955 protected:
7956 WebGestureEvent generateEvent(WebInputEvent::Type type, float deltaX = 0.0, float deltaY = 0.0)
7958 WebGestureEvent event;
7959 event.type = type;
7960 event.x = 100;
7961 event.y = 100;
7962 if (type == WebInputEvent::GestureScrollUpdate) {
7963 event.data.scrollUpdate.deltaX = deltaX;
7964 event.data.scrollUpdate.deltaY = deltaY;
7966 return event;
7969 void ScrollByWheel(FrameTestHelpers::WebViewHelper* webViewHelper, int windowX, int windowY, float deltaX, float deltaY)
7971 WebMouseWheelEvent event;
7972 event.type = WebInputEvent::MouseWheel;
7973 event.deltaX = deltaX;
7974 event.deltaY = deltaY;
7975 event.windowX = windowX;
7976 event.windowY = windowY;
7977 event.canScroll = true;
7978 webViewHelper->webViewImpl()->handleInputEvent(event);
7981 void ScrollBegin(FrameTestHelpers::WebViewHelper* webViewHelper)
7983 webViewHelper->webViewImpl()->handleInputEvent(generateEvent(WebInputEvent::GestureScrollBegin));
7986 void ScrollUpdate(FrameTestHelpers::WebViewHelper* webViewHelper, float deltaX, float deltaY)
7988 webViewHelper->webViewImpl()->handleInputEvent(generateEvent(WebInputEvent::GestureScrollUpdate, deltaX, deltaY));
7991 void ScrollEnd(FrameTestHelpers::WebViewHelper* webViewHelper)
7993 webViewHelper->webViewImpl()->handleInputEvent(generateEvent(WebInputEvent::GestureScrollEnd));
7997 TEST_F(WebFrameOverscrollTest, AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll)
7999 OverscrollWebViewClient client;
8000 registerMockedHttpURLLoad("overscroll/overscroll.html");
8001 FrameTestHelpers::WebViewHelper webViewHelper;
8002 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
8004 // Calculation of accumulatedRootOverscroll and unusedDelta on multiple scrollUpdate.
8005 ScrollBegin(&webViewHelper);
8006 EXPECT_CALL(client, didOverscroll(WebFloatSize(8, 16), WebFloatSize(8, 16), WebFloatPoint(100, 100), WebFloatSize()));
8007 ScrollUpdate(&webViewHelper, -308, -316);
8008 Mock::VerifyAndClearExpectations(&client);
8010 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 13), WebFloatSize(8, 29), WebFloatPoint(100, 100), WebFloatSize()));
8011 ScrollUpdate(&webViewHelper, 0, -13);
8012 Mock::VerifyAndClearExpectations(&client);
8014 EXPECT_CALL(client, didOverscroll(WebFloatSize(20, 13), WebFloatSize(28, 42), WebFloatPoint(100, 100), WebFloatSize()));
8015 ScrollUpdate(&webViewHelper, -20, -13);
8016 Mock::VerifyAndClearExpectations(&client);
8018 // Overscroll is not reported.
8019 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8020 ScrollUpdate(&webViewHelper, 0, 1);
8021 Mock::VerifyAndClearExpectations(&client);
8023 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8024 ScrollUpdate(&webViewHelper, 1, 0);
8025 Mock::VerifyAndClearExpectations(&client);
8027 // Overscroll is reported.
8028 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, -701), WebFloatSize(0, -701), WebFloatPoint(100, 100), WebFloatSize()));
8029 ScrollUpdate(&webViewHelper, 0, 1000);
8030 Mock::VerifyAndClearExpectations(&client);
8032 // Overscroll is not reported.
8033 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8034 ScrollEnd(&webViewHelper);
8035 Mock::VerifyAndClearExpectations(&client);
8038 TEST_F(WebFrameOverscrollTest, AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll)
8040 OverscrollWebViewClient client;
8041 registerMockedHttpURLLoad("overscroll/div-overscroll.html");
8042 FrameTestHelpers::WebViewHelper webViewHelper;
8043 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/div-overscroll.html", true, 0, &client, configureAndroid);
8045 ScrollBegin(&webViewHelper);
8047 // Scroll the Div to the end.
8048 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8049 ScrollUpdate(&webViewHelper, 0, -316);
8050 Mock::VerifyAndClearExpectations(&client);
8052 // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
8053 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 100), WebFloatSize(0, 100), WebFloatPoint(100, 100), WebFloatSize()));
8054 ScrollUpdate(&webViewHelper, 0, -100);
8055 Mock::VerifyAndClearExpectations(&client);
8057 // Page scrolls vertically, but over-scrolls horizontally.
8058 EXPECT_CALL(client, didOverscroll(WebFloatSize(-100, 0), WebFloatSize(-100, 0), WebFloatPoint(100, 100), WebFloatSize()));
8059 ScrollUpdate(&webViewHelper, 100, 50);
8060 Mock::VerifyAndClearExpectations(&client);
8062 // Scrolling up, Overscroll is not reported.
8063 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8064 ScrollUpdate(&webViewHelper, 0, -50);
8065 Mock::VerifyAndClearExpectations(&client);
8067 // Page scrolls horizontally, but over-scrolls vertically.
8068 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 100), WebFloatSize(0, 100), WebFloatPoint(100, 100), WebFloatSize()));
8069 ScrollUpdate(&webViewHelper, -100, -100);
8070 Mock::VerifyAndClearExpectations(&client);
8073 TEST_F(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll)
8075 OverscrollWebViewClient client;
8076 registerMockedHttpURLLoad("overscroll/div-overscroll.html");
8077 FrameTestHelpers::WebViewHelper webViewHelper;
8078 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/div-overscroll.html", true, 0, &client, configureAndroid);
8080 ScrollBegin(&webViewHelper);
8082 // Scroll the Div to the end.
8083 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8084 ScrollUpdate(&webViewHelper, 0, -316);
8085 Mock::VerifyAndClearExpectations(&client);
8087 // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
8088 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 50), WebFloatSize(0, 50), WebFloatPoint(100, 100), WebFloatSize()));
8089 ScrollUpdate(&webViewHelper, 0, -50);
8090 Mock::VerifyAndClearExpectations(&client);
8093 TEST_F(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll)
8095 OverscrollWebViewClient client;
8096 registerMockedHttpURLLoad("overscroll/iframe-overscroll.html");
8097 registerMockedHttpURLLoad("overscroll/scrollable-iframe.html");
8098 FrameTestHelpers::WebViewHelper webViewHelper;
8099 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/iframe-overscroll.html", true, 0, &client, configureAndroid);
8101 ScrollBegin(&webViewHelper);
8102 // Scroll the IFrame to the end.
8103 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8104 ScrollUpdate(&webViewHelper, 0, -320);
8105 Mock::VerifyAndClearExpectations(&client);
8107 // Now On Scrolling IFrame, scroll is bubbled and root layer is over-scrolled.
8108 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 50), WebFloatSize(0, 50), WebFloatPoint(100, 100), WebFloatSize()));
8109 ScrollUpdate(&webViewHelper, 0, -50);
8110 Mock::VerifyAndClearExpectations(&client);
8113 TEST_F(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled)
8115 OverscrollWebViewClient client;
8116 registerMockedHttpURLLoad("overscroll/overscroll.html");
8117 FrameTestHelpers::WebViewHelper webViewHelper;
8118 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
8119 webViewImpl->setPageScaleFactor(3.0);
8121 // Calculation of accumulatedRootOverscroll and unusedDelta on scaled page.
8122 ScrollBegin(&webViewHelper);
8123 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, -10), WebFloatSize(0, -10), WebFloatPoint(33, 33), WebFloatSize()));
8124 ScrollUpdate(&webViewHelper, 0, 30);
8125 Mock::VerifyAndClearExpectations(&client);
8127 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, -10), WebFloatSize(0, -20), WebFloatPoint(33, 33), WebFloatSize()));
8128 ScrollUpdate(&webViewHelper, 0, 30);
8129 Mock::VerifyAndClearExpectations(&client);
8131 EXPECT_CALL(client, didOverscroll(WebFloatSize(-10, -10), WebFloatSize(-10, -30), WebFloatPoint(33, 33), WebFloatSize()));
8132 ScrollUpdate(&webViewHelper, 30, 30);
8133 Mock::VerifyAndClearExpectations(&client);
8135 EXPECT_CALL(client, didOverscroll(WebFloatSize(-10, 0), WebFloatSize(-20, -30), WebFloatPoint(33, 33), WebFloatSize()));
8136 ScrollUpdate(&webViewHelper, 30, 0);
8137 Mock::VerifyAndClearExpectations(&client);
8139 // Overscroll is not reported.
8140 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8141 ScrollEnd(&webViewHelper);
8142 Mock::VerifyAndClearExpectations(&client);
8145 TEST_F(WebFrameOverscrollTest, NoOverscrollForSmallvalues)
8147 OverscrollWebViewClient client;
8148 registerMockedHttpURLLoad("overscroll/overscroll.html");
8149 FrameTestHelpers::WebViewHelper webViewHelper;
8150 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
8152 ScrollBegin(&webViewHelper);
8153 EXPECT_CALL(client, didOverscroll(WebFloatSize(-10, -10), WebFloatSize(-10, -10), WebFloatPoint(100, 100), WebFloatSize()));
8154 ScrollUpdate(&webViewHelper, 10, 10);
8155 Mock::VerifyAndClearExpectations(&client);
8157 EXPECT_CALL(client, didOverscroll(WebFloatSize(0, -0.10), WebFloatSize(-10, -10.10), WebFloatPoint(100, 100), WebFloatSize()));
8158 ScrollUpdate(&webViewHelper, 0, 0.10);
8159 Mock::VerifyAndClearExpectations(&client);
8161 EXPECT_CALL(client, didOverscroll(WebFloatSize(-0.10, 0), WebFloatSize(-10.10, -10.10), WebFloatPoint(100, 100), WebFloatSize()));
8162 ScrollUpdate(&webViewHelper, 0.10, 0);
8163 Mock::VerifyAndClearExpectations(&client);
8165 // For residual values overscrollDelta should be reset and didOverscroll shouldn't be called.
8166 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8167 ScrollUpdate(&webViewHelper, 0, 0.09);
8168 Mock::VerifyAndClearExpectations(&client);
8170 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8171 ScrollUpdate(&webViewHelper, 0.09, 0.09);
8172 Mock::VerifyAndClearExpectations(&client);
8174 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8175 ScrollUpdate(&webViewHelper, 0.09, 0);
8176 Mock::VerifyAndClearExpectations(&client);
8178 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8179 ScrollUpdate(&webViewHelper, 0, -0.09);
8180 Mock::VerifyAndClearExpectations(&client);
8182 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8183 ScrollUpdate(&webViewHelper, -0.09, -0.09);
8184 Mock::VerifyAndClearExpectations(&client);
8186 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8187 ScrollUpdate(&webViewHelper, -0.09, 0);
8188 Mock::VerifyAndClearExpectations(&client);
8190 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8191 ScrollEnd(&webViewHelper);
8192 Mock::VerifyAndClearExpectations(&client);
8195 TEST_F(WebFrameOverscrollTest, ReportingLatestOverscrollForElasticOverscroll)
8197 OverscrollWebViewClient client;
8198 registerMockedHttpURLLoad("overscroll/overscroll.html");
8199 FrameTestHelpers::WebViewHelper webViewHelper;
8200 webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
8202 // On disabling ReportWheelOverscroll, overscroll is not reported on MouseWheel.
8203 webViewHelper.webView()->settings()->setReportWheelOverscroll(false);
8204 EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
8205 ScrollByWheel(&webViewHelper, 10, 10, 1000, 1000);
8206 Mock::VerifyAndClearExpectations(&client);
8208 // On enabling ReportWheelOverscroll, overscroll is reported on MouseWheel.
8209 webViewHelper.webView()->settings()->setReportWheelOverscroll(true);
8210 EXPECT_CALL(client, didOverscroll(WebFloatSize(-1000, -1000), WebFloatSize(-1000, -1000), WebFloatPoint(), WebFloatSize()));
8211 ScrollByWheel(&webViewHelper, 10, 10, 1000, 1000);
8212 Mock::VerifyAndClearExpectations(&client);
8215 TEST_F(WebFrameTest, OrientationFrameDetach)
8217 RuntimeEnabledFeatures::setOrientationEventEnabled(true);
8218 registerMockedHttpURLLoad("orientation-frame-detach.html");
8219 FrameTestHelpers::WebViewHelper webViewHelper;
8220 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "orientation-frame-detach.html", true);
8221 webViewImpl->mainFrameImpl()->sendOrientationChangeEvent();
8224 TEST_F(WebFrameTest, MaxFramesDetach)
8226 registerMockedHttpURLLoad("max-frames-detach.html");
8227 FrameTestHelpers::WebViewHelper webViewHelper;
8228 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "max-frames-detach.html", true);
8229 webViewImpl->mainFrameImpl()->collectGarbage();
8232 } // namespace blink