1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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.
17 *
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.
29 */
30
31 #include "config.h"
32
33 #include "public/web/WebFrame.h"
34
35 #include "SkBitmap.h"
36 #include "SkCanvas.h"
37 #include "bindings/core/v8/V8Node.h"
38 #include "core/UserAgentStyleSheets.h"
39 #include "core/clipboard/DataTransfer.h"
40 #include "core/css/StyleSheetContents.h"
41 #include "core/css/resolver/StyleResolver.h"
42 #include "core/css/resolver/ViewportStyleResolver.h"
43 #include "core/dom/DocumentMarkerController.h"
44 #include "core/dom/Fullscreen.h"
45 #include "core/dom/NodeRenderStyle.h"
46 #include "core/dom/Range.h"
47 #include "core/editing/Editor.h"
48 #include "core/editing/FrameSelection.h"
49 #include "core/editing/SpellChecker.h"
50 #include "core/editing/VisiblePosition.h"
51 #include "core/events/MouseEvent.h"
52 #include "core/fetch/MemoryCache.h"
53 #include "core/frame/FrameHost.h"
54 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h"
56 #include "core/frame/PinchViewport.h"
57 #include "core/frame/Settings.h"
58 #include "core/html/HTMLDocument.h"
59 #include "core/html/HTMLFormElement.h"
60 #include "core/loader/DocumentThreadableLoader.h"
61 #include "core/loader/DocumentThreadableLoaderClient.h"
62 #include "core/loader/FrameLoadRequest.h"
63 #include "core/loader/ThreadableLoader.h"
64 #include "core/page/EventHandler.h"
65 #include "core/page/Page.h"
66 #include "core/rendering/HitTestResult.h"
67 #include "core/rendering/RenderView.h"
68 #include "core/rendering/compositing/RenderLayerCompositor.h"
69 #include "core/testing/URLTestHelpers.h"
70 #include "platform/DragImage.h"
71 #include "platform/RuntimeEnabledFeatures.h"
72 #include "platform/UserGestureIndicator.h"
73 #include "platform/geometry/FloatRect.h"
74 #include "platform/network/ResourceError.h"
75 #include "platform/scroll/ScrollbarTheme.h"
76 #include "platform/weborigin/SchemeRegistry.h"
77 #include "public/platform/Platform.h"
78 #include "public/platform/WebFloatRect.h"
79 #include "public/platform/WebSelectionBound.h"
80 #include "public/platform/WebThread.h"
81 #include "public/platform/WebURL.h"
82 #include "public/platform/WebURLResponse.h"
83 #include "public/platform/WebUnitTestSupport.h"
84 #include "public/web/WebCache.h"
85 #include "public/web/WebDataSource.h"
86 #include "public/web/WebDocument.h"
87 #include "public/web/WebFindOptions.h"
88 #include "public/web/WebFormElement.h"
89 #include "public/web/WebFrameClient.h"
90 #include "public/web/WebHistoryItem.h"
91 #include "public/web/WebPrintParams.h"
92 #include "public/web/WebRange.h"
93 #include "public/web/WebRemoteFrame.h"
94 #include "public/web/WebScriptSource.h"
95 #include "public/web/WebSearchableFormData.h"
96 #include "public/web/WebSecurityOrigin.h"
97 #include "public/web/WebSecurityPolicy.h"
98 #include "public/web/WebSettings.h"
99 #include "public/web/WebSpellCheckClient.h"
100 #include "public/web/WebTextCheckingCompletion.h"
101 #include "public/web/WebTextCheckingResult.h"
102 #include "public/web/WebViewClient.h"
103 #include "web/WebLocalFrameImpl.h"
104 #include "web/WebRemoteFrameImpl.h"
105 #include "web/WebViewImpl.h"
106 #include "web/tests/FrameTestHelpers.h"
107 #include "wtf/Forward.h"
108 #include "wtf/dtoa/utils.h"
109 #include <gmock/gmock.h>
110 #include <gtest/gtest.h>
111 #include <map>
112 #include <v8.h>
113
114 namespace {
115
116 using blink::URLTestHelpers::toKURL;
117 using blink::FrameTestHelpers::runPendingTasks;
118 using namespace blink;
119
120 const int touchPointPadding = 32;
121
122 #define EXPECT_RECT_EQ(a, b) \
123 do { \
124 EXPECT_EQ(a.x(), b.x()); \
125 EXPECT_EQ(a.y(), b.y()); \
126 EXPECT_EQ(a.width(), b.width()); \
127 EXPECT_EQ(a.height(), b.height()); \
128 } while (false)
129
130 #define EXPECT_POINT_EQ(expected, actual) \
131 do { \
132 EXPECT_EQ((expected).x(), (actual).x()); \
133 EXPECT_EQ((expected).y(), (actual).y()); \
134 } while (false)
135
136 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
137 do { \
138 EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
139 EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
140 } while (false)
141
142 #define EXPECT_EQ_POINT(a, b) \
143 EXPECT_EQ(a.x(), b.x()); \
144 EXPECT_EQ(a.y(), b.y());
145
146 class FakeCompositingWebViewClient : public FrameTestHelpers::TestWebViewClient {
147 public:
enterFullScreen()148 virtual bool enterFullScreen() OVERRIDE { return true; }
149 };
150
151 class WebFrameTest : public testing::Test {
152 protected:
WebFrameTest()153 WebFrameTest()
154 : m_baseURL("http://www.test.com/")
155 , m_chromeURL("chrome://")
156 {
157 }
158
~WebFrameTest()159 virtual ~WebFrameTest()
160 {
161 Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
162 }
163
registerMockedHttpURLLoad(const std::string & fileName)164 void registerMockedHttpURLLoad(const std::string& fileName)
165 {
166 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
167 }
168
registerMockedChromeURLLoad(const std::string & fileName)169 void registerMockedChromeURLLoad(const std::string& fileName)
170 {
171 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_chromeURL.c_str()), WebString::fromUTF8(fileName.c_str()));
172 }
173
applyViewportStyleOverride(FrameTestHelpers::WebViewHelper * webViewHelper)174 void applyViewportStyleOverride(FrameTestHelpers::WebViewHelper* webViewHelper)
175 {
176 RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0));
177 styleSheet->parseString(String(blink::viewportAndroidCss, sizeof(blink::viewportAndroidCss)));
178 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
179 ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen"));
180
181 Document* document = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame())->document();
182 document->ensureStyleResolver().viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin);
183 document->ensureStyleResolver().viewportStyleResolver()->resolve();
184 }
185
configueCompositingWebView(WebSettings * settings)186 static void configueCompositingWebView(WebSettings* settings)
187 {
188 settings->setAcceleratedCompositingEnabled(true);
189 settings->setPreferCompositingToLCDTextEnabled(true);
190 }
191
configureLoadsImagesAutomatically(WebSettings * settings)192 static void configureLoadsImagesAutomatically(WebSettings* settings)
193 {
194 settings->setLoadsImagesAutomatically(true);
195 }
196
initializeTextSelectionWebView(const std::string & url,FrameTestHelpers::WebViewHelper * webViewHelper)197 void initializeTextSelectionWebView(const std::string& url, FrameTestHelpers::WebViewHelper* webViewHelper)
198 {
199 webViewHelper->initializeAndLoad(url, true);
200 webViewHelper->webView()->settings()->setDefaultFontSize(12);
201 webViewHelper->webView()->resize(WebSize(640, 480));
202 }
203
nodeImageTestSetup(FrameTestHelpers::WebViewHelper * webViewHelper,const std::string & testcase)204 PassOwnPtr<DragImage> nodeImageTestSetup(FrameTestHelpers::WebViewHelper* webViewHelper, const std::string& testcase)
205 {
206 registerMockedHttpURLLoad("nodeimage.html");
207 webViewHelper->initializeAndLoad(m_baseURL + "nodeimage.html");
208 webViewHelper->webView()->resize(WebSize(640, 480));
209 webViewHelper->webView()->layout();
210 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame());
211 ASSERT(frame);
212 Element* element = frame->document()->getElementById(testcase.c_str());
213 return frame->nodeImage(*element);
214 }
215
216 std::string m_baseURL;
217 std::string m_chromeURL;
218 };
219
220 class UseMockScrollbarSettings {
221 public:
UseMockScrollbarSettings()222 UseMockScrollbarSettings()
223 {
224 Settings::setMockScrollbarsEnabled(true);
225 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true);
226 EXPECT_TRUE(ScrollbarTheme::theme()->usesOverlayScrollbars());
227 }
228
~UseMockScrollbarSettings()229 ~UseMockScrollbarSettings()
230 {
231 Settings::setMockScrollbarsEnabled(false);
232 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(false);
233 }
234 };
235
TEST_F(WebFrameTest,ContentText)236 TEST_F(WebFrameTest, ContentText)
237 {
238 registerMockedHttpURLLoad("iframes_test.html");
239 registerMockedHttpURLLoad("visible_iframe.html");
240 registerMockedHttpURLLoad("invisible_iframe.html");
241 registerMockedHttpURLLoad("zero_sized_iframe.html");
242
243 FrameTestHelpers::WebViewHelper webViewHelper;
244 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html");
245
246 // Now retrieve the frames text and test it only includes visible elements.
247 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
248 EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
249 EXPECT_NE(std::string::npos, content.find(" visible iframe"));
250 EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
251 EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
252 EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
253 }
254
TEST_F(WebFrameTest,FrameForEnteredContext)255 TEST_F(WebFrameTest, FrameForEnteredContext)
256 {
257 registerMockedHttpURLLoad("iframes_test.html");
258 registerMockedHttpURLLoad("visible_iframe.html");
259 registerMockedHttpURLLoad("invisible_iframe.html");
260 registerMockedHttpURLLoad("zero_sized_iframe.html");
261
262 FrameTestHelpers::WebViewHelper webViewHelper;
263 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html", true);
264
265 v8::HandleScope scope(v8::Isolate::GetCurrent());
266 EXPECT_EQ(webViewHelper.webView()->mainFrame(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->mainWorldScriptContext()));
267 EXPECT_EQ(webViewHelper.webView()->mainFrame()->firstChild(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->firstChild()->mainWorldScriptContext()));
268 }
269
TEST_F(WebFrameTest,FormWithNullFrame)270 TEST_F(WebFrameTest, FormWithNullFrame)
271 {
272 registerMockedHttpURLLoad("form.html");
273
274 FrameTestHelpers::WebViewHelper webViewHelper;
275 webViewHelper.initializeAndLoad(m_baseURL + "form.html");
276
277 WebVector<WebFormElement> forms;
278 webViewHelper.webView()->mainFrame()->document().forms(forms);
279 webViewHelper.reset();
280
281 EXPECT_EQ(forms.size(), 1U);
282
283 // This test passes if this doesn't crash.
284 WebSearchableFormData searchableDataForm(forms[0]);
285 }
286
TEST_F(WebFrameTest,ChromePageJavascript)287 TEST_F(WebFrameTest, ChromePageJavascript)
288 {
289 registerMockedChromeURLLoad("history.html");
290
291 // Pass true to enable JavaScript.
292 FrameTestHelpers::WebViewHelper webViewHelper;
293 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
294
295 // Try to run JS against the chrome-style URL.
296 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
297
298 // Required to see any updates in contentAsText.
299 webViewHelper.webView()->layout();
300
301 // Now retrieve the frame's text and ensure it was modified by running javascript.
302 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
303 EXPECT_NE(std::string::npos, content.find("Clobbered"));
304 }
305
TEST_F(WebFrameTest,ChromePageNoJavascript)306 TEST_F(WebFrameTest, ChromePageNoJavascript)
307 {
308 registerMockedChromeURLLoad("history.html");
309
310 /// Pass true to enable JavaScript.
311 FrameTestHelpers::WebViewHelper webViewHelper;
312 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
313
314 // Try to run JS against the chrome-style URL after prohibiting it.
315 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
316 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
317
318 // Required to see any updates in contentAsText.
319 webViewHelper.webView()->layout();
320
321 // Now retrieve the frame's text and ensure it wasn't modified by running javascript.
322 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
323 EXPECT_EQ(std::string::npos, content.find("Clobbered"));
324 }
325
TEST_F(WebFrameTest,LocationSetHostWithMissingPort)326 TEST_F(WebFrameTest, LocationSetHostWithMissingPort)
327 {
328 std::string fileName = "print-location-href.html";
329 registerMockedHttpURLLoad(fileName);
330 URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName));
331
332 FrameTestHelpers::WebViewHelper webViewHelper;
333
334 /// Pass true to enable JavaScript.
335 webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
336
337 // Setting host to "hostname:" should be treated as "hostname:0".
338 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.host = 'www.test.com:'; void 0;");
339
340 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
341
342 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
343 EXPECT_EQ("http://www.test.com:0/" + fileName, content);
344 }
345
TEST_F(WebFrameTest,LocationSetEmptyPort)346 TEST_F(WebFrameTest, LocationSetEmptyPort)
347 {
348 std::string fileName = "print-location-href.html";
349 registerMockedHttpURLLoad(fileName);
350 URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName));
351
352 FrameTestHelpers::WebViewHelper webViewHelper;
353
354 /// Pass true to enable JavaScript.
355 webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
356
357 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.port = ''; void 0;");
358
359 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
360
361 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
362 EXPECT_EQ("http://www.test.com:0/" + fileName, content);
363 }
364
365 class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
366 public:
CSSCallbackWebFrameClient()367 CSSCallbackWebFrameClient() : m_updateCount(0) { }
368 virtual void didMatchCSS(WebLocalFrame*, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors) OVERRIDE;
369
370 std::map<WebLocalFrame*, std::set<std::string> > m_matchedSelectors;
371 int m_updateCount;
372 };
373
didMatchCSS(WebLocalFrame * frame,const WebVector<WebString> & newlyMatchingSelectors,const WebVector<WebString> & stoppedMatchingSelectors)374 void CSSCallbackWebFrameClient::didMatchCSS(WebLocalFrame* frame, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors)
375 {
376 ++m_updateCount;
377 std::set<std::string>& frameSelectors = m_matchedSelectors[frame];
378 for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i) {
379 std::string selector = newlyMatchingSelectors[i].utf8();
380 EXPECT_EQ(0U, frameSelectors.count(selector)) << selector;
381 frameSelectors.insert(selector);
382 }
383 for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i) {
384 std::string selector = stoppedMatchingSelectors[i].utf8();
385 EXPECT_EQ(1U, frameSelectors.count(selector)) << selector;
386 frameSelectors.erase(selector);
387 }
388 }
389
390 class WebFrameCSSCallbackTest : public testing::Test {
391 protected:
WebFrameCSSCallbackTest()392 WebFrameCSSCallbackTest()
393 {
394
395 m_frame = m_helper.initializeAndLoad("about:blank", true, &m_client)->mainFrame()->toWebLocalFrame();
396 }
397
~WebFrameCSSCallbackTest()398 ~WebFrameCSSCallbackTest()
399 {
400 EXPECT_EQ(1U, m_client.m_matchedSelectors.size());
401 }
402
doc() const403 WebDocument doc() const
404 {
405 return m_frame->document();
406 }
407
updateCount() const408 int updateCount() const
409 {
410 return m_client.m_updateCount;
411 }
412
matchedSelectors()413 const std::set<std::string>& matchedSelectors()
414 {
415 return m_client.m_matchedSelectors[m_frame];
416 }
417
loadHTML(const std::string & html)418 void loadHTML(const std::string& html)
419 {
420 FrameTestHelpers::loadHTMLString(m_frame, html, toKURL("about:blank"));
421 }
422
executeScript(const WebString & code)423 void executeScript(const WebString& code)
424 {
425 m_frame->executeScript(WebScriptSource(code));
426 m_frame->view()->layout();
427 runPendingTasks();
428 }
429
430 CSSCallbackWebFrameClient m_client;
431 FrameTestHelpers::WebViewHelper m_helper;
432 WebLocalFrame* m_frame;
433 };
434
TEST_F(WebFrameCSSCallbackTest,AuthorStyleSheet)435 TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet)
436 {
437 loadHTML(
438 "<style>"
439 // This stylesheet checks that the internal property and value can't be
440 // set by a stylesheet, only WebDocument::watchCSSSelectors().
441 "div.initial_on { -internal-callback: none; }"
442 "div.initial_off { -internal-callback: -internal-presence; }"
443 "</style>"
444 "<div class=\"initial_on\"></div>"
445 "<div class=\"initial_off\"></div>");
446
447 std::vector<WebString> selectors;
448 selectors.push_back(WebString::fromUTF8("div.initial_on"));
449 m_frame->document().watchCSSSelectors(WebVector<WebString>(selectors));
450 m_frame->view()->layout();
451 runPendingTasks();
452 EXPECT_EQ(1, updateCount());
453 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_on"));
454
455 // Check that adding a watched selector calls back for already-present nodes.
456 selectors.push_back(WebString::fromUTF8("div.initial_off"));
457 doc().watchCSSSelectors(WebVector<WebString>(selectors));
458 m_frame->view()->layout();
459 runPendingTasks();
460 EXPECT_EQ(2, updateCount());
461 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_off", "div.initial_on"));
462
463 // Check that we can turn off callbacks for certain selectors.
464 doc().watchCSSSelectors(WebVector<WebString>());
465 m_frame->view()->layout();
466 runPendingTasks();
467 EXPECT_EQ(3, updateCount());
468 EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
469 }
470
TEST_F(WebFrameCSSCallbackTest,SharedRenderStyle)471 TEST_F(WebFrameCSSCallbackTest, SharedRenderStyle)
472 {
473 // Check that adding an element calls back when it matches an existing rule.
474 std::vector<WebString> selectors;
475 selectors.push_back(WebString::fromUTF8("span"));
476 doc().watchCSSSelectors(WebVector<WebString>(selectors));
477
478 executeScript(
479 "i1 = document.createElement('span');"
480 "i1.id = 'first_span';"
481 "document.body.appendChild(i1)");
482 EXPECT_EQ(1, updateCount());
483 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
484
485 // Adding a second element that shares a RenderStyle shouldn't call back.
486 // We use <span>s to avoid default style rules that can set
487 // RenderStyle::unique().
488 executeScript(
489 "i2 = document.createElement('span');"
490 "i2.id = 'second_span';"
491 "i1 = document.getElementById('first_span');"
492 "i1.parentNode.insertBefore(i2, i1.nextSibling);");
493 EXPECT_EQ(1, updateCount());
494 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
495
496 // Removing the first element shouldn't call back.
497 executeScript(
498 "i1 = document.getElementById('first_span');"
499 "i1.parentNode.removeChild(i1);");
500 EXPECT_EQ(1, updateCount());
501 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
502
503 // But removing the second element *should* call back.
504 executeScript(
505 "i2 = document.getElementById('second_span');"
506 "i2.parentNode.removeChild(i2);");
507 EXPECT_EQ(2, updateCount());
508 EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
509 }
510
TEST_F(WebFrameCSSCallbackTest,CatchesAttributeChange)511 TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange)
512 {
513 loadHTML("<span></span>");
514
515 std::vector<WebString> selectors;
516 selectors.push_back(WebString::fromUTF8("span[attr=\"value\"]"));
517 doc().watchCSSSelectors(WebVector<WebString>(selectors));
518 runPendingTasks();
519
520 EXPECT_EQ(0, updateCount());
521 EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
522
523 executeScript(
524 "document.querySelector('span').setAttribute('attr', 'value');");
525 EXPECT_EQ(1, updateCount());
526 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span[attr=\"value\"]"));
527 }
528
TEST_F(WebFrameCSSCallbackTest,DisplayNone)529 TEST_F(WebFrameCSSCallbackTest, DisplayNone)
530 {
531 loadHTML("<div style='display:none'><span></span></div>");
532
533 std::vector<WebString> selectors;
534 selectors.push_back(WebString::fromUTF8("span"));
535 doc().watchCSSSelectors(WebVector<WebString>(selectors));
536 runPendingTasks();
537
538 EXPECT_EQ(0, updateCount()) << "Don't match elements in display:none trees.";
539
540 executeScript(
541 "d = document.querySelector('div');"
542 "d.style.display = 'block';");
543 EXPECT_EQ(1, updateCount()) << "Match elements when they become displayed.";
544 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
545
546 executeScript(
547 "d = document.querySelector('div');"
548 "d.style.display = 'none';");
549 EXPECT_EQ(2, updateCount()) << "Unmatch elements when they become undisplayed.";
550 EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
551
552 executeScript(
553 "s = document.querySelector('span');"
554 "s.style.display = 'none';");
555 EXPECT_EQ(2, updateCount()) << "No effect from no-display'ing a span that's already undisplayed.";
556
557 executeScript(
558 "d = document.querySelector('div');"
559 "d.style.display = 'block';");
560 EXPECT_EQ(2, updateCount()) << "No effect from displaying a div whose span is display:none.";
561
562 executeScript(
563 "s = document.querySelector('span');"
564 "s.style.display = 'inline';");
565 EXPECT_EQ(3, updateCount()) << "Now the span is visible and produces a callback.";
566 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
567
568 executeScript(
569 "s = document.querySelector('span');"
570 "s.style.display = 'none';");
571 EXPECT_EQ(4, updateCount()) << "Undisplaying the span directly should produce another callback.";
572 EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
573 }
574
TEST_F(WebFrameCSSCallbackTest,Reparenting)575 TEST_F(WebFrameCSSCallbackTest, Reparenting)
576 {
577 loadHTML(
578 "<div id='d1'><span></span></div>"
579 "<div id='d2'></div>");
580
581 std::vector<WebString> selectors;
582 selectors.push_back(WebString::fromUTF8("span"));
583 doc().watchCSSSelectors(WebVector<WebString>(selectors));
584 m_frame->view()->layout();
585 runPendingTasks();
586
587 EXPECT_EQ(1, updateCount());
588 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
589
590 executeScript(
591 "s = document.querySelector('span');"
592 "d2 = document.getElementById('d2');"
593 "d2.appendChild(s);");
594 EXPECT_EQ(1, updateCount()) << "Just moving an element that continues to match shouldn't send a spurious callback.";
595 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
596 }
597
TEST_F(WebFrameCSSCallbackTest,MultiSelector)598 TEST_F(WebFrameCSSCallbackTest, MultiSelector)
599 {
600 loadHTML("<span></span>");
601
602 // Check that selector lists match as the whole list, not as each element
603 // independently.
604 std::vector<WebString> selectors;
605 selectors.push_back(WebString::fromUTF8("span"));
606 selectors.push_back(WebString::fromUTF8("span,p"));
607 doc().watchCSSSelectors(WebVector<WebString>(selectors));
608 m_frame->view()->layout();
609 runPendingTasks();
610
611 EXPECT_EQ(1, updateCount());
612 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span", "span, p"));
613 }
614
TEST_F(WebFrameCSSCallbackTest,InvalidSelector)615 TEST_F(WebFrameCSSCallbackTest, InvalidSelector)
616 {
617 loadHTML("<p><span></span></p>");
618
619 // Build a list with one valid selector and one invalid.
620 std::vector<WebString> selectors;
621 selectors.push_back(WebString::fromUTF8("span"));
622 selectors.push_back(WebString::fromUTF8("[")); // Invalid.
623 selectors.push_back(WebString::fromUTF8("p span")); // Not compound.
624 doc().watchCSSSelectors(WebVector<WebString>(selectors));
625 m_frame->view()->layout();
626 runPendingTasks();
627
628 EXPECT_EQ(1, updateCount());
629 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"))
630 << "An invalid selector shouldn't prevent other selectors from matching.";
631 }
632
TEST_F(WebFrameTest,DispatchMessageEventWithOriginCheck)633 TEST_F(WebFrameTest, DispatchMessageEventWithOriginCheck)
634 {
635 registerMockedHttpURLLoad("postmessage_test.html");
636
637 // Pass true to enable JavaScript.
638 FrameTestHelpers::WebViewHelper webViewHelper;
639 webViewHelper.initializeAndLoad(m_baseURL + "postmessage_test.html", true);
640
641 // Send a message with the correct origin.
642 WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL)));
643 WebDOMEvent event = webViewHelper.webView()->mainFrame()->document().createEvent("MessageEvent");
644 WebDOMMessageEvent message = event.to<WebDOMMessageEvent>();
645 WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
646 message.initMessageEvent("message", false, false, data, "http://origin.com", 0, "");
647 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message);
648
649 // Send another message with incorrect origin.
650 WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(toKURL(m_chromeURL)));
651 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message);
652
653 // Required to see any updates in contentAsText.
654 webViewHelper.webView()->layout();
655
656 // Verify that only the first addition is in the body of the page.
657 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
658 EXPECT_NE(std::string::npos, content.find("Message 1."));
659 EXPECT_EQ(std::string::npos, content.find("Message 2."));
660 }
661
TEST_F(WebFrameTest,PostMessageThenDetach)662 TEST_F(WebFrameTest, PostMessageThenDetach)
663 {
664 FrameTestHelpers::WebViewHelper webViewHelper;
665 webViewHelper.initializeAndLoad("about:blank");
666
667 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame());
668 NonThrowableExceptionState exceptionState;
669 frame->domWindow()->postMessage(SerializedScriptValue::create("message"), 0, "*", frame->domWindow(), exceptionState);
670 webViewHelper.reset();
671 EXPECT_FALSE(exceptionState.hadException());
672
673 // Success is not crashing.
674 runPendingTasks();
675 }
676
677 class FixedLayoutTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
678 public:
screenInfo()679 virtual WebScreenInfo screenInfo() OVERRIDE { return m_screenInfo; }
680
681 WebScreenInfo m_screenInfo;
682 };
683
684 // Viewport settings need to be set before the page gets loaded
enableViewportSettings(WebSettings * settings)685 static void enableViewportSettings(WebSettings* settings)
686 {
687 settings->setViewportMetaEnabled(true);
688 settings->setViewportEnabled(true);
689 settings->setMainFrameResizesAreOrientationChanges(true);
690 settings->setShrinksViewportContentToFit(true);
691 }
692
693 // Helper function to check or set text autosizing multipliers on a document.
checkOrSetTextAutosizingMultiplier(Document * document,float multiplier,bool setMultiplier)694 static bool checkOrSetTextAutosizingMultiplier(Document* document, float multiplier, bool setMultiplier)
695 {
696 bool multiplierCheckedOrSetAtLeastOnce = false;
697 for (RenderObject* renderer = document->renderView(); renderer; renderer = renderer->nextInPreOrder()) {
698 if (renderer->style()) {
699 if (setMultiplier)
700 renderer->style()->setTextAutosizingMultiplier(multiplier);
701 EXPECT_EQ(multiplier, renderer->style()->textAutosizingMultiplier());
702 multiplierCheckedOrSetAtLeastOnce = true;
703 }
704 }
705 return multiplierCheckedOrSetAtLeastOnce;
706
707 }
708
setTextAutosizingMultiplier(Document * document,float multiplier)709 static bool setTextAutosizingMultiplier(Document* document, float multiplier)
710 {
711 return checkOrSetTextAutosizingMultiplier(document, multiplier, true);
712 }
713
checkTextAutosizingMultiplier(Document * document,float multiplier)714 static bool checkTextAutosizingMultiplier(Document* document, float multiplier)
715 {
716 return checkOrSetTextAutosizingMultiplier(document, multiplier, false);
717 }
718
TEST_F(WebFrameTest,ChangeInFixedLayoutResetsTextAutosizingMultipliers)719 TEST_F(WebFrameTest, ChangeInFixedLayoutResetsTextAutosizingMultipliers)
720 {
721 UseMockScrollbarSettings mockScrollbarSettings;
722 registerMockedHttpURLLoad("fixed_layout.html");
723
724 FixedLayoutTestWebViewClient client;
725 int viewportWidth = 640;
726 int viewportHeight = 480;
727
728 FrameTestHelpers::WebViewHelper webViewHelper;
729 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
730
731 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
732 document->settings()->setTextAutosizingEnabled(true);
733 EXPECT_TRUE(document->settings()->textAutosizingEnabled());
734 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight));
735 webViewHelper.webViewImpl()->layout();
736
737 EXPECT_TRUE(setTextAutosizingMultiplier(document, 2));
738
739 ViewportDescription description = document->viewportDescription();
740 // Choose a width that's not going match the viewport width of the loaded document.
741 description.minWidth = Length(100, blink::Fixed);
742 description.maxWidth = Length(100, blink::Fixed);
743 webViewHelper.webViewImpl()->updatePageDefinedViewportConstraints(description);
744
745 EXPECT_TRUE(checkTextAutosizingMultiplier(document, 1));
746 }
747
TEST_F(WebFrameTest,SetFrameRectInvalidatesTextAutosizingMultipliers)748 TEST_F(WebFrameTest, SetFrameRectInvalidatesTextAutosizingMultipliers)
749 {
750 UseMockScrollbarSettings mockScrollbarSettings;
751 registerMockedHttpURLLoad("iframe_reload.html");
752 registerMockedHttpURLLoad("visible_iframe.html");
753
754 FixedLayoutTestWebViewClient client;
755 int viewportWidth = 640;
756 int viewportHeight = 480;
757
758 FrameTestHelpers::WebViewHelper webViewHelper;
759 webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, 0, &client, enableViewportSettings);
760
761 LocalFrame* mainFrame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame());
762 Document* document = mainFrame->document();
763 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
764 document->settings()->setTextAutosizingEnabled(true);
765 EXPECT_TRUE(document->settings()->textAutosizingEnabled());
766 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight));
767 webViewHelper.webViewImpl()->layout();
768
769 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
770 if (!frame->isLocalFrame())
771 continue;
772 EXPECT_TRUE(setTextAutosizingMultiplier(toLocalFrame(frame)->document(), 2));
773 for (RenderObject* renderer = toLocalFrame(frame)->document()->renderView(); renderer; renderer = renderer->nextInPreOrder()) {
774 if (renderer->isText())
775 EXPECT_FALSE(renderer->needsLayout());
776 }
777 }
778
779 frameView->setFrameRect(IntRect(0, 0, 200, 200));
780 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
781 if (!frame->isLocalFrame())
782 continue;
783 for (RenderObject* renderer = toLocalFrame(frame)->document()->renderView(); renderer; renderer = renderer->nextInPreOrder()) {
784 if (renderer->isText())
785 EXPECT_TRUE(renderer->needsLayout());
786 }
787 }
788 }
789
TEST_F(WebFrameTest,ZeroHeightPositiveWidthNotIgnored)790 TEST_F(WebFrameTest, ZeroHeightPositiveWidthNotIgnored)
791 {
792 UseMockScrollbarSettings mockScrollbarSettings;
793
794 FixedLayoutTestWebViewClient client;
795 client.m_screenInfo.deviceScaleFactor = 1;
796 int viewportWidth = 1280;
797 int viewportHeight = 0;
798
799 FrameTestHelpers::WebViewHelper webViewHelper;
800 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
801 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
802
803 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
804 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
805 }
806
TEST_F(WebFrameTest,DeviceScaleFactorUsesDefaultWithoutViewportTag)807 TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag)
808 {
809 UseMockScrollbarSettings mockScrollbarSettings;
810 registerMockedHttpURLLoad("no_viewport_tag.html");
811
812 int viewportWidth = 640;
813 int viewportHeight = 480;
814
815 FixedLayoutTestWebViewClient client;
816 client.m_screenInfo.deviceScaleFactor = 2;
817
818 FrameTestHelpers::WebViewHelper webViewHelper;
819 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
820
821 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
822 webViewHelper.webView()->layout();
823
824 EXPECT_EQ(2, webViewHelper.webView()->deviceScaleFactor());
825
826 // Device scale factor should be independent of page scale.
827 webViewHelper.webView()->setPageScaleFactorLimits(1, 2);
828 webViewHelper.webView()->setPageScaleFactor(0.5);
829 webViewHelper.webView()->layout();
830 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
831
832 // Force the layout to happen before leaving the test.
833 webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
834 }
835
TEST_F(WebFrameTest,FixedLayoutInitializeAtMinimumScale)836 TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumScale)
837 {
838 UseMockScrollbarSettings mockScrollbarSettings;
839
840 registerMockedHttpURLLoad("fixed_layout.html");
841
842 FixedLayoutTestWebViewClient client;
843 client.m_screenInfo.deviceScaleFactor = 1;
844 int viewportWidth = 640;
845 int viewportHeight = 480;
846
847 // Make sure we initialize to minimum scale, even if the window size
848 // only becomes available after the load begins.
849 FrameTestHelpers::WebViewHelper webViewHelper;
850 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
851 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
852
853 int defaultFixedLayoutWidth = 980;
854 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
855 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
856 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor());
857
858 // Assume the user has pinch zoomed to page scale factor 2.
859 float userPinchPageScaleFactor = 2;
860 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
861 webViewHelper.webView()->layout();
862
863 // Make sure we don't reset to initial scale if the page continues to load.
864 webViewHelper.webViewImpl()->didCommitLoad(false, false);
865 webViewHelper.webViewImpl()->didChangeContentsSize();
866 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
867
868 // Make sure we don't reset to initial scale if the viewport size changes.
869 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100));
870 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
871 }
872
TEST_F(WebFrameTest,WideDocumentInitializeAtMinimumScale)873 TEST_F(WebFrameTest, WideDocumentInitializeAtMinimumScale)
874 {
875 UseMockScrollbarSettings mockScrollbarSettings;
876
877 registerMockedHttpURLLoad("wide_document.html");
878
879 FixedLayoutTestWebViewClient client;
880 client.m_screenInfo.deviceScaleFactor = 1;
881 int viewportWidth = 640;
882 int viewportHeight = 480;
883
884 // Make sure we initialize to minimum scale, even if the window size
885 // only becomes available after the load begins.
886 FrameTestHelpers::WebViewHelper webViewHelper;
887 webViewHelper.initializeAndLoad(m_baseURL + "wide_document.html", true, 0, &client, enableViewportSettings);
888 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
889
890 int wideDocumentWidth = 1500;
891 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth;
892 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
893 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor());
894
895 // Assume the user has pinch zoomed to page scale factor 2.
896 float userPinchPageScaleFactor = 2;
897 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
898 webViewHelper.webView()->layout();
899
900 // Make sure we don't reset to initial scale if the page continues to load.
901 webViewHelper.webViewImpl()->didCommitLoad(false, false);
902 webViewHelper.webViewImpl()->didChangeContentsSize();
903 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
904
905 // Make sure we don't reset to initial scale if the viewport size changes.
906 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100));
907 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
908 }
909
TEST_F(WebFrameTest,DelayedViewportInitialScale)910 TEST_F(WebFrameTest, DelayedViewportInitialScale)
911 {
912 UseMockScrollbarSettings mockScrollbarSettings;
913 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
914
915 FixedLayoutTestWebViewClient client;
916 client.m_screenInfo.deviceScaleFactor = 1;
917 int viewportWidth = 640;
918 int viewportHeight = 480;
919
920 FrameTestHelpers::WebViewHelper webViewHelper;
921 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
922 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
923
924 EXPECT_EQ(0.25f, webViewHelper.webView()->pageScaleFactor());
925
926 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
927 ViewportDescription description = document->viewportDescription();
928 description.zoom = 2;
929 document->setViewportDescription(description);
930 webViewHelper.webView()->layout();
931 EXPECT_EQ(2, webViewHelper.webView()->pageScaleFactor());
932 }
933
TEST_F(WebFrameTest,setLoadWithOverviewModeToFalse)934 TEST_F(WebFrameTest, setLoadWithOverviewModeToFalse)
935 {
936 UseMockScrollbarSettings mockScrollbarSettings;
937 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
938
939 FixedLayoutTestWebViewClient client;
940 client.m_screenInfo.deviceScaleFactor = 1;
941 int viewportWidth = 640;
942 int viewportHeight = 480;
943
944 FrameTestHelpers::WebViewHelper webViewHelper;
945 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
946 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
947 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
948 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
949
950 // The page must be displayed at 100% zoom.
951 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
952 }
953
TEST_F(WebFrameTest,SetLoadWithOverviewModeToFalseAndNoWideViewport)954 TEST_F(WebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport)
955 {
956 UseMockScrollbarSettings mockScrollbarSettings;
957 registerMockedHttpURLLoad("large-div.html");
958
959 FixedLayoutTestWebViewClient client;
960 client.m_screenInfo.deviceScaleFactor = 1;
961 int viewportWidth = 640;
962 int viewportHeight = 480;
963
964 FrameTestHelpers::WebViewHelper webViewHelper;
965 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
966 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
967 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
968 webViewHelper.webView()->settings()->setUseWideViewport(false);
969 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
970
971 // The page must be displayed at 100% zoom, despite that it hosts a wide div element.
972 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
973 }
974
TEST_F(WebFrameTest,NoWideViewportIgnoresPageViewportWidth)975 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidth)
976 {
977 UseMockScrollbarSettings mockScrollbarSettings;
978 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
979
980 FixedLayoutTestWebViewClient client;
981 client.m_screenInfo.deviceScaleFactor = 1;
982 int viewportWidth = 640;
983 int viewportHeight = 480;
984
985 FrameTestHelpers::WebViewHelper webViewHelper;
986 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
987 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
988 webViewHelper.webView()->settings()->setUseWideViewport(false);
989 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
990
991 // The page sets viewport width to 3000, but with UseWideViewport == false is must be ignored.
992 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
993 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
994 }
995
TEST_F(WebFrameTest,NoWideViewportIgnoresPageViewportWidthButAccountsScale)996 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale)
997 {
998 UseMockScrollbarSettings mockScrollbarSettings;
999 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1000
1001 FixedLayoutTestWebViewClient client;
1002 client.m_screenInfo.deviceScaleFactor = 1;
1003 int viewportWidth = 640;
1004 int viewportHeight = 480;
1005
1006 FrameTestHelpers::WebViewHelper webViewHelper;
1007 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1008 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1009 webViewHelper.webView()->settings()->setUseWideViewport(false);
1010 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1011
1012 // The page sets viewport width to 3000, but with UseWideViewport == false it must be ignored.
1013 // While the initial scale specified by the page must be accounted.
1014 EXPECT_EQ(viewportWidth / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1015 EXPECT_EQ(viewportHeight / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1016 }
1017
TEST_F(WebFrameTest,WideViewportSetsTo980WithoutViewportTag)1018 TEST_F(WebFrameTest, WideViewportSetsTo980WithoutViewportTag)
1019 {
1020 UseMockScrollbarSettings mockScrollbarSettings;
1021 registerMockedHttpURLLoad("no_viewport_tag.html");
1022
1023 FixedLayoutTestWebViewClient client;
1024 client.m_screenInfo.deviceScaleFactor = 1;
1025 int viewportWidth = 640;
1026 int viewportHeight = 480;
1027
1028 FrameTestHelpers::WebViewHelper webViewHelper;
1029 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
1030 applyViewportStyleOverride(&webViewHelper);
1031 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1032 webViewHelper.webView()->settings()->setUseWideViewport(true);
1033 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1034
1035 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1036 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1037 }
1038
TEST_F(WebFrameTest,NoWideViewportAndHeightInMeta)1039 TEST_F(WebFrameTest, NoWideViewportAndHeightInMeta)
1040 {
1041 UseMockScrollbarSettings mockScrollbarSettings;
1042 registerMockedHttpURLLoad("viewport-height-1000.html");
1043
1044 FixedLayoutTestWebViewClient client;
1045 client.m_screenInfo.deviceScaleFactor = 1;
1046 int viewportWidth = 640;
1047 int viewportHeight = 480;
1048
1049 FrameTestHelpers::WebViewHelper webViewHelper;
1050 webViewHelper.initializeAndLoad(m_baseURL + "viewport-height-1000.html", true, 0, &client, enableViewportSettings);
1051 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1052 webViewHelper.webView()->settings()->setUseWideViewport(false);
1053 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1054
1055 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1056 }
1057
TEST_F(WebFrameTest,WideViewportSetsTo980WithAutoWidth)1058 TEST_F(WebFrameTest, WideViewportSetsTo980WithAutoWidth)
1059 {
1060 UseMockScrollbarSettings mockScrollbarSettings;
1061 registerMockedHttpURLLoad("viewport-2x-initial-scale.html");
1062
1063 FixedLayoutTestWebViewClient client;
1064 client.m_screenInfo.deviceScaleFactor = 1;
1065 int viewportWidth = 640;
1066 int viewportHeight = 480;
1067
1068 FrameTestHelpers::WebViewHelper webViewHelper;
1069 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1070 applyViewportStyleOverride(&webViewHelper);
1071 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1072 webViewHelper.webView()->settings()->setUseWideViewport(true);
1073 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1074
1075 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1076 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height());
1077 }
1078
TEST_F(WebFrameTest,PageViewportInitialScaleOverridesLoadWithOverviewMode)1079 TEST_F(WebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode)
1080 {
1081 UseMockScrollbarSettings mockScrollbarSettings;
1082 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1083
1084 FixedLayoutTestWebViewClient client;
1085 client.m_screenInfo.deviceScaleFactor = 1;
1086 int viewportWidth = 640;
1087 int viewportHeight = 480;
1088
1089 FrameTestHelpers::WebViewHelper webViewHelper;
1090 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1091 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1092 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1093
1094 // The page must be displayed at 200% zoom, as specified in its viewport meta tag.
1095 EXPECT_EQ(2.0f, webViewHelper.webView()->pageScaleFactor());
1096 }
1097
TEST_F(WebFrameTest,setInitialPageScaleFactorPermanently)1098 TEST_F(WebFrameTest, setInitialPageScaleFactorPermanently)
1099 {
1100 UseMockScrollbarSettings mockScrollbarSettings;
1101
1102 registerMockedHttpURLLoad("fixed_layout.html");
1103
1104 FixedLayoutTestWebViewClient client;
1105 client.m_screenInfo.deviceScaleFactor = 1;
1106 float enforcedPageScaleFactor = 2.0f;
1107
1108 FrameTestHelpers::WebViewHelper webViewHelper;
1109 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1110 applyViewportStyleOverride(&webViewHelper);
1111 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1112 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1113 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1114 webViewHelper.webView()->layout();
1115
1116 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1117
1118 int viewportWidth = 640;
1119 int viewportHeight = 480;
1120 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1121 webViewHelper.webView()->layout();
1122
1123 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1124
1125 webViewHelper.webView()->setInitialPageScaleOverride(-1);
1126 webViewHelper.webView()->layout();
1127 EXPECT_EQ(1.0, webViewHelper.webView()->pageScaleFactor());
1128 }
1129
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode)1130 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode)
1131 {
1132 UseMockScrollbarSettings mockScrollbarSettings;
1133 registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
1134
1135 FixedLayoutTestWebViewClient client;
1136 client.m_screenInfo.deviceScaleFactor = 1;
1137 int viewportWidth = 640;
1138 int viewportHeight = 480;
1139 float enforcedPageScaleFactor = 0.5f;
1140
1141 FrameTestHelpers::WebViewHelper webViewHelper;
1142 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings);
1143 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1144 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1145 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1146
1147 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1148 }
1149
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorOverridesPageViewportInitialScale)1150 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorOverridesPageViewportInitialScale)
1151 {
1152 UseMockScrollbarSettings mockScrollbarSettings;
1153 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
1154
1155 FixedLayoutTestWebViewClient client;
1156 client.m_screenInfo.deviceScaleFactor = 1;
1157 int viewportWidth = 640;
1158 int viewportHeight = 480;
1159 float enforcedPageScaleFactor = 0.5f;
1160
1161 FrameTestHelpers::WebViewHelper webViewHelper;
1162 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings);
1163 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1164 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1165
1166 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1167 }
1168
TEST_F(WebFrameTest,SmallPermanentInitialPageScaleFactorIsClobbered)1169 TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered)
1170 {
1171 UseMockScrollbarSettings mockScrollbarSettings;
1172 const char* pages[] = {
1173 // These pages trigger the clobbering condition. There must be a matching item in "pageScaleFactors" array.
1174 "viewport-device-0.5x-initial-scale.html",
1175 "viewport-initial-scale-1.html",
1176 // These ones do not.
1177 "viewport-auto-initial-scale.html",
1178 "viewport-target-densitydpi-device-and-fixed-width.html"
1179 };
1180 float pageScaleFactors[] = { 0.5f, 1.0f };
1181 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i)
1182 registerMockedHttpURLLoad(pages[i]);
1183
1184 FixedLayoutTestWebViewClient client;
1185 client.m_screenInfo.deviceScaleFactor = 1;
1186 int viewportWidth = 400;
1187 int viewportHeight = 300;
1188 float enforcedPageScaleFactor = 0.75f;
1189
1190 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i) {
1191 for (int quirkEnabled = 0; quirkEnabled <= 1; ++quirkEnabled) {
1192 FrameTestHelpers::WebViewHelper webViewHelper;
1193 webViewHelper.initializeAndLoad(m_baseURL + pages[i], true, 0, &client, enableViewportSettings);
1194 applyViewportStyleOverride(&webViewHelper);
1195 webViewHelper.webView()->settings()->setClobberUserAgentInitialScaleQuirk(quirkEnabled);
1196 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1197 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1198
1199 float expectedPageScaleFactor = quirkEnabled && i < ARRAY_SIZE(pageScaleFactors) ? pageScaleFactors[i] : enforcedPageScaleFactor;
1200 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1201 }
1202 }
1203 }
1204
TEST_F(WebFrameTest,PermanentInitialPageScaleFactorAffectsLayoutWidth)1205 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth)
1206 {
1207 UseMockScrollbarSettings mockScrollbarSettings;
1208
1209 FixedLayoutTestWebViewClient client;
1210 client.m_screenInfo.deviceScaleFactor = 1;
1211 int viewportWidth = 640;
1212 int viewportHeight = 480;
1213 float enforcedPageScaleFactor = 0.5;
1214
1215 FrameTestHelpers::WebViewHelper webViewHelper;
1216 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1217 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1218 webViewHelper.webView()->settings()->setUseWideViewport(false);
1219 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
1220 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1221 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1222
1223 EXPECT_EQ(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1224 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1225 }
1226
TEST_F(WebFrameTest,SetForceZeroLayoutHeight)1227 TEST_F(WebFrameTest, SetForceZeroLayoutHeight)
1228 {
1229 UseMockScrollbarSettings mockScrollbarSettings;
1230 registerMockedHttpURLLoad("200-by-300.html");
1231
1232 FixedLayoutTestWebViewClient client;
1233 client.m_screenInfo.deviceScaleFactor = 1;
1234 int viewportWidth = 640;
1235 int viewportHeight = 480;
1236
1237 FrameTestHelpers::WebViewHelper webViewHelper;
1238
1239 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1240 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1241 webViewHelper.webView()->layout();
1242
1243 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1244 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1245 EXPECT_TRUE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1246
1247 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1248
1249 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight * 2));
1250 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1251 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1252
1253 webViewHelper.webView()->resize(WebSize(viewportWidth * 2, viewportHeight));
1254 webViewHelper.webView()->layout();
1255 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1256
1257 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(false);
1258 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1259 }
1260
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWorksAcrossNavigations)1261 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations)
1262 {
1263 UseMockScrollbarSettings mockScrollbarSettings;
1264 registerMockedHttpURLLoad("200-by-300.html");
1265 registerMockedHttpURLLoad("large-div.html");
1266
1267 FixedLayoutTestWebViewClient client;
1268 client.m_screenInfo.deviceScaleFactor = 1;
1269 int viewportWidth = 640;
1270 int viewportHeight = 480;
1271
1272 FrameTestHelpers::WebViewHelper webViewHelper;
1273
1274 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1275 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1276 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1277 webViewHelper.webView()->layout();
1278
1279 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
1280 webViewHelper.webView()->layout();
1281
1282 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1283 }
1284
TEST_F(WebFrameTest,SetForceZeroLayoutHeightWithWideViewportQuirk)1285 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk)
1286 {
1287 UseMockScrollbarSettings mockScrollbarSettings;
1288 registerMockedHttpURLLoad("200-by-300.html");
1289
1290 FixedLayoutTestWebViewClient client;
1291 client.m_screenInfo.deviceScaleFactor = 1;
1292 int viewportWidth = 640;
1293 int viewportHeight = 480;
1294
1295 FrameTestHelpers::WebViewHelper webViewHelper;
1296
1297 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1298 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1299 webViewHelper.webView()->settings()->setUseWideViewport(true);
1300 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1301 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1302 webViewHelper.webView()->layout();
1303
1304 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1305 }
1306
TEST_F(WebFrameTest,WideViewportAndWideContentWithInitialScale)1307 TEST_F(WebFrameTest, WideViewportAndWideContentWithInitialScale)
1308 {
1309 UseMockScrollbarSettings mockScrollbarSettings;
1310 registerMockedHttpURLLoad("wide_document_width_viewport.html");
1311
1312 FixedLayoutTestWebViewClient client;
1313 client.m_screenInfo.deviceScaleFactor = 1;
1314 int viewportWidth = 600;
1315 int viewportHeight = 800;
1316
1317 FrameTestHelpers::WebViewHelper webViewHelper;
1318 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1319 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1320 webViewHelper.webView()->settings()->setUseWideViewport(true);
1321 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1322 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1323
1324 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "wide_document_width_viewport.html");
1325 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1326
1327 int wideDocumentWidth = 800;
1328 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth;
1329 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1330 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor());
1331 }
1332
TEST_F(WebFrameTest,WideViewportQuirkClobbersHeight)1333 TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight)
1334 {
1335 UseMockScrollbarSettings mockScrollbarSettings;
1336 registerMockedHttpURLLoad("viewport-height-1000.html");
1337
1338 FixedLayoutTestWebViewClient client;
1339 client.m_screenInfo.deviceScaleFactor = 1;
1340 int viewportWidth = 600;
1341 int viewportHeight = 800;
1342
1343 FrameTestHelpers::WebViewHelper webViewHelper;
1344 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1345 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1346 webViewHelper.webView()->settings()->setUseWideViewport(false);
1347 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1348 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1349
1350 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-height-1000.html");
1351 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1352
1353 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1354 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1355 }
1356
TEST_F(WebFrameTest,LayoutSize320Quirk)1357 TEST_F(WebFrameTest, LayoutSize320Quirk)
1358 {
1359 UseMockScrollbarSettings mockScrollbarSettings;
1360 registerMockedHttpURLLoad("viewport/viewport-30.html");
1361
1362 FixedLayoutTestWebViewClient client;
1363 client.m_screenInfo.deviceScaleFactor = 1;
1364 int viewportWidth = 600;
1365 int viewportHeight = 800;
1366
1367 FrameTestHelpers::WebViewHelper webViewHelper;
1368 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1369 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1370 webViewHelper.webView()->settings()->setUseWideViewport(true);
1371 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1372 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1373
1374 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport/viewport-30.html");
1375 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1376
1377 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1378 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1379 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1380
1381 // The magic number to snap to device-width is 320, so test that 321 is
1382 // respected.
1383 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
1384 ViewportDescription description = document->viewportDescription();
1385 description.minWidth = Length(321, blink::Fixed);
1386 description.maxWidth = Length(321, blink::Fixed);
1387 document->setViewportDescription(description);
1388 webViewHelper.webView()->layout();
1389 EXPECT_EQ(321, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1390
1391 description.minWidth = Length(320, blink::Fixed);
1392 description.maxWidth = Length(320, blink::Fixed);
1393 document->setViewportDescription(description);
1394 webViewHelper.webView()->layout();
1395 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1396
1397 description = document->viewportDescription();
1398 description.maxHeight = Length(1000, blink::Fixed);
1399 document->setViewportDescription(description);
1400 webViewHelper.webView()->layout();
1401 EXPECT_EQ(1000, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1402
1403 description.maxHeight = Length(320, blink::Fixed);
1404 document->setViewportDescription(description);
1405 webViewHelper.webView()->layout();
1406 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1407 }
1408
TEST_F(WebFrameTest,ZeroValuesQuirk)1409 TEST_F(WebFrameTest, ZeroValuesQuirk)
1410 {
1411 UseMockScrollbarSettings mockScrollbarSettings;
1412 registerMockedHttpURLLoad("viewport-zero-values.html");
1413
1414 FixedLayoutTestWebViewClient client;
1415 client.m_screenInfo.deviceScaleFactor = 1;
1416 int viewportWidth = 640;
1417 int viewportHeight = 480;
1418
1419 FrameTestHelpers::WebViewHelper webViewHelper;
1420 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1421 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1422 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1423 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1424 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-zero-values.html");
1425 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1426
1427 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1428 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1429
1430 webViewHelper.webView()->settings()->setUseWideViewport(true);
1431 webViewHelper.webView()->layout();
1432 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1433 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1434 }
1435
TEST_F(WebFrameTest,OverflowHiddenDisablesScrolling)1436 TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling)
1437 {
1438 registerMockedHttpURLLoad("body-overflow-hidden.html");
1439
1440 FixedLayoutTestWebViewClient client;
1441 client.m_screenInfo.deviceScaleFactor = 1;
1442 int viewportWidth = 640;
1443 int viewportHeight = 480;
1444
1445 FrameTestHelpers::WebViewHelper webViewHelper;
1446 webViewHelper.initialize(true, 0, &client);
1447 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1448 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1449
1450 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1451 EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
1452 }
1453
TEST_F(WebFrameTest,IgnoreOverflowHiddenQuirk)1454 TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk)
1455 {
1456 registerMockedHttpURLLoad("body-overflow-hidden.html");
1457
1458 FixedLayoutTestWebViewClient client;
1459 client.m_screenInfo.deviceScaleFactor = 1;
1460 int viewportWidth = 640;
1461 int viewportHeight = 480;
1462
1463 FrameTestHelpers::WebViewHelper webViewHelper;
1464 webViewHelper.initialize(true, 0, &client);
1465 webViewHelper.webView()->settings()->setIgnoreMainFrameOverflowHiddenQuirk(true);
1466 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1467 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1468
1469 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1470 EXPECT_TRUE(view->userInputScrollable(VerticalScrollbar));
1471 }
1472
TEST_F(WebFrameTest,NonZeroValuesNoQuirk)1473 TEST_F(WebFrameTest, NonZeroValuesNoQuirk)
1474 {
1475 UseMockScrollbarSettings mockScrollbarSettings;
1476 registerMockedHttpURLLoad("viewport-nonzero-values.html");
1477
1478 FixedLayoutTestWebViewClient client;
1479 client.m_screenInfo.deviceScaleFactor = 1;
1480 int viewportWidth = 640;
1481 int viewportHeight = 480;
1482 float expectedPageScaleFactor = 0.5f;
1483
1484 FrameTestHelpers::WebViewHelper webViewHelper;
1485 webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1486 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1487 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1488 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-nonzero-values.html");
1489 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1490
1491 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1492 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1493
1494 webViewHelper.webView()->settings()->setUseWideViewport(true);
1495 webViewHelper.webView()->layout();
1496 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1497 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1498 }
1499
TEST_F(WebFrameTest,setPageScaleFactorDoesNotLayout)1500 TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout)
1501 {
1502 UseMockScrollbarSettings mockScrollbarSettings;
1503 registerMockedHttpURLLoad("fixed_layout.html");
1504
1505 FixedLayoutTestWebViewClient client;
1506 client.m_screenInfo.deviceScaleFactor = 1;
1507 // Small viewport to ensure there are always scrollbars.
1508 int viewportWidth = 64;
1509 int viewportHeight = 48;
1510
1511 FrameTestHelpers::WebViewHelper webViewHelper;
1512 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1513 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1514 webViewHelper.webView()->layout();
1515
1516 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1517 webViewHelper.webViewImpl()->setPageScaleFactor(3);
1518 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1519 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1520 }
1521
TEST_F(WebFrameTest,setPageScaleFactorWithOverlayScrollbarsDoesNotLayout)1522 TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout)
1523 {
1524 UseMockScrollbarSettings mockScrollbarSettings;
1525
1526 registerMockedHttpURLLoad("fixed_layout.html");
1527
1528 FixedLayoutTestWebViewClient client;
1529 client.m_screenInfo.deviceScaleFactor = 1;
1530 int viewportWidth = 640;
1531 int viewportHeight = 480;
1532
1533 FrameTestHelpers::WebViewHelper webViewHelper;
1534 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1535 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1536 webViewHelper.webView()->layout();
1537
1538 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1539 webViewHelper.webViewImpl()->setPageScaleFactor(30);
1540 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1541 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1542
1543 }
1544
TEST_F(WebFrameTest,pageScaleFactorWrittenToHistoryItem)1545 TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem)
1546 {
1547 UseMockScrollbarSettings mockScrollbarSettings;
1548 registerMockedHttpURLLoad("fixed_layout.html");
1549
1550 FixedLayoutTestWebViewClient client;
1551 client.m_screenInfo.deviceScaleFactor = 1;
1552 int viewportWidth = 640;
1553 int viewportHeight = 480;
1554
1555 FrameTestHelpers::WebViewHelper webViewHelper;
1556 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1557 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1558 webViewHelper.webView()->layout();
1559
1560 webViewHelper.webView()->setPageScaleFactor(3);
1561 EXPECT_EQ(3, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1562 }
1563
TEST_F(WebFrameTest,initialScaleWrittenToHistoryItem)1564 TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem)
1565 {
1566 UseMockScrollbarSettings mockScrollbarSettings;
1567 registerMockedHttpURLLoad("fixed_layout.html");
1568
1569 FixedLayoutTestWebViewClient client;
1570 client.m_screenInfo.deviceScaleFactor = 1;
1571 int viewportWidth = 640;
1572 int viewportHeight = 480;
1573
1574 FrameTestHelpers::WebViewHelper webViewHelper;
1575 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1576 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1577 webViewHelper.webView()->layout();
1578
1579 int defaultFixedLayoutWidth = 980;
1580 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
1581 EXPECT_EQ(minimumPageScaleFactor, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1582 }
1583
TEST_F(WebFrameTest,pageScaleFactorShrinksViewport)1584 TEST_F(WebFrameTest, pageScaleFactorShrinksViewport)
1585 {
1586 UseMockScrollbarSettings mockScrollbarSettings;
1587 registerMockedHttpURLLoad("large-div.html");
1588
1589 FixedLayoutTestWebViewClient client;
1590 client.m_screenInfo.deviceScaleFactor = 1;
1591 // Small viewport to ensure there are always scrollbars.
1592 int viewportWidth = 64;
1593 int viewportHeight = 48;
1594
1595 FrameTestHelpers::WebViewHelper webViewHelper;
1596 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1597 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1598 webViewHelper.webView()->layout();
1599
1600 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1601 int viewportWidthMinusScrollbar = viewportWidth - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
1602 int viewportHeightMinusScrollbar = viewportHeight - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
1603
1604 webViewHelper.webView()->setPageScaleFactor(2);
1605
1606 IntSize unscaledSize = view->unscaledVisibleContentSize(IncludeScrollbars);
1607 EXPECT_EQ(viewportWidth, unscaledSize.width());
1608 EXPECT_EQ(viewportHeight, unscaledSize.height());
1609
1610 IntSize unscaledSizeMinusScrollbar = view->unscaledVisibleContentSize(ExcludeScrollbars);
1611 EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width());
1612 EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height());
1613
1614 IntSize scaledSize = view->visibleContentRect().size();
1615 EXPECT_EQ(ceil(viewportWidthMinusScrollbar / 2.0), scaledSize.width());
1616 EXPECT_EQ(ceil(viewportHeightMinusScrollbar / 2.0), scaledSize.height());
1617 }
1618
TEST_F(WebFrameTest,pageScaleFactorDoesNotApplyCssTransform)1619 TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform)
1620 {
1621 UseMockScrollbarSettings mockScrollbarSettings;
1622 registerMockedHttpURLLoad("fixed_layout.html");
1623
1624 FixedLayoutTestWebViewClient client;
1625 client.m_screenInfo.deviceScaleFactor = 1;
1626 int viewportWidth = 640;
1627 int viewportHeight = 480;
1628
1629 FrameTestHelpers::WebViewHelper webViewHelper;
1630 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1631 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1632 webViewHelper.webView()->layout();
1633
1634 webViewHelper.webView()->setPageScaleFactor(2);
1635
1636 EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentRenderer()->unscaledDocumentRect().width());
1637 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1638 }
1639
TEST_F(WebFrameTest,targetDensityDpiHigh)1640 TEST_F(WebFrameTest, targetDensityDpiHigh)
1641 {
1642 UseMockScrollbarSettings mockScrollbarSettings;
1643 registerMockedHttpURLLoad("viewport-target-densitydpi-high.html");
1644
1645 FixedLayoutTestWebViewClient client;
1646 // high-dpi = 240
1647 float targetDpi = 240.0f;
1648 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1649 int viewportWidth = 640;
1650 int viewportHeight = 480;
1651
1652 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1653 float deviceScaleFactor = deviceScaleFactors[i];
1654 float deviceDpi = deviceScaleFactor * 160.0f;
1655 client.m_screenInfo.deviceScaleFactor = deviceScaleFactor;
1656
1657 FrameTestHelpers::WebViewHelper webViewHelper;
1658 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-high.html", true, 0, &client, enableViewportSettings);
1659 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1660 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1661 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1662
1663 // We need to account for the fact that logical pixels are unconditionally multiplied by deviceScaleFactor to produce
1664 // physical pixels.
1665 float densityDpiScaleRatio = deviceScaleFactor * targetDpi / deviceDpi;
1666 EXPECT_NEAR(viewportWidth * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1667 EXPECT_NEAR(viewportHeight * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1668 EXPECT_NEAR(1.0f / densityDpiScaleRatio, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1669 }
1670 }
1671
TEST_F(WebFrameTest,targetDensityDpiDevice)1672 TEST_F(WebFrameTest, targetDensityDpiDevice)
1673 {
1674 UseMockScrollbarSettings mockScrollbarSettings;
1675 registerMockedHttpURLLoad("viewport-target-densitydpi-device.html");
1676
1677 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1678
1679 FixedLayoutTestWebViewClient client;
1680 int viewportWidth = 640;
1681 int viewportHeight = 480;
1682
1683 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1684 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
1685
1686 FrameTestHelpers::WebViewHelper webViewHelper;
1687 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device.html", true, 0, &client, enableViewportSettings);
1688 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1689 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1690 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1691
1692 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1693 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1694 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1695 }
1696 }
1697
TEST_F(WebFrameTest,targetDensityDpiDeviceAndFixedWidth)1698 TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth)
1699 {
1700 UseMockScrollbarSettings mockScrollbarSettings;
1701 registerMockedHttpURLLoad("viewport-target-densitydpi-device-and-fixed-width.html");
1702
1703 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1704
1705 FixedLayoutTestWebViewClient client;
1706 int viewportWidth = 640;
1707 int viewportHeight = 480;
1708
1709 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1710 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
1711
1712 FrameTestHelpers::WebViewHelper webViewHelper;
1713 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device-and-fixed-width.html", true, 0, &client, enableViewportSettings);
1714 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1715 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1716 webViewHelper.webView()->settings()->setUseWideViewport(true);
1717 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1718
1719 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1720 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1721 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1722 }
1723 }
1724
TEST_F(WebFrameTest,NoWideViewportAndScaleLessThanOne)1725 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne)
1726 {
1727 UseMockScrollbarSettings mockScrollbarSettings;
1728 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
1729
1730 FixedLayoutTestWebViewClient client;
1731 client.m_screenInfo.deviceScaleFactor = 1.33f;
1732 int viewportWidth = 640;
1733 int viewportHeight = 480;
1734
1735 FrameTestHelpers::WebViewHelper webViewHelper;
1736 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1.html", true, 0, &client, enableViewportSettings);
1737 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1738 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1739 webViewHelper.webView()->settings()->setUseWideViewport(false);
1740 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1741 webViewHelper.webView()->layout();
1742
1743 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1744 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1745 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1746 }
1747
TEST_F(WebFrameTest,NoWideViewportAndScaleLessThanOneWithDeviceWidth)1748 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth)
1749 {
1750 UseMockScrollbarSettings mockScrollbarSettings;
1751 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1-device-width.html");
1752
1753 FixedLayoutTestWebViewClient client;
1754 client.m_screenInfo.deviceScaleFactor = 1.33f;
1755 int viewportWidth = 640;
1756 int viewportHeight = 480;
1757
1758 FrameTestHelpers::WebViewHelper webViewHelper;
1759 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true, 0, &client, enableViewportSettings);
1760 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1761 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1762 webViewHelper.webView()->settings()->setUseWideViewport(false);
1763 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1764 webViewHelper.webView()->layout();
1765
1766 const float pageZoom = 0.25f;
1767 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1768 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1769 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1770 }
1771
TEST_F(WebFrameTest,NoWideViewportAndNoViewportWithInitialPageScaleOverride)1772 TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride)
1773 {
1774 UseMockScrollbarSettings mockScrollbarSettings;
1775 registerMockedHttpURLLoad("large-div.html");
1776
1777 FixedLayoutTestWebViewClient client;
1778 int viewportWidth = 640;
1779 int viewportHeight = 480;
1780 float enforcedPageScaleFactor = 5.0f;
1781
1782 FrameTestHelpers::WebViewHelper webViewHelper;
1783 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1784 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1785 webViewHelper.webView()->settings()->setUseWideViewport(false);
1786 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1787 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1788 webViewHelper.webView()->layout();
1789
1790 EXPECT_NEAR(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1791 EXPECT_NEAR(viewportHeight / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1792 EXPECT_NEAR(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1793 }
1794
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScale)1795 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScale)
1796 {
1797 UseMockScrollbarSettings mockScrollbarSettings;
1798 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
1799
1800 FixedLayoutTestWebViewClient client;
1801 int viewportWidth = 640;
1802 int viewportHeight = 480;
1803
1804 FrameTestHelpers::WebViewHelper webViewHelper;
1805 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
1806 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1807 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1808 webViewHelper.webView()->layout();
1809
1810 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1811 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1812 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1813 }
1814
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport)1815 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport)
1816 {
1817 UseMockScrollbarSettings mockScrollbarSettings;
1818 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
1819
1820 FixedLayoutTestWebViewClient client;
1821 client.m_screenInfo.deviceScaleFactor = 1.33f;
1822 int viewportWidth = 640;
1823 int viewportHeight = 480;
1824
1825 FrameTestHelpers::WebViewHelper webViewHelper;
1826 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
1827 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1828 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1829 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1830 webViewHelper.webView()->settings()->setUseWideViewport(false);
1831 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1832 webViewHelper.webView()->layout();
1833
1834 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1835 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1836 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1837 }
1838
TEST_F(WebFrameTest,NoUserScalableQuirkIgnoresViewportScaleForWideViewport)1839 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport)
1840 {
1841 UseMockScrollbarSettings mockScrollbarSettings;
1842 registerMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html");
1843
1844 FixedLayoutTestWebViewClient client;
1845 int viewportWidth = 640;
1846 int viewportHeight = 480;
1847
1848 FrameTestHelpers::WebViewHelper webViewHelper;
1849 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale-non-user-scalable.html", true, 0, &client, enableViewportSettings);
1850 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1851 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1852 webViewHelper.webView()->settings()->setUseWideViewport(true);
1853 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1854
1855 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1856 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1857 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1858 }
1859
TEST_F(WebFrameTest,DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff)1860 TEST_F(WebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff)
1861 {
1862 UseMockScrollbarSettings mockScrollbarSettings;
1863 registerMockedHttpURLLoad("no_viewport_tag.html");
1864
1865 FixedLayoutTestWebViewClient client;
1866 int viewportWidth = 640;
1867 int viewportHeight = 480;
1868
1869 FrameTestHelpers::WebViewHelper webViewHelper;
1870 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
1871 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1872 webViewHelper.webView()->settings()->setUseWideViewport(false);
1873 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1874
1875 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1876 EXPECT_NEAR(1.0f, webViewHelper.webView()->minimumPageScaleFactor(), 0.01f);
1877 EXPECT_NEAR(5.0f, webViewHelper.webView()->maximumPageScaleFactor(), 0.01f);
1878 }
1879
1880 class WebFrameResizeTest : public WebFrameTest {
1881 protected:
1882
computeRelativeOffset(const IntPoint & absoluteOffset,const LayoutRect & rect)1883 static FloatSize computeRelativeOffset(const IntPoint& absoluteOffset, const LayoutRect& rect)
1884 {
1885 FloatSize relativeOffset = FloatPoint(absoluteOffset) - rect.location();
1886 relativeOffset.scale(1.f / rect.width(), 1.f / rect.height());
1887 return relativeOffset;
1888 }
1889
testResizeYieldsCorrectScrollAndScale(const char * url,const float initialPageScaleFactor,const WebSize scrollOffset,const WebSize viewportSize,const bool shouldScaleRelativeToViewportWidth)1890 void testResizeYieldsCorrectScrollAndScale(const char* url,
1891 const float initialPageScaleFactor,
1892 const WebSize scrollOffset,
1893 const WebSize viewportSize,
1894 const bool shouldScaleRelativeToViewportWidth) {
1895 UseMockScrollbarSettings mockScrollbarSettings;
1896 registerMockedHttpURLLoad(url);
1897
1898 const float aspectRatio = static_cast<float>(viewportSize.width) / viewportSize.height;
1899
1900 FrameTestHelpers::WebViewHelper webViewHelper;
1901 webViewHelper.initializeAndLoad(m_baseURL + url, true, 0, 0, enableViewportSettings);
1902
1903 // Origin scrollOffsets preserved under resize.
1904 {
1905 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
1906 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
1907 ASSERT_EQ(viewportSize, webViewHelper.webViewImpl()->size());
1908 ASSERT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1909 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
1910 float expectedPageScaleFactor = initialPageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1);
1911 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
1912 EXPECT_EQ(WebSize(), webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
1913 }
1914
1915 // Resizing just the height should not affect pageScaleFactor or scrollOffset.
1916 {
1917 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
1918 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
1919 webViewHelper.webViewImpl()->setMainFrameScrollOffset(WebPoint(scrollOffset.width, scrollOffset.height));
1920 webViewHelper.webViewImpl()->layout();
1921 const WebSize expectedScrollOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
1922 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
1923 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1924 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
1925 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
1926 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
1927 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
1928 }
1929
1930 // Generic resize preserves scrollOffset relative to anchor node located
1931 // the top center of the screen.
1932 {
1933 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
1934 float pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor();
1935 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
1936 float expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? aspectRatio : 1);
1937 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
1938 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(scrollOffset);
1939
1940 IntPoint anchorPoint = IntPoint(scrollOffset) + IntPoint(viewportSize.width / 2, 0);
1941 RefPtrWillBeRawPtr<Node> anchorNode = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->eventHandler().hitTestResultAtPoint(anchorPoint, HitTestRequest::ReadOnly | HitTestRequest::Active).innerNode();
1942 ASSERT(anchorNode);
1943
1944 pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor();
1945 const FloatSize preResizeRelativeOffset
1946 = computeRelativeOffset(anchorPoint, anchorNode->boundingBox());
1947 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
1948 IntPoint newAnchorPoint = IntPoint(webViewHelper.webViewImpl()->mainFrame()->scrollOffset()) + IntPoint(viewportSize.height / 2, 0);
1949 const FloatSize postResizeRelativeOffset
1950 = computeRelativeOffset(newAnchorPoint, anchorNode->boundingBox());
1951 EXPECT_NEAR(preResizeRelativeOffset.width(), postResizeRelativeOffset.width(), 0.15f);
1952 expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1);
1953 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
1954 }
1955 }
1956 };
1957
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth)1958 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth)
1959 {
1960 // With width=device-width, pageScaleFactor is preserved across resizes as
1961 // long as the content adjusts according to the device-width.
1962 const char* url = "resize_scroll_mobile.html";
1963 const float initialPageScaleFactor = 1;
1964 const WebSize scrollOffset(0, 50);
1965 const WebSize viewportSize(120, 160);
1966 const bool shouldScaleRelativeToViewportWidth = true;
1967
1968 testResizeYieldsCorrectScrollAndScale(
1969 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
1970 }
1971
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForMinimumScale)1972 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForMinimumScale)
1973 {
1974 // This tests a scenario where minimum-scale is set to 1.0, but some element
1975 // on the page is slightly larger than the portrait width, so our "natural"
1976 // minimum-scale would be lower. In that case, we should stick to 1.0 scale
1977 // on rotation and not do anything strange.
1978 const char* url = "resize_scroll_minimum_scale.html";
1979 const float initialPageScaleFactor = 1;
1980 const WebSize scrollOffset(0, 0);
1981 const WebSize viewportSize(240, 320);
1982 const bool shouldScaleRelativeToViewportWidth = false;
1983
1984 testResizeYieldsCorrectScrollAndScale(
1985 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
1986 }
1987
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForFixedWidth)1988 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedWidth)
1989 {
1990 // With a fixed width, pageScaleFactor scales by the relative change in viewport width.
1991 const char* url = "resize_scroll_fixed_width.html";
1992 const float initialPageScaleFactor = 2;
1993 const WebSize scrollOffset(0, 200);
1994 const WebSize viewportSize(240, 320);
1995 const bool shouldScaleRelativeToViewportWidth = true;
1996
1997 testResizeYieldsCorrectScrollAndScale(
1998 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
1999 }
2000
TEST_F(WebFrameResizeTest,ResizeYieldsCorrectScrollAndScaleForFixedLayout)2001 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout)
2002 {
2003 // With a fixed layout, pageScaleFactor scales by the relative change in viewport width.
2004 const char* url = "resize_scroll_fixed_layout.html";
2005 const float initialPageScaleFactor = 2;
2006 const WebSize scrollOffset(200, 400);
2007 const WebSize viewportSize(320, 240);
2008 const bool shouldScaleRelativeToViewportWidth = true;
2009
2010 testResizeYieldsCorrectScrollAndScale(
2011 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2012 }
2013
TEST_F(WebFrameTest,pageScaleFactorScalesPaintClip)2014 TEST_F(WebFrameTest, pageScaleFactorScalesPaintClip)
2015 {
2016 UseMockScrollbarSettings mockScrollbarSettings;
2017 registerMockedHttpURLLoad("large-div.html");
2018
2019 FixedLayoutTestWebViewClient client;
2020 client.m_screenInfo.deviceScaleFactor = 1;
2021 int viewportWidth = 50;
2022 int viewportHeight = 50;
2023
2024 FrameTestHelpers::WebViewHelper webViewHelper;
2025 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client);
2026 // FIXME: This test breaks if the viewport is enabled before loading the page due to the paint
2027 // calls below not working on composited layers. For some reason, enabling the viewport here
2028 // doesn't cause compositing
2029 webViewHelper.webView()->settings()->setViewportEnabled(true);
2030 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2031 webViewHelper.webView()->layout();
2032
2033 // Set <1 page scale so that the clip rect should be larger than
2034 // the viewport size as passed into resize().
2035 webViewHelper.webView()->setPageScaleFactor(0.5);
2036
2037 SkBitmap bitmap;
2038 bitmap.allocN32Pixels(200, 200);
2039 bitmap.eraseColor(0);
2040 SkCanvas canvas(bitmap);
2041
2042 GraphicsContext context(&canvas);
2043 context.setRegionTrackingMode(GraphicsContext::RegionTrackingOpaque);
2044
2045 EXPECT_RECT_EQ(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect());
2046
2047 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2048 IntRect paintRect(0, 0, 200, 200);
2049 view->paint(&context, paintRect);
2050
2051 // FIXME: This test broke in release builds when changing the FixedLayoutTestWebViewClient
2052 // to return a non-null layerTreeView, which is what all our shipping configurations do,
2053 // so this is just exposing an existing bug.
2054 // crbug.com/365812
2055 #ifndef NDEBUG
2056 int viewportWidthMinusScrollbar = 50 - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
2057 int viewportHeightMinusScrollbar = 50 - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
2058 IntRect clippedRect(0, 0, viewportWidthMinusScrollbar * 2, viewportHeightMinusScrollbar * 2);
2059 EXPECT_RECT_EQ(clippedRect, context.opaqueRegion().asRect());
2060 #endif
2061 }
2062
TEST_F(WebFrameTest,pageScaleFactorUpdatesScrollbars)2063 TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars)
2064 {
2065 UseMockScrollbarSettings mockScrollbarSettings;
2066 registerMockedHttpURLLoad("fixed_layout.html");
2067
2068 FixedLayoutTestWebViewClient client;
2069 client.m_screenInfo.deviceScaleFactor = 1;
2070 int viewportWidth = 640;
2071 int viewportHeight = 480;
2072
2073 FrameTestHelpers::WebViewHelper webViewHelper;
2074 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
2075 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2076 webViewHelper.webView()->layout();
2077
2078 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2079 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2080 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2081
2082 webViewHelper.webView()->setPageScaleFactor(10);
2083
2084 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2085 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2086 }
2087
TEST_F(WebFrameTest,CanOverrideScaleLimits)2088 TEST_F(WebFrameTest, CanOverrideScaleLimits)
2089 {
2090 UseMockScrollbarSettings mockScrollbarSettings;
2091
2092 registerMockedHttpURLLoad("no_scale_for_you.html");
2093
2094 FixedLayoutTestWebViewClient client;
2095 client.m_screenInfo.deviceScaleFactor = 1;
2096 int viewportWidth = 640;
2097 int viewportHeight = 480;
2098
2099 FrameTestHelpers::WebViewHelper webViewHelper;
2100 webViewHelper.initializeAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client, enableViewportSettings);
2101 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2102
2103 EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor());
2104 EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor());
2105
2106 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(true);
2107 webViewHelper.webView()->layout();
2108
2109 EXPECT_EQ(1.0f, webViewHelper.webView()->minimumPageScaleFactor());
2110 EXPECT_EQ(5.0f, webViewHelper.webView()->maximumPageScaleFactor());
2111
2112 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(false);
2113 webViewHelper.webView()->layout();
2114
2115 EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor());
2116 EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor());
2117 }
2118
TEST_F(WebFrameTest,updateOverlayScrollbarLayers)2119 TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
2120 {
2121 UseMockScrollbarSettings mockScrollbarSettings;
2122
2123 registerMockedHttpURLLoad("large-div.html");
2124
2125 int viewWidth = 500;
2126 int viewHeight = 500;
2127
2128 OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
2129 FrameTestHelpers::WebViewHelper webViewHelper;
2130 webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
2131
2132 webViewHelper.webView()->setPageScaleFactorLimits(1, 1);
2133 webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
2134 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
2135
2136 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2137 EXPECT_TRUE(view->renderView()->compositor()->layerForHorizontalScrollbar());
2138 EXPECT_TRUE(view->renderView()->compositor()->layerForVerticalScrollbar());
2139
2140 webViewHelper.webView()->resize(WebSize(viewWidth * 10, viewHeight * 10));
2141 webViewHelper.webView()->layout();
2142 EXPECT_FALSE(view->renderView()->compositor()->layerForHorizontalScrollbar());
2143 EXPECT_FALSE(view->renderView()->compositor()->layerForVerticalScrollbar());
2144 }
2145
setScaleAndScrollAndLayout(WebView * webView,WebPoint scroll,float scale)2146 void setScaleAndScrollAndLayout(WebView* webView, WebPoint scroll, float scale)
2147 {
2148 webView->setPageScaleFactor(scale);
2149 webView->setMainFrameScrollOffset(WebPoint(scroll.x, scroll.y));
2150 webView->layout();
2151 }
2152
TEST_F(WebFrameTest,DivAutoZoomParamsTest)2153 TEST_F(WebFrameTest, DivAutoZoomParamsTest)
2154 {
2155 registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html");
2156
2157 const float deviceScaleFactor = 2.0f;
2158 int viewportWidth = 640 / deviceScaleFactor;
2159 int viewportHeight = 1280 / deviceScaleFactor;
2160 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2161 FrameTestHelpers::WebViewHelper webViewHelper;
2162 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html");
2163 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2164 webViewHelper.webView()->setPageScaleFactorLimits(0.01f, 4);
2165 webViewHelper.webView()->setPageScaleFactor(0.5f);
2166 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2167 webViewHelper.webView()->layout();
2168
2169 WebRect wideDiv(200, 100, 400, 150);
2170 WebRect tallDiv(200, 300, 400, 800);
2171 WebRect doubleTapPointWide(wideDiv.x + 50, wideDiv.y + 50, touchPointPadding, touchPointPadding);
2172 WebRect doubleTapPointTall(tallDiv.x + 50, tallDiv.y + 50, touchPointPadding, touchPointPadding);
2173 WebRect wideBlockBounds;
2174 WebRect tallBlockBounds;
2175 float scale;
2176 WebPoint scroll;
2177
2178 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2179
2180 // Test double-tap zooming into wide div.
2181 wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false);
2182 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2183 // The div should horizontally fill the screen (modulo margins), and
2184 // vertically centered (modulo integer rounding).
2185 EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
2186 EXPECT_NEAR(wideDiv.x, scroll.x, 20);
2187 EXPECT_EQ(0, scroll.y);
2188
2189 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
2190
2191 // Test zoom out back to minimum scale.
2192 wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false);
2193 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2194
2195 scale = webViewHelper.webViewImpl()->minimumPageScaleFactor();
2196 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), scale);
2197
2198 // Test double-tap zooming into tall div.
2199 tallBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointTall, false);
2200 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointTall.x, doubleTapPointTall.y), tallBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2201 // The div should start at the top left of the viewport.
2202 EXPECT_NEAR(viewportWidth / (float) tallDiv.width, scale, 0.1);
2203 EXPECT_NEAR(tallDiv.x, scroll.x, 20);
2204 EXPECT_NEAR(tallDiv.y, scroll.y, 20);
2205
2206 // Test for Non-doubletap scaling
2207 // Test zooming into div.
2208 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(250, 250), webViewHelper.webViewImpl()->computeBlockBounds(WebRect(250, 250, 10, 10), true), 0, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2209 EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
2210 }
2211
simulatePageScale(WebViewImpl * webViewImpl,float & scale)2212 void simulatePageScale(WebViewImpl* webViewImpl, float& scale)
2213 {
2214 IntSize scrollDelta = webViewImpl->fakePageScaleAnimationTargetPositionForTesting() - webViewImpl->mainFrameImpl()->frameView()->scrollPosition();
2215 float scaleDelta = webViewImpl->fakePageScaleAnimationPageScaleForTesting() / webViewImpl->pageScaleFactor();
2216 webViewImpl->applyViewportDeltas(scrollDelta, scaleDelta, 0);
2217 scale = webViewImpl->pageScaleFactor();
2218 }
2219
simulateMultiTargetZoom(WebViewImpl * webViewImpl,const WebRect & rect,float & scale)2220 void simulateMultiTargetZoom(WebViewImpl* webViewImpl, const WebRect& rect, float& scale)
2221 {
2222 if (webViewImpl->zoomToMultipleTargetsRect(rect))
2223 simulatePageScale(webViewImpl, scale);
2224 }
2225
simulateDoubleTap(WebViewImpl * webViewImpl,WebPoint & point,float & scale)2226 void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale)
2227 {
2228 webViewImpl->animateDoubleTapZoom(point);
2229 EXPECT_TRUE(webViewImpl->fakeDoubleTapAnimationPendingForTesting());
2230 simulatePageScale(webViewImpl, scale);
2231 }
2232
TEST_F(WebFrameTest,DivAutoZoomWideDivTest)2233 TEST_F(WebFrameTest, DivAutoZoomWideDivTest)
2234 {
2235 registerMockedHttpURLLoad("get_wide_div_for_auto_zoom_test.html");
2236
2237 const float deviceScaleFactor = 2.0f;
2238 int viewportWidth = 640 / deviceScaleFactor;
2239 int viewportHeight = 1280 / deviceScaleFactor;
2240 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2241 FrameTestHelpers::WebViewHelper webViewHelper;
2242 webViewHelper.initializeAndLoad(m_baseURL + "get_wide_div_for_auto_zoom_test.html");
2243 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2244 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2245 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2246 webViewHelper.webView()->setPageScaleFactor(1.0f);
2247 webViewHelper.webView()->layout();
2248
2249 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2250
2251 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2252
2253 WebRect div(0, 100, viewportWidth, 150);
2254 WebPoint point(div.x + 50, div.y + 50);
2255 float scale;
2256 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2257
2258 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2259 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2260 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2261 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2262 }
2263
TEST_F(WebFrameTest,DivAutoZoomVeryTallTest)2264 TEST_F(WebFrameTest, DivAutoZoomVeryTallTest)
2265 {
2266 // When a block is taller than the viewport and a zoom targets a lower part
2267 // of it, then we should keep the target point onscreen instead of snapping
2268 // back up the top of the block.
2269 registerMockedHttpURLLoad("very_tall_div.html");
2270
2271 const float deviceScaleFactor = 2.0f;
2272 int viewportWidth = 640 / deviceScaleFactor;
2273 int viewportHeight = 1280 / deviceScaleFactor;
2274 FrameTestHelpers::WebViewHelper webViewHelper;
2275 webViewHelper.initializeAndLoad(m_baseURL + "very_tall_div.html", true, 0, 0, enableViewportSettings);
2276 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2277 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2278 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2279 webViewHelper.webView()->setPageScaleFactor(1.0f);
2280 webViewHelper.webView()->layout();
2281
2282 WebRect div(200, 300, 400, 5000);
2283 WebPoint point(div.x + 50, div.y + 3000);
2284 float scale;
2285 WebPoint scroll;
2286
2287 WebRect blockBounds = webViewHelper.webViewImpl()->computeBlockBounds(WebRect(point.x, point.y, 0, 0), true);
2288 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(point, blockBounds, 0, 1.0f, scale, scroll);
2289 EXPECT_EQ(scale, 1.0f);
2290 EXPECT_EQ(scroll.y, 2660);
2291 }
2292
TEST_F(WebFrameTest,DivAutoZoomMultipleDivsTest)2293 TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest)
2294 {
2295 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2296
2297 const float deviceScaleFactor = 2.0f;
2298 int viewportWidth = 640 / deviceScaleFactor;
2299 int viewportHeight = 1280 / deviceScaleFactor;
2300 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2301 FrameTestHelpers::WebViewHelper webViewHelper;
2302 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
2303 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2304 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2305 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2306 webViewHelper.webView()->setPageScaleFactor(0.5f);
2307 webViewHelper.webView()->layout();
2308
2309 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2310
2311 WebRect topDiv(200, 100, 200, 150);
2312 WebRect bottomDiv(200, 300, 200, 150);
2313 WebPoint topPoint(topDiv.x + 50, topDiv.y + 50);
2314 WebPoint bottomPoint(bottomDiv.x + 50, bottomDiv.y + 50);
2315 float scale;
2316 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2317
2318 // Test double tap on two different divs
2319 // After first zoom, we should go back to minimum page scale with a second double tap.
2320 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2321 EXPECT_FLOAT_EQ(1, scale);
2322 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2323 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2324
2325 // If the user pinch zooms after double tap, a second double tap should zoom back to the div.
2326 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2327 EXPECT_FLOAT_EQ(1, scale);
2328 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 0.6f, 0);
2329 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2330 EXPECT_FLOAT_EQ(1, scale);
2331 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2332 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2333
2334 // If we didn't yet get an auto-zoom update and a second double-tap arrives, should go back to minimum scale.
2335 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2336 webViewHelper.webViewImpl()->animateDoubleTapZoom(topPoint);
2337 EXPECT_TRUE(webViewHelper.webViewImpl()->fakeDoubleTapAnimationPendingForTesting());
2338 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2339 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2340 }
2341
TEST_F(WebFrameTest,DivAutoZoomScaleBoundsTest)2342 TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest)
2343 {
2344 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2345
2346 int viewportWidth = 320;
2347 int viewportHeight = 480;
2348 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2349 FrameTestHelpers::WebViewHelper webViewHelper;
2350 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
2351 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2352 webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2353 webViewHelper.webView()->layout();
2354
2355 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2356
2357 WebRect div(200, 100, 200, 150);
2358 WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2359 float scale;
2360
2361 // Test double tap scale bounds.
2362 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1
2363 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2364 webViewHelper.webView()->layout();
2365 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2366 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2367 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2368 EXPECT_FLOAT_EQ(1, scale);
2369 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2370 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2371 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2372 EXPECT_FLOAT_EQ(1, scale);
2373
2374 // Zoom in to reset double_tap_zoom_in_effect flag.
2375 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2376 // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2377 webViewHelper.webView()->setPageScaleFactorLimits(1.1f, 4);
2378 webViewHelper.webView()->layout();
2379 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2380 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2381 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2382 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2383 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2384 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2385 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2386 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2387
2388 // Zoom in to reset double_tap_zoom_in_effect flag.
2389 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2390 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
2391 webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4);
2392 webViewHelper.webView()->layout();
2393 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2394 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2395 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2396 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2397 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2398 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2399 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2400 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2401 }
2402
TEST_F(WebFrameTest,DivAutoZoomScaleFontScaleFactorTest)2403 TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest)
2404 {
2405 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2406
2407 int viewportWidth = 320;
2408 int viewportHeight = 480;
2409 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2410 float accessibilityFontScaleFactor = 1.13f;
2411 FrameTestHelpers::WebViewHelper webViewHelper;
2412 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
2413 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2414 webViewHelper.webView()->layout();
2415
2416 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2417 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(true);
2418 webViewHelper.webViewImpl()->page()->settings().setAccessibilityFontScaleFactor(accessibilityFontScaleFactor);
2419
2420 WebRect div(200, 100, 200, 150);
2421 WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2422 float scale;
2423
2424 // Test double tap scale bounds.
2425 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < accessibilityFontScaleFactor
2426 float legibleScale = accessibilityFontScaleFactor;
2427 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2428 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2429 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2430 webViewHelper.webView()->layout();
2431 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2432 EXPECT_FLOAT_EQ(legibleScale, scale);
2433 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2434 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2435 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2436 EXPECT_FLOAT_EQ(legibleScale, scale);
2437
2438 // Zoom in to reset double_tap_zoom_in_effect flag.
2439 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2440 // 1 < accessibilityFontScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2441 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2442 webViewHelper.webView()->layout();
2443 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2444 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2445 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2446 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2447 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2448 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2449 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2450 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2451
2452 // Zoom in to reset double_tap_zoom_in_effect flag.
2453 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2454 // minimumPageScale < 1 < accessibilityFontScaleFactor < doubleTapZoomAlreadyLegibleScale
2455 webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4);
2456 webViewHelper.webView()->layout();
2457 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2458 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2459 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2460 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2461 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2462 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2463 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2464 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2465
2466 // Zoom in to reset double_tap_zoom_in_effect flag.
2467 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0);
2468 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < accessibilityFontScaleFactor
2469 webViewHelper.webView()->setPageScaleFactorLimits(0.9f, 4);
2470 webViewHelper.webView()->layout();
2471 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2472 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2473 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2474 EXPECT_FLOAT_EQ(legibleScale, scale);
2475 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2476 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2477 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2478 EXPECT_FLOAT_EQ(legibleScale, scale);
2479 }
2480
TEST_F(WebFrameTest,DivMultipleTargetZoomMultipleDivsTest)2481 TEST_F(WebFrameTest, DivMultipleTargetZoomMultipleDivsTest)
2482 {
2483 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2484
2485 const float deviceScaleFactor = 2.0f;
2486 int viewportWidth = 640 / deviceScaleFactor;
2487 int viewportHeight = 1280 / deviceScaleFactor;
2488 float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2489 FrameTestHelpers::WebViewHelper webViewHelper;
2490 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
2491 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2492 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2493 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2494 webViewHelper.webView()->setPageScaleFactor(0.5f);
2495 webViewHelper.webView()->layout();
2496
2497 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2498
2499 WebRect viewportRect(0, 0, viewportWidth, viewportHeight);
2500 WebRect topDiv(200, 100, 200, 150);
2501 WebRect bottomDiv(200, 300, 200, 150);
2502 float scale;
2503 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2504
2505 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2506 EXPECT_FLOAT_EQ(1, scale);
2507 simulateMultiTargetZoom(webViewHelper.webViewImpl(), bottomDiv, scale);
2508 EXPECT_FLOAT_EQ(1, scale);
2509 simulateMultiTargetZoom(webViewHelper.webViewImpl(), viewportRect, scale);
2510 EXPECT_FLOAT_EQ(1, scale);
2511 webViewHelper.webViewImpl()->setPageScaleFactor(webViewHelper.webViewImpl()->minimumPageScaleFactor());
2512 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2513 EXPECT_FLOAT_EQ(1, scale);
2514 }
2515
TEST_F(WebFrameTest,DivScrollIntoEditableTest)2516 TEST_F(WebFrameTest, DivScrollIntoEditableTest)
2517 {
2518 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
2519
2520 int viewportWidth = 450;
2521 int viewportHeight = 300;
2522 float leftBoxRatio = 0.3f;
2523 int caretPadding = 10;
2524 float minReadableCaretHeight = 18.0f;
2525 FrameTestHelpers::WebViewHelper webViewHelper;
2526 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
2527 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2528 webViewHelper.webView()->setPageScaleFactorLimits(1, 4);
2529 webViewHelper.webView()->layout();
2530 webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2531 webViewHelper.webView()->settings()->setAutoZoomFocusedNodeToLegibleScale(true);
2532
2533 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2534
2535 WebRect editBoxWithText(200, 200, 250, 20);
2536 WebRect editBoxWithNoText(200, 250, 250, 20);
2537
2538 // Test scrolling the focused node
2539 // The edit box is shorter and narrower than the viewport when legible.
2540 webViewHelper.webView()->advanceFocus(false);
2541 // Set the caret to the end of the input box.
2542 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(1000, 1000);
2543 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2544 WebRect rect, caret;
2545 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2546
2547 float scale;
2548 IntPoint scroll;
2549 bool needAnimation;
2550 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2551 EXPECT_TRUE(needAnimation);
2552 // The edit box should be left aligned with a margin for possible label.
2553 int hScroll = editBoxWithText.x - leftBoxRatio * viewportWidth / scale;
2554 EXPECT_NEAR(hScroll, scroll.x(), 1);
2555 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
2556 EXPECT_NEAR(vScroll, scroll.y(), 1);
2557 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2558
2559 // The edit box is wider than the viewport when legible.
2560 viewportWidth = 200;
2561 viewportHeight = 150;
2562 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2563 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2564 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2565 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2566 EXPECT_TRUE(needAnimation);
2567 // The caret should be right aligned since the caret would be offscreen when the edit box is left aligned.
2568 hScroll = caret.x + caret.width + caretPadding - viewportWidth / scale;
2569 EXPECT_NEAR(hScroll, scroll.x(), 1);
2570 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2571
2572 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2573 // Move focus to edit box with text.
2574 webViewHelper.webView()->advanceFocus(false);
2575 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2576 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2577 EXPECT_TRUE(needAnimation);
2578 // The edit box should be left aligned.
2579 hScroll = editBoxWithNoText.x;
2580 EXPECT_NEAR(hScroll, scroll.x(), 1);
2581 vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2;
2582 EXPECT_NEAR(vScroll, scroll.y(), 1);
2583 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2584
2585 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
2586
2587 // Move focus back to the first edit box.
2588 webViewHelper.webView()->advanceFocus(true);
2589 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2590 // The position should have stayed the same since this box was already on screen with the right scale.
2591 EXPECT_FALSE(needAnimation);
2592 }
2593
TEST_F(WebFrameTest,DivScrollIntoEditablePreservePageScaleTest)2594 TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest)
2595 {
2596 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
2597
2598 const int viewportWidth = 450;
2599 const int viewportHeight = 300;
2600 const float minReadableCaretHeight = 18.0f;
2601 FrameTestHelpers::WebViewHelper webViewHelper;
2602 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
2603 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2604 webViewHelper.webView()->setPageScaleFactorLimits(1, 4);
2605 webViewHelper.webView()->layout();
2606 webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2607 webViewHelper.webView()->settings()->setAutoZoomFocusedNodeToLegibleScale(true);
2608 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2609
2610 const WebRect editBoxWithText(200, 200, 250, 20);
2611
2612 webViewHelper.webView()->advanceFocus(false);
2613 // Set the caret to the begining of the input box.
2614 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(0, 0);
2615 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2616 WebRect rect, caret;
2617 webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2618
2619 // Set page scale twice larger then minimal readable scale
2620 float newScale = minReadableCaretHeight / caret.height * 2.0;
2621 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), newScale);
2622
2623 float scale;
2624 IntPoint scroll;
2625 bool needAnimation;
2626 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2627 EXPECT_TRUE(needAnimation);
2628 // Edit box and caret should be left alinged
2629 int hScroll = editBoxWithText.x;
2630 EXPECT_NEAR(hScroll, scroll.x(), 1);
2631 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
2632 EXPECT_NEAR(vScroll, scroll.y(), 1);
2633 // Page scale have to be unchanged
2634 EXPECT_EQ(newScale, scale);
2635
2636 // Set page scale and scroll such that edit box will be under the screen
2637 newScale = 3.0;
2638 hScroll = 200;
2639 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(hScroll, 0), newScale);
2640 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2641 EXPECT_TRUE(needAnimation);
2642 // Horizontal scroll have to be the same
2643 EXPECT_NEAR(hScroll, scroll.x(), 1);
2644 vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
2645 EXPECT_NEAR(vScroll, scroll.y(), 1);
2646 // Page scale have to be unchanged
2647 EXPECT_EQ(newScale, scale);
2648 }
2649
2650 class TestReloadDoesntRedirectWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2651 public:
decidePolicyForNavigation(const NavigationPolicyInfo & info)2652 virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE
2653 {
2654 EXPECT_FALSE(info.isRedirect);
2655 return WebNavigationPolicyCurrentTab;
2656 }
2657 };
2658
TEST_F(WebFrameTest,ReloadDoesntSetRedirect)2659 TEST_F(WebFrameTest, ReloadDoesntSetRedirect)
2660 {
2661 // Test for case in http://crbug.com/73104. Reloading a frame very quickly
2662 // would sometimes call decidePolicyForNavigation with isRedirect=true
2663 registerMockedHttpURLLoad("form.html");
2664
2665 TestReloadDoesntRedirectWebFrameClient webFrameClient;
2666 FrameTestHelpers::WebViewHelper webViewHelper;
2667 webViewHelper.initializeAndLoad(m_baseURL + "form.html", false, &webFrameClient);
2668
2669 webViewHelper.webView()->mainFrame()->reload(true);
2670 // start another reload before request is delivered.
2671 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
2672 }
2673
2674 class ReloadWithOverrideURLTask : public WebThread::Task {
2675 public:
ReloadWithOverrideURLTask(WebFrame * frame,const KURL & url,bool ignoreCache)2676 ReloadWithOverrideURLTask(WebFrame* frame, const KURL& url, bool ignoreCache)
2677 : m_frame(frame), m_url(url), m_ignoreCache(ignoreCache)
2678 {
2679 }
2680
run()2681 virtual void run() OVERRIDE
2682 {
2683 m_frame->reloadWithOverrideURL(m_url, m_ignoreCache);
2684 }
2685
2686 private:
2687 WebFrame* const m_frame;
2688 const KURL m_url;
2689 const bool m_ignoreCache;
2690 };
2691
TEST_F(WebFrameTest,ReloadWithOverrideURLPreservesState)2692 TEST_F(WebFrameTest, ReloadWithOverrideURLPreservesState)
2693 {
2694 const std::string firstURL = "find.html";
2695 const std::string secondURL = "form.html";
2696 const std::string thirdURL = "history.html";
2697 const float pageScaleFactor = 1.1684f;
2698 const int pageWidth = 640;
2699 const int pageHeight = 480;
2700
2701 registerMockedHttpURLLoad(firstURL);
2702 registerMockedHttpURLLoad(secondURL);
2703 registerMockedHttpURLLoad(thirdURL);
2704
2705 FrameTestHelpers::WebViewHelper webViewHelper;
2706 webViewHelper.initializeAndLoad(m_baseURL + firstURL, true);
2707 webViewHelper.webViewImpl()->resize(WebSize(pageWidth, pageHeight));
2708 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(WebSize(pageWidth / 4, pageHeight / 4));
2709 webViewHelper.webViewImpl()->setPageScaleFactor(pageScaleFactor);
2710
2711 WebSize previousOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
2712 float previousScale = webViewHelper.webViewImpl()->pageScaleFactor();
2713
2714 // Reload the page using the cache.
2715 Platform::current()->currentThread()->postTask(
2716 new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + secondURL), false));
2717 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
2718 ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2719 ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor());
2720
2721 // Reload the page while ignoring the cache.
2722 Platform::current()->currentThread()->postTask(
2723 new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + thirdURL), true));
2724 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
2725 ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2726 ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor());
2727 }
2728
TEST_F(WebFrameTest,ReloadWhileProvisional)2729 TEST_F(WebFrameTest, ReloadWhileProvisional)
2730 {
2731 // Test that reloading while the previous load is still pending does not cause the initial
2732 // request to get lost.
2733 registerMockedHttpURLLoad("fixed_layout.html");
2734
2735 FrameTestHelpers::WebViewHelper webViewHelper;
2736 webViewHelper.initialize();
2737 WebURLRequest request;
2738 request.initialize();
2739 request.setURL(toKURL(m_baseURL + "fixed_layout.html"));
2740 webViewHelper.webView()->mainFrame()->loadRequest(request);
2741 // start reload before first request is delivered.
2742 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
2743
2744 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
2745 ASSERT_TRUE(dataSource);
2746 EXPECT_EQ(toKURL(m_baseURL + "fixed_layout.html"), toKURL(dataSource->request().url().spec()));
2747 }
2748
TEST_F(WebFrameTest,AppendRedirects)2749 TEST_F(WebFrameTest, AppendRedirects)
2750 {
2751 const std::string firstURL = "about:blank";
2752 const std::string secondURL = "http://www.test.com";
2753
2754 FrameTestHelpers::WebViewHelper webViewHelper;
2755 webViewHelper.initializeAndLoad(firstURL, true);
2756
2757 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
2758 ASSERT_TRUE(dataSource);
2759 dataSource->appendRedirect(toKURL(secondURL));
2760
2761 WebVector<WebURL> redirects;
2762 dataSource->redirectChain(redirects);
2763 ASSERT_EQ(2U, redirects.size());
2764 EXPECT_EQ(toKURL(firstURL), toKURL(redirects[0].spec().data()));
2765 EXPECT_EQ(toKURL(secondURL), toKURL(redirects[1].spec().data()));
2766 }
2767
TEST_F(WebFrameTest,IframeRedirect)2768 TEST_F(WebFrameTest, IframeRedirect)
2769 {
2770 registerMockedHttpURLLoad("iframe_redirect.html");
2771 registerMockedHttpURLLoad("visible_iframe.html");
2772
2773 FrameTestHelpers::WebViewHelper webViewHelper;
2774 webViewHelper.initializeAndLoad(m_baseURL + "iframe_redirect.html", true);
2775 // Pump pending requests one more time. The test page loads script that navigates.
2776 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
2777
2778 WebFrame* iframe = webViewHelper.webView()->findFrameByName(WebString::fromUTF8("ifr"));
2779 ASSERT_TRUE(iframe);
2780 WebDataSource* iframeDataSource = iframe->dataSource();
2781 ASSERT_TRUE(iframeDataSource);
2782 WebVector<WebURL> redirects;
2783 iframeDataSource->redirectChain(redirects);
2784 ASSERT_EQ(2U, redirects.size());
2785 EXPECT_EQ(toKURL("about:blank"), toKURL(redirects[0].spec().data()));
2786 EXPECT_EQ(toKURL("http://www.test.com/visible_iframe.html"), toKURL(redirects[1].spec().data()));
2787 }
2788
TEST_F(WebFrameTest,ClearFocusedNodeTest)2789 TEST_F(WebFrameTest, ClearFocusedNodeTest)
2790 {
2791 registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
2792 registerMockedHttpURLLoad("autofocus_input_field_iframe.html");
2793
2794 FrameTestHelpers::WebViewHelper webViewHelper;
2795 webViewHelper.initializeAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true);
2796
2797 // Clear the focused node.
2798 webViewHelper.webView()->clearFocusedElement();
2799
2800 // Now retrieve the FocusedNode and test it should be null.
2801 EXPECT_EQ(0, webViewHelper.webViewImpl()->focusedElement());
2802 }
2803
2804 // Implementation of WebFrameClient that tracks the v8 contexts that are created
2805 // and destroyed for verification.
2806 class ContextLifetimeTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2807 public:
2808 struct Notification {
2809 public:
Notification__anonb8cba1d90111::ContextLifetimeTestWebFrameClient::Notification2810 Notification(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId)
2811 : frame(frame)
2812 , context(context->GetIsolate(), context)
2813 , worldId(worldId)
2814 {
2815 }
2816
~Notification__anonb8cba1d90111::ContextLifetimeTestWebFrameClient::Notification2817 ~Notification()
2818 {
2819 context.Reset();
2820 }
2821
Equals__anonb8cba1d90111::ContextLifetimeTestWebFrameClient::Notification2822 bool Equals(Notification* other)
2823 {
2824 return other && frame == other->frame && context == other->context && worldId == other->worldId;
2825 }
2826
2827 WebLocalFrame* frame;
2828 v8::Persistent<v8::Context> context;
2829 int worldId;
2830 };
2831
~ContextLifetimeTestWebFrameClient()2832 virtual ~ContextLifetimeTestWebFrameClient()
2833 {
2834 reset();
2835 }
2836
reset()2837 void reset()
2838 {
2839 for (size_t i = 0; i < createNotifications.size(); ++i)
2840 delete createNotifications[i];
2841
2842 for (size_t i = 0; i < releaseNotifications.size(); ++i)
2843 delete releaseNotifications[i];
2844
2845 createNotifications.clear();
2846 releaseNotifications.clear();
2847 }
2848
2849 std::vector<Notification*> createNotifications;
2850 std::vector<Notification*> releaseNotifications;
2851
2852 private:
didCreateScriptContext(WebLocalFrame * frame,v8::Handle<v8::Context> context,int extensionGroup,int worldId)2853 virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
2854 {
2855 createNotifications.push_back(new Notification(frame, context, worldId));
2856 }
2857
willReleaseScriptContext(WebLocalFrame * frame,v8::Handle<v8::Context> context,int worldId)2858 virtual void willReleaseScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId) OVERRIDE
2859 {
2860 releaseNotifications.push_back(new Notification(frame, context, worldId));
2861 }
2862 };
2863
2864 // TODO(aa): Deflake this test.
TEST_F(WebFrameTest,FLAKY_ContextNotificationsLoadUnload)2865 TEST_F(WebFrameTest, FLAKY_ContextNotificationsLoadUnload)
2866 {
2867 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
2868
2869 registerMockedHttpURLLoad("context_notifications_test.html");
2870 registerMockedHttpURLLoad("context_notifications_test_frame.html");
2871
2872 // Load a frame with an iframe, make sure we get the right create notifications.
2873 ContextLifetimeTestWebFrameClient webFrameClient;
2874 FrameTestHelpers::WebViewHelper webViewHelper;
2875 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
2876
2877 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
2878 WebFrame* childFrame = mainFrame->firstChild();
2879
2880 ASSERT_EQ(2u, webFrameClient.createNotifications.size());
2881 EXPECT_EQ(0u, webFrameClient.releaseNotifications.size());
2882
2883 ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0];
2884 ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1];
2885
2886 EXPECT_EQ(mainFrame, firstCreateNotification->frame);
2887 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context);
2888 EXPECT_EQ(0, firstCreateNotification->worldId);
2889
2890 EXPECT_EQ(childFrame, secondCreateNotification->frame);
2891 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context);
2892 EXPECT_EQ(0, secondCreateNotification->worldId);
2893
2894 // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order.
2895 webViewHelper.reset();
2896
2897 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
2898 ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0];
2899 ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1];
2900
2901 ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification));
2902 ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification));
2903 }
2904
TEST_F(WebFrameTest,ContextNotificationsReload)2905 TEST_F(WebFrameTest, ContextNotificationsReload)
2906 {
2907 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
2908
2909 registerMockedHttpURLLoad("context_notifications_test.html");
2910 registerMockedHttpURLLoad("context_notifications_test_frame.html");
2911
2912 ContextLifetimeTestWebFrameClient webFrameClient;
2913 FrameTestHelpers::WebViewHelper webViewHelper;
2914 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
2915
2916 // Refresh, we should get two release notifications and two more create notifications.
2917 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
2918 ASSERT_EQ(4u, webFrameClient.createNotifications.size());
2919 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
2920
2921 // The two release notifications we got should be exactly the same as the first two create notifications.
2922 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
2923 EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals(
2924 webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i]));
2925 }
2926
2927 // The last two create notifications should be for the current frames and context.
2928 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
2929 WebFrame* childFrame = mainFrame->firstChild();
2930 ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2];
2931 ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3];
2932
2933 EXPECT_EQ(mainFrame, firstRefreshNotification->frame);
2934 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context);
2935 EXPECT_EQ(0, firstRefreshNotification->worldId);
2936
2937 EXPECT_EQ(childFrame, secondRefreshNotification->frame);
2938 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context);
2939 EXPECT_EQ(0, secondRefreshNotification->worldId);
2940 }
2941
TEST_F(WebFrameTest,ContextNotificationsIsolatedWorlds)2942 TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds)
2943 {
2944 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2945 v8::HandleScope handleScope(isolate);
2946
2947 registerMockedHttpURLLoad("context_notifications_test.html");
2948 registerMockedHttpURLLoad("context_notifications_test_frame.html");
2949
2950 ContextLifetimeTestWebFrameClient webFrameClient;
2951 FrameTestHelpers::WebViewHelper webViewHelper;
2952 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
2953
2954 // Add an isolated world.
2955 webFrameClient.reset();
2956
2957 int isolatedWorldId = 42;
2958 WebScriptSource scriptSource("hi!");
2959 int numSources = 1;
2960 int extensionGroup = 0;
2961 webViewHelper.webView()->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup);
2962
2963 // We should now have a new create notification.
2964 ASSERT_EQ(1u, webFrameClient.createNotifications.size());
2965 ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0];
2966 ASSERT_EQ(isolatedWorldId, notification->worldId);
2967 ASSERT_EQ(webViewHelper.webView()->mainFrame(), notification->frame);
2968
2969 // 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.
2970 ASSERT_NE(webViewHelper.webView()->mainFrame()->mainWorldScriptContext(), v8::Local<v8::Context>::New(isolate, notification->context));
2971
2972 webViewHelper.reset();
2973
2974 // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context).
2975 ASSERT_EQ(3u, webFrameClient.releaseNotifications.size());
2976
2977 // And one of them should be exactly the same as the create notification for the isolated context.
2978 int matchCount = 0;
2979 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
2980 if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0]))
2981 ++matchCount;
2982 }
2983 EXPECT_EQ(1, matchCount);
2984 }
2985
TEST_F(WebFrameTest,FindInPage)2986 TEST_F(WebFrameTest, FindInPage)
2987 {
2988 registerMockedHttpURLLoad("find.html");
2989 FrameTestHelpers::WebViewHelper webViewHelper;
2990 webViewHelper.initializeAndLoad(m_baseURL + "find.html");
2991 WebFrame* frame = webViewHelper.webView()->mainFrame();
2992 const int findIdentifier = 12345;
2993 WebFindOptions options;
2994
2995 // Find in a <div> element.
2996 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0));
2997 frame->stopFinding(false);
2998 WebRange range = frame->selectionRange();
2999 EXPECT_EQ(5, range.startOffset());
3000 EXPECT_EQ(9, range.endOffset());
3001 EXPECT_TRUE(frame->document().focusedElement().isNull());
3002
3003 // Find in an <input> value.
3004 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0));
3005 // Confirm stopFinding(false) sets the selection on the found text.
3006 frame->stopFinding(false);
3007 range = frame->selectionRange();
3008 ASSERT_FALSE(range.isNull());
3009 EXPECT_EQ(5, range.startOffset());
3010 EXPECT_EQ(9, range.endOffset());
3011 EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedElement().tagName());
3012
3013 // Find in a <textarea> content.
3014 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0));
3015 // Confirm stopFinding(false) sets the selection on the found text.
3016 frame->stopFinding(false);
3017 range = frame->selectionRange();
3018 ASSERT_FALSE(range.isNull());
3019 EXPECT_EQ(5, range.startOffset());
3020 EXPECT_EQ(9, range.endOffset());
3021 EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedElement().tagName());
3022
3023 // Find in a contentEditable element.
3024 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0));
3025 // Confirm stopFinding(false) sets the selection on the found text.
3026 frame->stopFinding(false);
3027 range = frame->selectionRange();
3028 ASSERT_FALSE(range.isNull());
3029 EXPECT_EQ(0, range.startOffset());
3030 EXPECT_EQ(4, range.endOffset());
3031 // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>.
3032 EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedElement().tagName());
3033
3034 // Find in <select> content.
3035 EXPECT_FALSE(frame->find(findIdentifier, WebString::fromUTF8("bar5"), options, false, 0));
3036 // If there are any matches, stopFinding will set the selection on the found text.
3037 // However, we do not expect any matches, so check that the selection is null.
3038 frame->stopFinding(false);
3039 range = frame->selectionRange();
3040 ASSERT_TRUE(range.isNull());
3041 }
3042
TEST_F(WebFrameTest,GetContentAsPlainText)3043 TEST_F(WebFrameTest, GetContentAsPlainText)
3044 {
3045 FrameTestHelpers::WebViewHelper webViewHelper;
3046 webViewHelper.initializeAndLoad("about:blank", true);
3047 // We set the size because it impacts line wrapping, which changes the
3048 // resulting text value.
3049 webViewHelper.webView()->resize(WebSize(640, 480));
3050 WebFrame* frame = webViewHelper.webView()->mainFrame();
3051
3052 // Generate a simple test case.
3053 const char simpleSource[] = "<div>Foo bar</div><div></div>baz";
3054 KURL testURL = toKURL("about:blank");
3055 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3056
3057 // Make sure it comes out OK.
3058 const std::string expected("Foo bar\nbaz");
3059 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3060 EXPECT_EQ(expected, text.utf8());
3061
3062 // Try reading the same one with clipping of the text.
3063 const int length = 5;
3064 text = frame->contentAsText(length);
3065 EXPECT_EQ(expected.substr(0, length), text.utf8());
3066
3067 // Now do a new test with a subframe.
3068 const char outerFrameSource[] = "Hello<iframe></iframe> world";
3069 FrameTestHelpers::loadHTMLString(frame, outerFrameSource, testURL);
3070
3071 // Load something into the subframe.
3072 WebFrame* subframe = frame->firstChild();
3073 ASSERT_TRUE(subframe);
3074 FrameTestHelpers::loadHTMLString(subframe, "sub<p>text", testURL);
3075
3076 text = frame->contentAsText(std::numeric_limits<size_t>::max());
3077 EXPECT_EQ("Hello world\n\nsub\ntext", text.utf8());
3078
3079 // Get the frame text where the subframe separator falls on the boundary of
3080 // what we'll take. There used to be a crash in this case.
3081 text = frame->contentAsText(12);
3082 EXPECT_EQ("Hello world", text.utf8());
3083 }
3084
TEST_F(WebFrameTest,GetFullHtmlOfPage)3085 TEST_F(WebFrameTest, GetFullHtmlOfPage)
3086 {
3087 FrameTestHelpers::WebViewHelper webViewHelper;
3088 webViewHelper.initializeAndLoad("about:blank", true);
3089 WebFrame* frame = webViewHelper.webView()->mainFrame();
3090
3091 // Generate a simple test case.
3092 const char simpleSource[] = "<p>Hello</p><p>World</p>";
3093 KURL testURL = toKURL("about:blank");
3094 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3095
3096 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3097 EXPECT_EQ("Hello\n\nWorld", text.utf8());
3098
3099 const std::string html = frame->contentAsMarkup().utf8();
3100
3101 // Load again with the output html.
3102 FrameTestHelpers::loadHTMLString(frame, html, testURL);
3103
3104 EXPECT_EQ(html, frame->contentAsMarkup().utf8());
3105
3106 text = frame->contentAsText(std::numeric_limits<size_t>::max());
3107 EXPECT_EQ("Hello\n\nWorld", text.utf8());
3108
3109 // Test selection check
3110 EXPECT_FALSE(frame->hasSelection());
3111 frame->executeCommand(WebString::fromUTF8("SelectAll"));
3112 EXPECT_TRUE(frame->hasSelection());
3113 frame->executeCommand(WebString::fromUTF8("Unselect"));
3114 EXPECT_FALSE(frame->hasSelection());
3115 WebString selectionHtml = frame->selectionAsMarkup();
3116 EXPECT_TRUE(selectionHtml.isEmpty());
3117 }
3118
3119 class TestExecuteScriptDuringDidCreateScriptContext : public FrameTestHelpers::TestWebFrameClient {
3120 public:
didCreateScriptContext(WebLocalFrame * frame,v8::Handle<v8::Context> context,int extensionGroup,int worldId)3121 virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
3122 {
3123 frame->executeScript(WebScriptSource("window.history = 'replaced';"));
3124 }
3125 };
3126
TEST_F(WebFrameTest,ExecuteScriptDuringDidCreateScriptContext)3127 TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext)
3128 {
3129 registerMockedHttpURLLoad("hello_world.html");
3130
3131 TestExecuteScriptDuringDidCreateScriptContext webFrameClient;
3132 FrameTestHelpers::WebViewHelper webViewHelper;
3133 webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient);
3134
3135 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
3136 }
3137
3138 class FindUpdateWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3139 public:
FindUpdateWebFrameClient()3140 FindUpdateWebFrameClient()
3141 : m_findResultsAreReady(false)
3142 , m_count(-1)
3143 {
3144 }
3145
reportFindInPageMatchCount(int,int count,bool finalUpdate)3146 virtual void reportFindInPageMatchCount(int, int count, bool finalUpdate) OVERRIDE
3147 {
3148 m_count = count;
3149 if (finalUpdate)
3150 m_findResultsAreReady = true;
3151 }
3152
findResultsAreReady() const3153 bool findResultsAreReady() const { return m_findResultsAreReady; }
count() const3154 int count() const { return m_count; }
3155
3156 private:
3157 bool m_findResultsAreReady;
3158 int m_count;
3159 };
3160
3161 // This fails on Mac https://bugs.webkit.org/show_bug.cgi?id=108574
3162 // Also failing on Android: http://crbug.com/341314
3163 #if OS(MACOSX) || OS(ANDROID)
TEST_F(WebFrameTest,DISABLED_FindInPageMatchRects)3164 TEST_F(WebFrameTest, DISABLED_FindInPageMatchRects)
3165 #else
3166 TEST_F(WebFrameTest, FindInPageMatchRects)
3167 #endif
3168 {
3169 registerMockedHttpURLLoad("find_in_page.html");
3170 registerMockedHttpURLLoad("find_in_page_frame.html");
3171
3172 FindUpdateWebFrameClient client;
3173 FrameTestHelpers::WebViewHelper webViewHelper;
3174 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3175 webViewHelper.webView()->resize(WebSize(640, 480));
3176 webViewHelper.webView()->layout();
3177 runPendingTasks();
3178
3179 // Note that the 'result 19' in the <select> element is not expected to produce a match.
3180 static const char* kFindString = "result";
3181 static const int kFindIdentifier = 12345;
3182 static const int kNumResults = 19;
3183
3184 WebFindOptions options;
3185 WebString searchText = WebString::fromUTF8(kFindString);
3186 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3187 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3188
3189 mainFrame->resetMatchCount();
3190
3191 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3192 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3193
3194 runPendingTasks();
3195 EXPECT_TRUE(client.findResultsAreReady());
3196
3197 WebVector<WebFloatRect> webMatchRects;
3198 mainFrame->findMatchRects(webMatchRects);
3199 ASSERT_EQ(webMatchRects.size(), static_cast<size_t>(kNumResults));
3200 int rectsVersion = mainFrame->findMatchMarkersVersion();
3201
3202 for (int resultIndex = 0; resultIndex < kNumResults; ++resultIndex) {
3203 FloatRect resultRect = static_cast<FloatRect>(webMatchRects[resultIndex]);
3204
3205 // Select the match by the center of its rect.
3206 EXPECT_EQ(mainFrame->selectNearestFindMatch(resultRect.center(), 0), resultIndex + 1);
3207
3208 // Check that the find result ordering matches with our expectations.
3209 Range* result = mainFrame->activeMatchFrame()->activeMatch();
3210 ASSERT_TRUE(result);
3211 result->setEnd(result->endContainer(), result->endOffset() + 3);
3212 EXPECT_EQ(result->text(), String::format("%s %02d", kFindString, resultIndex));
3213
3214 // Verify that the expected match rect also matches the currently active match.
3215 // Compare the enclosing rects to prevent precision issues caused by CSS transforms.
3216 FloatRect activeMatch = mainFrame->activeFindMatchRect();
3217 EXPECT_EQ(enclosingIntRect(activeMatch), enclosingIntRect(resultRect));
3218
3219 // The rects version should not have changed.
3220 EXPECT_EQ(mainFrame->findMatchMarkersVersion(), rectsVersion);
3221 }
3222
3223 // All results after the first two ones should be below between them in find-in-page coordinates.
3224 // This is because results 2 to 9 are inside an iframe located between results 0 and 1. This applies to the fixed div too.
3225 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[1].y);
3226 for (int resultIndex = 2; resultIndex < kNumResults; ++resultIndex) {
3227 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[resultIndex].y);
3228 EXPECT_TRUE(webMatchRects[1].y > webMatchRects[resultIndex].y);
3229 }
3230
3231 // Result 3 should be below both 2 and 4. This is caused by the CSS transform in the containing div.
3232 // If the transform doesn't work then 3 will be between 2 and 4.
3233 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[2].y);
3234 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[4].y);
3235
3236 // Results 6, 7, 8 and 9 should be one below the other in that same order.
3237 // If overflow:scroll is not properly handled then result 8 would be below result 9 or
3238 // result 7 above result 6 depending on the scroll.
3239 EXPECT_TRUE(webMatchRects[6].y < webMatchRects[7].y);
3240 EXPECT_TRUE(webMatchRects[7].y < webMatchRects[8].y);
3241 EXPECT_TRUE(webMatchRects[8].y < webMatchRects[9].y);
3242
3243 // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are inside the table.
3244 EXPECT_TRUE(webMatchRects[11].y > webMatchRects[10].y);
3245 EXPECT_TRUE(webMatchRects[12].y > webMatchRects[10].y);
3246 EXPECT_TRUE(webMatchRects[13].y > webMatchRects[10].y);
3247 EXPECT_TRUE(webMatchRects[14].y > webMatchRects[10].y);
3248 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[15].y);
3249 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[15].y);
3250 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[15].y);
3251 EXPECT_TRUE(webMatchRects[14].y < webMatchRects[15].y);
3252
3253 // Result 11 should be above 12, 13 and 14 as it's in the table header.
3254 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[12].y);
3255 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[13].y);
3256 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[14].y);
3257
3258 // Result 11 should also be right to 12, 13 and 14 because of the colspan.
3259 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[12].x);
3260 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[13].x);
3261 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[14].x);
3262
3263 // Result 12 should be left to results 11, 13 and 14 in the table layout.
3264 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[11].x);
3265 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[13].x);
3266 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[14].x);
3267
3268 // Results 13, 12 and 14 should be one above the other in that order because of the rowspan
3269 // and vertical-align: middle by default.
3270 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[12].y);
3271 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[14].y);
3272
3273 // Result 16 should be below result 15.
3274 EXPECT_TRUE(webMatchRects[15].y > webMatchRects[14].y);
3275
3276 // Result 18 should be normalized with respect to the position:relative div, and not it's
3277 // immediate containing div. Consequently, result 18 should be above result 17.
3278 EXPECT_TRUE(webMatchRects[17].y > webMatchRects[18].y);
3279
3280 // Resizing should update the rects version.
3281 webViewHelper.webView()->resize(WebSize(800, 600));
3282 runPendingTasks();
3283 EXPECT_TRUE(mainFrame->findMatchMarkersVersion() != rectsVersion);
3284 }
3285
TEST_F(WebFrameTest,FindInPageSkipsHiddenFrames)3286 TEST_F(WebFrameTest, FindInPageSkipsHiddenFrames)
3287 {
3288 registerMockedHttpURLLoad("find_in_hidden_frame.html");
3289
3290 FindUpdateWebFrameClient client;
3291 FrameTestHelpers::WebViewHelper webViewHelper;
3292 webViewHelper.initializeAndLoad(m_baseURL + "find_in_hidden_frame.html", true, &client);
3293 webViewHelper.webView()->resize(WebSize(640, 480));
3294 webViewHelper.webView()->layout();
3295 runPendingTasks();
3296
3297 static const char* kFindString = "hello";
3298 static const int kFindIdentifier = 12345;
3299 static const int kNumResults = 1;
3300
3301 WebFindOptions options;
3302 WebString searchText = WebString::fromUTF8(kFindString);
3303 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3304 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3305
3306 mainFrame->resetMatchCount();
3307
3308 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3309 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3310
3311 runPendingTasks();
3312 EXPECT_TRUE(client.findResultsAreReady());
3313 EXPECT_EQ(kNumResults, client.count());
3314 }
3315
TEST_F(WebFrameTest,FindOnDetachedFrame)3316 TEST_F(WebFrameTest, FindOnDetachedFrame)
3317 {
3318 registerMockedHttpURLLoad("find_in_page.html");
3319 registerMockedHttpURLLoad("find_in_page_frame.html");
3320
3321 FindUpdateWebFrameClient client;
3322 FrameTestHelpers::WebViewHelper webViewHelper;
3323 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3324 webViewHelper.webView()->resize(WebSize(640, 480));
3325 webViewHelper.webView()->layout();
3326 runPendingTasks();
3327
3328 static const char* kFindString = "result";
3329 static const int kFindIdentifier = 12345;
3330
3331 WebFindOptions options;
3332 WebString searchText = WebString::fromUTF8(kFindString);
3333 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3334 RefPtrWillBeRawPtr<WebLocalFrameImpl> secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3335 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
3336
3337 // Detach the frame before finding.
3338 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3339
3340 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3341 EXPECT_FALSE(secondFrame->find(kFindIdentifier, searchText, options, false, 0));
3342
3343 runPendingTasks();
3344 EXPECT_FALSE(client.findResultsAreReady());
3345
3346 mainFrame->resetMatchCount();
3347
3348 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3349 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3350
3351 runPendingTasks();
3352 EXPECT_TRUE(client.findResultsAreReady());
3353 }
3354
TEST_F(WebFrameTest,FindDetachFrameBeforeScopeStrings)3355 TEST_F(WebFrameTest, FindDetachFrameBeforeScopeStrings)
3356 {
3357 registerMockedHttpURLLoad("find_in_page.html");
3358 registerMockedHttpURLLoad("find_in_page_frame.html");
3359
3360 FindUpdateWebFrameClient client;
3361 FrameTestHelpers::WebViewHelper webViewHelper;
3362 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3363 webViewHelper.webView()->resize(WebSize(640, 480));
3364 webViewHelper.webView()->layout();
3365 runPendingTasks();
3366
3367 static const char* kFindString = "result";
3368 static const int kFindIdentifier = 12345;
3369
3370 WebFindOptions options;
3371 WebString searchText = WebString::fromUTF8(kFindString);
3372 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3373 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3374 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
3375
3376 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3377 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
3378
3379 runPendingTasks();
3380 EXPECT_FALSE(client.findResultsAreReady());
3381
3382 // Detach the frame between finding and scoping.
3383 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3384
3385 mainFrame->resetMatchCount();
3386
3387 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3388 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3389
3390 runPendingTasks();
3391 EXPECT_TRUE(client.findResultsAreReady());
3392 }
3393
TEST_F(WebFrameTest,FindDetachFrameWhileScopingStrings)3394 TEST_F(WebFrameTest, FindDetachFrameWhileScopingStrings)
3395 {
3396 registerMockedHttpURLLoad("find_in_page.html");
3397 registerMockedHttpURLLoad("find_in_page_frame.html");
3398
3399 FindUpdateWebFrameClient client;
3400 FrameTestHelpers::WebViewHelper webViewHelper;
3401 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3402 webViewHelper.webView()->resize(WebSize(640, 480));
3403 webViewHelper.webView()->layout();
3404 runPendingTasks();
3405
3406 static const char* kFindString = "result";
3407 static const int kFindIdentifier = 12345;
3408
3409 WebFindOptions options;
3410 WebString searchText = WebString::fromUTF8(kFindString);
3411 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3412 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3413 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame());
3414
3415 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3416 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
3417
3418 runPendingTasks();
3419 EXPECT_FALSE(client.findResultsAreReady());
3420
3421 mainFrame->resetMatchCount();
3422
3423 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3424 frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3425
3426 // The first scopeStringMatches will have reset the state. Detach before it actually scopes.
3427 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3428
3429 runPendingTasks();
3430 EXPECT_TRUE(client.findResultsAreReady());
3431 }
3432
TEST_F(WebFrameTest,ResetMatchCount)3433 TEST_F(WebFrameTest, ResetMatchCount)
3434 {
3435 registerMockedHttpURLLoad("find_in_generated_frame.html");
3436
3437 FindUpdateWebFrameClient client;
3438 FrameTestHelpers::WebViewHelper webViewHelper;
3439 webViewHelper.initializeAndLoad(m_baseURL + "find_in_generated_frame.html", true, &client);
3440 webViewHelper.webView()->resize(WebSize(640, 480));
3441 webViewHelper.webView()->layout();
3442 runPendingTasks();
3443
3444 static const char* kFindString = "result";
3445 static const int kFindIdentifier = 12345;
3446
3447 WebFindOptions options;
3448 WebString searchText = WebString::fromUTF8(kFindString);
3449 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3450
3451 // Check that child frame exists.
3452 EXPECT_TRUE(!!mainFrame->traverseNext(false));
3453
3454 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) {
3455 EXPECT_FALSE(frame->find(kFindIdentifier, searchText, options, false, 0));
3456 }
3457
3458 runPendingTasks();
3459 EXPECT_FALSE(client.findResultsAreReady());
3460
3461 mainFrame->resetMatchCount();
3462 }
3463
TEST_F(WebFrameTest,SetTickmarks)3464 TEST_F(WebFrameTest, SetTickmarks)
3465 {
3466 registerMockedHttpURLLoad("find.html");
3467
3468 FindUpdateWebFrameClient client;
3469 FrameTestHelpers::WebViewHelper webViewHelper;
3470 webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client);
3471 webViewHelper.webView()->resize(WebSize(640, 480));
3472 webViewHelper.webView()->layout();
3473 runPendingTasks();
3474
3475 static const char* kFindString = "foo";
3476 static const int kFindIdentifier = 12345;
3477
3478 WebFindOptions options;
3479 WebString searchText = WebString::fromUTF8(kFindString);
3480 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3481 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3482
3483 mainFrame->resetMatchCount();
3484 mainFrame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3485
3486 runPendingTasks();
3487 EXPECT_TRUE(client.findResultsAreReady());
3488
3489 // Get the tickmarks for the original find request.
3490 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
3491 RefPtr<Scrollbar> scrollbar = frameView->createScrollbar(HorizontalScrollbar);
3492 Vector<IntRect> originalTickmarks;
3493 scrollbar->getTickmarks(originalTickmarks);
3494 EXPECT_EQ(4u, originalTickmarks.size());
3495
3496 // Override the tickmarks.
3497 Vector<IntRect> overridingTickmarksExpected;
3498 overridingTickmarksExpected.append(IntRect(0, 0, 100, 100));
3499 overridingTickmarksExpected.append(IntRect(0, 20, 100, 100));
3500 overridingTickmarksExpected.append(IntRect(0, 30, 100, 100));
3501 mainFrame->setTickmarks(overridingTickmarksExpected);
3502
3503 // Check the tickmarks are overriden correctly.
3504 Vector<IntRect> overridingTickmarksActual;
3505 scrollbar->getTickmarks(overridingTickmarksActual);
3506 EXPECT_EQ(overridingTickmarksExpected, overridingTickmarksActual);
3507
3508 // Reset the tickmark behavior.
3509 Vector<IntRect> resetTickmarks;
3510 mainFrame->setTickmarks(resetTickmarks);
3511
3512 // Check that the original tickmarks are returned
3513 Vector<IntRect> originalTickmarksAfterReset;
3514 scrollbar->getTickmarks(originalTickmarksAfterReset);
3515 EXPECT_EQ(originalTickmarks, originalTickmarksAfterReset);
3516 }
3517
topLeft(const WebRect & rect)3518 static WebPoint topLeft(const WebRect& rect)
3519 {
3520 return WebPoint(rect.x, rect.y);
3521 }
3522
bottomRightMinusOne(const WebRect & rect)3523 static WebPoint bottomRightMinusOne(const WebRect& rect)
3524 {
3525 // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
3526 // selection bounds, selectRange() will select the *next* element. That's
3527 // strictly correct, as hit-testing checks the pixel to the lower-right of
3528 // the input coordinate, but it's a wart on the API.
3529 return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1);
3530 }
3531
elementBounds(WebFrame * frame,const WebString & id)3532 static WebRect elementBounds(WebFrame* frame, const WebString& id)
3533 {
3534 return frame->document().getElementById(id).boundsInViewportSpace();
3535 }
3536
selectionAsString(WebFrame * frame)3537 static std::string selectionAsString(WebFrame* frame)
3538 {
3539 return frame->selectionAsText().utf8();
3540 }
3541
TEST_F(WebFrameTest,SelectRange)3542 TEST_F(WebFrameTest, SelectRange)
3543 {
3544 WebFrame* frame;
3545 WebRect startWebRect;
3546 WebRect endWebRect;
3547
3548 registerMockedHttpURLLoad("select_range_basic.html");
3549 registerMockedHttpURLLoad("select_range_scroll.html");
3550
3551 FrameTestHelpers::WebViewHelper webViewHelper;
3552 initializeTextSelectionWebView(m_baseURL + "select_range_basic.html", &webViewHelper);
3553 frame = webViewHelper.webView()->mainFrame();
3554 EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3555 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3556 frame->executeCommand(WebString::fromUTF8("Unselect"));
3557 EXPECT_EQ("", selectionAsString(frame));
3558 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3559 EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3560
3561 initializeTextSelectionWebView(m_baseURL + "select_range_scroll.html", &webViewHelper);
3562 frame = webViewHelper.webView()->mainFrame();
3563 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3564 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3565 frame->executeCommand(WebString::fromUTF8("Unselect"));
3566 EXPECT_EQ("", selectionAsString(frame));
3567 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3568 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3569 }
3570
TEST_F(WebFrameTest,SelectRangeInIframe)3571 TEST_F(WebFrameTest, SelectRangeInIframe)
3572 {
3573 WebFrame* frame;
3574 WebRect startWebRect;
3575 WebRect endWebRect;
3576
3577 registerMockedHttpURLLoad("select_range_iframe.html");
3578 registerMockedHttpURLLoad("select_range_basic.html");
3579
3580 FrameTestHelpers::WebViewHelper webViewHelper;
3581 initializeTextSelectionWebView(m_baseURL + "select_range_iframe.html", &webViewHelper);
3582 frame = webViewHelper.webView()->mainFrame();
3583 WebFrame* subframe = frame->firstChild();
3584 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3585 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3586 subframe->executeCommand(WebString::fromUTF8("Unselect"));
3587 EXPECT_EQ("", selectionAsString(subframe));
3588 subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3589 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3590 }
3591
TEST_F(WebFrameTest,SelectRangeDivContentEditable)3592 TEST_F(WebFrameTest, SelectRangeDivContentEditable)
3593 {
3594 WebFrame* frame;
3595 WebRect startWebRect;
3596 WebRect endWebRect;
3597
3598 registerMockedHttpURLLoad("select_range_div_editable.html");
3599
3600 // Select the middle of an editable element, then try to extend the selection to the top of the document.
3601 // The selection range should be clipped to the bounds of the editable element.
3602 FrameTestHelpers::WebViewHelper webViewHelper;
3603 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3604 frame = webViewHelper.webView()->mainFrame();
3605 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3606 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3607
3608 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3609 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3610
3611 // As above, but extending the selection to the bottom of the document.
3612 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3613 frame = webViewHelper.webView()->mainFrame();
3614
3615 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3616 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3617 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3618 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3619
3620 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3621 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3622 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3623 }
3624
3625 // positionForPoint returns the wrong values for contenteditable spans. See
3626 // http://crbug.com/238334.
TEST_F(WebFrameTest,DISABLED_SelectRangeSpanContentEditable)3627 TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable)
3628 {
3629 WebFrame* frame;
3630 WebRect startWebRect;
3631 WebRect endWebRect;
3632
3633 registerMockedHttpURLLoad("select_range_span_editable.html");
3634
3635 // Select the middle of an editable element, then try to extend the selection to the top of the document.
3636 // The selection range should be clipped to the bounds of the editable element.
3637 FrameTestHelpers::WebViewHelper webViewHelper;
3638 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3639 frame = webViewHelper.webView()->mainFrame();
3640 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3641 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3642
3643 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3644 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3645
3646 // As above, but extending the selection to the bottom of the document.
3647 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3648 frame = webViewHelper.webView()->mainFrame();
3649
3650 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3651 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3652 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3653 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3654
3655 EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3656 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3657 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3658 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3659 }
3660
TEST_F(WebFrameTest,SelectRangeCanMoveSelectionStart)3661 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart)
3662 {
3663 registerMockedHttpURLLoad("text_selection.html");
3664 FrameTestHelpers::WebViewHelper webViewHelper;
3665 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3666 WebFrame* frame = webViewHelper.webView()->mainFrame();
3667
3668 // Select second span. We can move the start to include the first span.
3669 frame->executeScript(WebScriptSource("selectElement('header_2');"));
3670 EXPECT_EQ("Header 2.", selectionAsString(frame));
3671 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3672 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3673
3674 // We can move the start and end together.
3675 frame->executeScript(WebScriptSource("selectElement('header_1');"));
3676 EXPECT_EQ("Header 1.", selectionAsString(frame));
3677 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1")));
3678 EXPECT_EQ("", selectionAsString(frame));
3679 // Selection is a caret, not empty.
3680 EXPECT_FALSE(frame->selectionRange().isNull());
3681
3682 // We can move the start across the end.
3683 frame->executeScript(WebScriptSource("selectElement('header_1');"));
3684 EXPECT_EQ("Header 1.", selectionAsString(frame));
3685 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3686 EXPECT_EQ(" Header 2.", selectionAsString(frame));
3687
3688 // Can't extend the selection part-way into an editable element.
3689 frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3690 EXPECT_EQ("Footer 2.", selectionAsString(frame));
3691 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2")));
3692 EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame));
3693
3694 // Can extend the selection completely across editable elements.
3695 frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3696 EXPECT_EQ("Footer 2.", selectionAsString(frame));
3697 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2")));
3698 EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame));
3699
3700 // If the selection is editable text, we can't extend it into non-editable text.
3701 frame->executeScript(WebScriptSource("selectElement('editable_2');"));
3702 EXPECT_EQ("Editable 2.", selectionAsString(frame));
3703 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2")));
3704 // positionForPoint returns the wrong values for contenteditable spans. See
3705 // http://crbug.com/238334.
3706 // EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame));
3707 }
3708
TEST_F(WebFrameTest,SelectRangeCanMoveSelectionEnd)3709 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd)
3710 {
3711 registerMockedHttpURLLoad("text_selection.html");
3712 FrameTestHelpers::WebViewHelper webViewHelper;
3713 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3714 WebFrame* frame = webViewHelper.webView()->mainFrame();
3715
3716 // Select first span. We can move the end to include the second span.
3717 frame->executeScript(WebScriptSource("selectElement('header_1');"));
3718 EXPECT_EQ("Header 1.", selectionAsString(frame));
3719 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3720 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3721
3722 // We can move the start and end together.
3723 frame->executeScript(WebScriptSource("selectElement('header_2');"));
3724 EXPECT_EQ("Header 2.", selectionAsString(frame));
3725 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2")));
3726 EXPECT_EQ("", selectionAsString(frame));
3727 // Selection is a caret, not empty.
3728 EXPECT_FALSE(frame->selectionRange().isNull());
3729
3730 // We can move the end across the start.
3731 frame->executeScript(WebScriptSource("selectElement('header_2');"));
3732 EXPECT_EQ("Header 2.", selectionAsString(frame));
3733 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3734 EXPECT_EQ("Header 1. ", selectionAsString(frame));
3735
3736 // Can't extend the selection part-way into an editable element.
3737 frame->executeScript(WebScriptSource("selectElement('header_1');"));
3738 EXPECT_EQ("Header 1.", selectionAsString(frame));
3739 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1")));
3740 EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame));
3741
3742 // Can extend the selection completely across editable elements.
3743 frame->executeScript(WebScriptSource("selectElement('header_1');"));
3744 EXPECT_EQ("Header 1.", selectionAsString(frame));
3745 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3746 EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame));
3747
3748 // If the selection is editable text, we can't extend it into non-editable text.
3749 frame->executeScript(WebScriptSource("selectElement('editable_1');"));
3750 EXPECT_EQ("Editable 1.", selectionAsString(frame));
3751 frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3752 // positionForPoint returns the wrong values for contenteditable spans. See
3753 // http://crbug.com/238334.
3754 // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
3755 }
3756
computeOffset(RenderObject * renderer,int x,int y)3757 static int computeOffset(RenderObject* renderer, int x, int y)
3758 {
3759 return VisiblePosition(renderer->positionForPoint(LayoutPoint(x, y))).deepEquivalent().computeOffsetInContainerNode();
3760 }
3761
3762 // positionForPoint returns the wrong values for contenteditable spans. See
3763 // http://crbug.com/238334.
TEST_F(WebFrameTest,DISABLED_PositionForPointTest)3764 TEST_F(WebFrameTest, DISABLED_PositionForPointTest)
3765 {
3766 registerMockedHttpURLLoad("select_range_span_editable.html");
3767 FrameTestHelpers::WebViewHelper webViewHelper;
3768 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3769 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3770 RenderObject* renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3771 EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3772 EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3773
3774 registerMockedHttpURLLoad("select_range_div_editable.html");
3775 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3776 mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3777 renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3778 EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3779 EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3780 }
3781
3782 #if !OS(MACOSX) && !OS(LINUX)
TEST_F(WebFrameTest,SelectRangeStaysHorizontallyAlignedWhenMoved)3783 TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved)
3784 {
3785 registerMockedHttpURLLoad("move_caret.html");
3786
3787 FrameTestHelpers::WebViewHelper webViewHelper;
3788 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3789 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3790
3791 WebRect initialStartRect;
3792 WebRect initialEndRect;
3793 WebRect startRect;
3794 WebRect endRect;
3795
3796 frame->executeScript(WebScriptSource("selectRange();"));
3797 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3798 WebPoint movedStart(topLeft(initialStartRect));
3799
3800 movedStart.y += 40;
3801 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3802 webViewHelper.webView()->selectionBounds(startRect, endRect);
3803 EXPECT_EQ(startRect, initialStartRect);
3804 EXPECT_EQ(endRect, initialEndRect);
3805
3806 movedStart.y -= 80;
3807 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3808 webViewHelper.webView()->selectionBounds(startRect, endRect);
3809 EXPECT_EQ(startRect, initialStartRect);
3810 EXPECT_EQ(endRect, initialEndRect);
3811
3812 WebPoint movedEnd(bottomRightMinusOne(initialEndRect));
3813
3814 movedEnd.y += 40;
3815 frame->selectRange(topLeft(initialStartRect), movedEnd);
3816 webViewHelper.webView()->selectionBounds(startRect, endRect);
3817 EXPECT_EQ(startRect, initialStartRect);
3818 EXPECT_EQ(endRect, initialEndRect);
3819
3820 movedEnd.y -= 80;
3821 frame->selectRange(topLeft(initialStartRect), movedEnd);
3822 webViewHelper.webView()->selectionBounds(startRect, endRect);
3823 EXPECT_EQ(startRect, initialStartRect);
3824 EXPECT_EQ(endRect, initialEndRect);
3825 }
3826
TEST_F(WebFrameTest,MoveCaretStaysHorizontallyAlignedWhenMoved)3827 TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved)
3828 {
3829 WebLocalFrameImpl* frame;
3830 registerMockedHttpURLLoad("move_caret.html");
3831
3832 FrameTestHelpers::WebViewHelper webViewHelper;
3833 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3834 frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
3835
3836 WebRect initialStartRect;
3837 WebRect initialEndRect;
3838 WebRect startRect;
3839 WebRect endRect;
3840
3841 frame->executeScript(WebScriptSource("selectCaret();"));
3842 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3843 WebPoint moveTo(topLeft(initialStartRect));
3844
3845 moveTo.y += 40;
3846 frame->moveCaretSelection(moveTo);
3847 webViewHelper.webView()->selectionBounds(startRect, endRect);
3848 EXPECT_EQ(startRect, initialStartRect);
3849 EXPECT_EQ(endRect, initialEndRect);
3850
3851 moveTo.y -= 80;
3852 frame->moveCaretSelection(moveTo);
3853 webViewHelper.webView()->selectionBounds(startRect, endRect);
3854 EXPECT_EQ(startRect, initialStartRect);
3855 EXPECT_EQ(endRect, initialEndRect);
3856 }
3857 #endif
3858
3859 class CompositedSelectionBoundsTestLayerTreeView : public WebLayerTreeView {
3860 public:
CompositedSelectionBoundsTestLayerTreeView()3861 CompositedSelectionBoundsTestLayerTreeView() : m_selectionCleared(false) { }
~CompositedSelectionBoundsTestLayerTreeView()3862 virtual ~CompositedSelectionBoundsTestLayerTreeView() { }
3863
setSurfaceReady()3864 virtual void setSurfaceReady() OVERRIDE { }
setRootLayer(const WebLayer &)3865 virtual void setRootLayer(const WebLayer&) OVERRIDE { }
clearRootLayer()3866 virtual void clearRootLayer() OVERRIDE { }
setViewportSize(const WebSize & deviceViewportSize)3867 virtual void setViewportSize(const WebSize& deviceViewportSize) OVERRIDE { }
deviceViewportSize() const3868 virtual WebSize deviceViewportSize() const OVERRIDE { return WebSize(); }
setDeviceScaleFactor(float)3869 virtual void setDeviceScaleFactor(float) OVERRIDE { }
deviceScaleFactor() const3870 virtual float deviceScaleFactor() const OVERRIDE { return 1.f; }
setBackgroundColor(WebColor)3871 virtual void setBackgroundColor(WebColor) OVERRIDE { }
setHasTransparentBackground(bool)3872 virtual void setHasTransparentBackground(bool) OVERRIDE { }
setVisible(bool)3873 virtual void setVisible(bool) OVERRIDE { }
setPageScaleFactorAndLimits(float pageScaleFactor,float minimum,float maximum)3874 virtual void setPageScaleFactorAndLimits(float pageScaleFactor, float minimum, float maximum) OVERRIDE { }
startPageScaleAnimation(const WebPoint & destination,bool useAnchor,float newPageScale,double durationSec)3875 virtual void startPageScaleAnimation(const WebPoint& destination, bool useAnchor, float newPageScale, double durationSec) OVERRIDE { }
setNeedsAnimate()3876 virtual void setNeedsAnimate() OVERRIDE { }
commitRequested() const3877 virtual bool commitRequested() const OVERRIDE { return false; }
finishAllRendering()3878 virtual void finishAllRendering() OVERRIDE { }
registerSelection(const WebSelectionBound & start,const WebSelectionBound & end)3879 virtual void registerSelection(const WebSelectionBound& start, const WebSelectionBound& end) OVERRIDE
3880 {
3881 m_start = adoptPtr(new WebSelectionBound(start));
3882 m_end = adoptPtr(new WebSelectionBound(end));
3883 }
clearSelection()3884 virtual void clearSelection() OVERRIDE
3885 {
3886 m_selectionCleared = true;
3887 m_start.clear();
3888 m_end.clear();
3889 }
3890
getAndResetSelectionCleared()3891 bool getAndResetSelectionCleared()
3892 {
3893 bool selectionCleared = m_selectionCleared;
3894 m_selectionCleared = false;
3895 return selectionCleared;
3896 }
3897
start() const3898 const WebSelectionBound* start() const { return m_start.get(); }
end() const3899 const WebSelectionBound* end() const { return m_end.get(); }
3900
3901 private:
3902 bool m_selectionCleared;
3903 OwnPtr<WebSelectionBound> m_start;
3904 OwnPtr<WebSelectionBound> m_end;
3905 };
3906
3907 class CompositedSelectionBoundsTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
3908 public:
~CompositedSelectionBoundsTestWebViewClient()3909 virtual ~CompositedSelectionBoundsTestWebViewClient() { }
layerTreeView()3910 virtual WebLayerTreeView* layerTreeView() OVERRIDE { return &m_testLayerTreeView; }
3911
selectionLayerTreeView()3912 CompositedSelectionBoundsTestLayerTreeView& selectionLayerTreeView() { return m_testLayerTreeView; }
3913
3914 private:
3915 CompositedSelectionBoundsTestLayerTreeView m_testLayerTreeView;
3916 };
3917
3918 class CompositedSelectionBoundsTest : public WebFrameTest {
3919 protected:
CompositedSelectionBoundsTest()3920 CompositedSelectionBoundsTest()
3921 : m_fakeSelectionLayerTreeView(m_fakeSelectionWebViewClient.selectionLayerTreeView())
3922 {
3923 blink::RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
3924 registerMockedHttpURLLoad("Ahem.ttf");
3925
3926 m_webViewHelper.initialize(true, 0, &m_fakeSelectionWebViewClient);
3927 m_webViewHelper.webView()->settings()->setDefaultFontSize(12);
3928 m_webViewHelper.webView()->setPageScaleFactorLimits(1, 1);
3929 m_webViewHelper.webView()->resize(WebSize(640, 480));
3930 }
3931
runTest(const char * testFile)3932 void runTest(const char* testFile)
3933 {
3934 registerMockedHttpURLLoad(testFile);
3935 FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), m_baseURL + testFile);
3936 m_webViewHelper.webView()->layout();
3937
3938 const WebSelectionBound* selectStart = m_fakeSelectionLayerTreeView.start();
3939 const WebSelectionBound* selectEnd = m_fakeSelectionLayerTreeView.end();
3940
3941 v8::HandleScope handleScope(v8::Isolate::GetCurrent());
3942 v8::Handle<v8::Value> result = m_webViewHelper.webView()->mainFrame()->toWebLocalFrame()->executeScriptAndReturnValueForTests(WebScriptSource("expectedResult"));
3943 if (result.IsEmpty() || (*result)->IsUndefined()) {
3944 EXPECT_FALSE(selectStart);
3945 EXPECT_FALSE(selectEnd);
3946 return;
3947 }
3948
3949 ASSERT_TRUE(selectStart);
3950 ASSERT_TRUE(selectEnd);
3951
3952 ASSERT_TRUE((*result)->IsArray());
3953 v8::Array& expectedResult = *v8::Array::Cast(*result);
3954 ASSERT_EQ(10u, expectedResult.Length());
3955
3956 blink::Node* layerOwnerNodeForStart = blink::V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(0));
3957 ASSERT_TRUE(layerOwnerNodeForStart);
3958 EXPECT_EQ(layerOwnerNodeForStart->renderer()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectStart->layerId);
3959 EXPECT_EQ(expectedResult.Get(1)->Int32Value(), selectStart->edgeTopInLayer.x);
3960 EXPECT_EQ(expectedResult.Get(2)->Int32Value(), selectStart->edgeTopInLayer.y);
3961 EXPECT_EQ(expectedResult.Get(3)->Int32Value(), selectStart->edgeBottomInLayer.x);
3962 EXPECT_EQ(expectedResult.Get(4)->Int32Value(), selectStart->edgeBottomInLayer.y);
3963
3964 blink::Node* layerOwnerNodeForEnd = blink::V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(5));
3965 ASSERT_TRUE(layerOwnerNodeForEnd);
3966 EXPECT_EQ(layerOwnerNodeForEnd->renderer()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectEnd->layerId);
3967 EXPECT_EQ(expectedResult.Get(6)->Int32Value(), selectEnd->edgeTopInLayer.x);
3968 EXPECT_EQ(expectedResult.Get(7)->Int32Value(), selectEnd->edgeTopInLayer.y);
3969 EXPECT_EQ(expectedResult.Get(8)->Int32Value(), selectEnd->edgeBottomInLayer.x);
3970 EXPECT_EQ(expectedResult.Get(9)->Int32Value(), selectEnd->edgeBottomInLayer.y);
3971 }
3972
runTestWithMultipleFiles(const char * testFile,...)3973 void runTestWithMultipleFiles(const char* testFile, ...)
3974 {
3975 va_list auxFiles;
3976 va_start(auxFiles, testFile);
3977 while (const char* auxFile = va_arg(auxFiles, const char*))
3978 registerMockedHttpURLLoad(auxFile);
3979 va_end(auxFiles);
3980
3981 runTest(testFile);
3982 }
3983
3984 CompositedSelectionBoundsTestWebViewClient m_fakeSelectionWebViewClient;
3985 CompositedSelectionBoundsTestLayerTreeView& m_fakeSelectionLayerTreeView;
3986 FrameTestHelpers::WebViewHelper m_webViewHelper;
3987 };
3988
TEST_F(CompositedSelectionBoundsTest,None)3989 TEST_F(CompositedSelectionBoundsTest, None) { runTest("composited_selection_bounds_none.html"); }
TEST_F(CompositedSelectionBoundsTest,Basic)3990 TEST_F(CompositedSelectionBoundsTest, Basic) { runTest("composited_selection_bounds_basic.html"); }
TEST_F(CompositedSelectionBoundsTest,Transformed)3991 TEST_F(CompositedSelectionBoundsTest, Transformed) { runTest("composited_selection_bounds_transformed.html"); }
TEST_F(CompositedSelectionBoundsTest,SplitLayer)3992 TEST_F(CompositedSelectionBoundsTest, SplitLayer) { runTest("composited_selection_bounds_split_layer.html"); }
TEST_F(CompositedSelectionBoundsTest,EmptyLayer)3993 TEST_F(CompositedSelectionBoundsTest, EmptyLayer) { runTest("composited_selection_bounds_empty_layer.html"); }
TEST_F(CompositedSelectionBoundsTest,Iframe)3994 TEST_F(CompositedSelectionBoundsTest, Iframe) { runTestWithMultipleFiles("composited_selection_bounds_iframe.html", "composited_selection_bounds_basic.html", nullptr); }
3995
TEST_F(WebFrameTest,CompositedSelectionBoundsCleared)3996 TEST_F(WebFrameTest, CompositedSelectionBoundsCleared)
3997 {
3998 RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
3999
4000 registerMockedHttpURLLoad("select_range_basic.html");
4001 registerMockedHttpURLLoad("select_range_scroll.html");
4002
4003 int viewWidth = 500;
4004 int viewHeight = 500;
4005
4006 CompositedSelectionBoundsTestWebViewClient fakeSelectionWebViewClient;
4007 CompositedSelectionBoundsTestLayerTreeView& fakeSelectionLayerTreeView = fakeSelectionWebViewClient.selectionLayerTreeView();
4008
4009 FrameTestHelpers::WebViewHelper webViewHelper;
4010 webViewHelper.initialize(true, 0, &fakeSelectionWebViewClient);
4011 webViewHelper.webView()->settings()->setDefaultFontSize(12);
4012 webViewHelper.webView()->setPageScaleFactorLimits(1, 1);
4013 webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
4014 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_basic.html");
4015
4016 // The frame starts with a non-empty selection.
4017 WebFrame* frame = webViewHelper.webView()->mainFrame();
4018 ASSERT_TRUE(frame->hasSelection());
4019 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4020
4021 // The selection cleared notification should be triggered upon layout.
4022 frame->executeCommand(WebString::fromUTF8("Unselect"));
4023 ASSERT_FALSE(frame->hasSelection());
4024 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4025 webViewHelper.webView()->layout();
4026 EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4027
4028 frame->executeCommand(WebString::fromUTF8("SelectAll"));
4029 webViewHelper.webView()->layout();
4030 ASSERT_TRUE(frame->hasSelection());
4031 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4032
4033 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_scroll.html");
4034 ASSERT_TRUE(frame->hasSelection());
4035 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4036
4037 // Transitions between non-empty selections should not trigger a clearing.
4038 WebRect startWebRect;
4039 WebRect endWebRect;
4040 webViewHelper.webViewImpl()->selectionBounds(startWebRect, endWebRect);
4041 WebPoint movedEnd(bottomRightMinusOne(endWebRect));
4042 endWebRect.x -= 20;
4043 frame->selectRange(topLeft(startWebRect), movedEnd);
4044 webViewHelper.webView()->layout();
4045 ASSERT_TRUE(frame->hasSelection());
4046 EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4047
4048 frame = webViewHelper.webView()->mainFrame();
4049 frame->executeCommand(WebString::fromUTF8("Unselect"));
4050 webViewHelper.webView()->layout();
4051 ASSERT_FALSE(frame->hasSelection());
4052 EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4053 }
4054
4055 class DisambiguationPopupTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
4056 public:
didTapMultipleTargets(const WebSize &,const WebRect &,const WebVector<WebRect> & targetRects)4057 virtual bool didTapMultipleTargets(const WebSize&, const WebRect&, const WebVector<WebRect>& targetRects) OVERRIDE
4058 {
4059 EXPECT_GE(targetRects.size(), 2u);
4060 m_triggered = true;
4061 return true;
4062 }
4063
triggered() const4064 bool triggered() const { return m_triggered; }
resetTriggered()4065 void resetTriggered() { m_triggered = false; }
4066 bool m_triggered;
4067 };
4068
fatTap(int x,int y)4069 static WebGestureEvent fatTap(int x, int y)
4070 {
4071 WebGestureEvent event;
4072 event.type = WebInputEvent::GestureTap;
4073 event.x = x;
4074 event.y = y;
4075 event.data.tap.width = 50;
4076 event.data.tap.height = 50;
4077 return event;
4078 }
4079
TEST_F(WebFrameTest,DisambiguationPopup)4080 TEST_F(WebFrameTest, DisambiguationPopup)
4081 {
4082 const std::string htmlFile = "disambiguation_popup.html";
4083 registerMockedHttpURLLoad(htmlFile);
4084
4085 DisambiguationPopupTestWebViewClient client;
4086
4087 // Make sure we initialize to minimum scale, even if the window size
4088 // only becomes available after the load begins.
4089 FrameTestHelpers::WebViewHelper webViewHelper;
4090 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4091 webViewHelper.webView()->resize(WebSize(1000, 1000));
4092 webViewHelper.webView()->layout();
4093
4094 client.resetTriggered();
4095 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4096 EXPECT_FALSE(client.triggered());
4097
4098 client.resetTriggered();
4099 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4100 EXPECT_FALSE(client.triggered());
4101
4102 for (int i = 0; i <= 46; i++) {
4103 client.resetTriggered();
4104 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4105
4106 int j = i % 10;
4107 if (j >= 7 && j <= 9)
4108 EXPECT_TRUE(client.triggered());
4109 else
4110 EXPECT_FALSE(client.triggered());
4111 }
4112
4113 for (int i = 0; i <= 46; i++) {
4114 client.resetTriggered();
4115 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4116
4117 int j = i % 10;
4118 if (j >= 7 && j <= 9)
4119 EXPECT_TRUE(client.triggered());
4120 else
4121 EXPECT_FALSE(client.triggered());
4122 }
4123 }
4124
TEST_F(WebFrameTest,DisambiguationPopupNoContainer)4125 TEST_F(WebFrameTest, DisambiguationPopupNoContainer)
4126 {
4127 registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
4128
4129 DisambiguationPopupTestWebViewClient client;
4130
4131 // Make sure we initialize to minimum scale, even if the window size
4132 // only becomes available after the load begins.
4133 FrameTestHelpers::WebViewHelper webViewHelper;
4134 webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_no_container.html", true, 0, &client);
4135 webViewHelper.webView()->resize(WebSize(1000, 1000));
4136 webViewHelper.webView()->layout();
4137
4138 client.resetTriggered();
4139 webViewHelper.webView()->handleInputEvent(fatTap(50, 50));
4140 EXPECT_FALSE(client.triggered());
4141 }
4142
TEST_F(WebFrameTest,DisambiguationPopupMobileSite)4143 TEST_F(WebFrameTest, DisambiguationPopupMobileSite)
4144 {
4145 UseMockScrollbarSettings mockScrollbarSettings;
4146 const std::string htmlFile = "disambiguation_popup_mobile_site.html";
4147 registerMockedHttpURLLoad(htmlFile);
4148
4149 DisambiguationPopupTestWebViewClient client;
4150
4151 // Make sure we initialize to minimum scale, even if the window size
4152 // only becomes available after the load begins.
4153 FrameTestHelpers::WebViewHelper webViewHelper;
4154 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4155 webViewHelper.webView()->resize(WebSize(1000, 1000));
4156 webViewHelper.webView()->layout();
4157
4158 client.resetTriggered();
4159 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4160 EXPECT_FALSE(client.triggered());
4161
4162 client.resetTriggered();
4163 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4164 EXPECT_FALSE(client.triggered());
4165
4166 for (int i = 0; i <= 46; i++) {
4167 client.resetTriggered();
4168 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4169 EXPECT_FALSE(client.triggered());
4170 }
4171
4172 for (int i = 0; i <= 46; i++) {
4173 client.resetTriggered();
4174 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4175 EXPECT_FALSE(client.triggered());
4176 }
4177 }
4178
TEST_F(WebFrameTest,DisambiguationPopupViewportSite)4179 TEST_F(WebFrameTest, DisambiguationPopupViewportSite)
4180 {
4181 UseMockScrollbarSettings mockScrollbarSettings;
4182 const std::string htmlFile = "disambiguation_popup_viewport_site.html";
4183 registerMockedHttpURLLoad(htmlFile);
4184
4185 DisambiguationPopupTestWebViewClient client;
4186
4187 // Make sure we initialize to minimum scale, even if the window size
4188 // only becomes available after the load begins.
4189 FrameTestHelpers::WebViewHelper webViewHelper;
4190 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4191 webViewHelper.webView()->resize(WebSize(1000, 1000));
4192 webViewHelper.webView()->layout();
4193
4194 client.resetTriggered();
4195 webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4196 EXPECT_FALSE(client.triggered());
4197
4198 client.resetTriggered();
4199 webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4200 EXPECT_FALSE(client.triggered());
4201
4202 for (int i = 0; i <= 46; i++) {
4203 client.resetTriggered();
4204 webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4205 EXPECT_FALSE(client.triggered());
4206 }
4207
4208 for (int i = 0; i <= 46; i++) {
4209 client.resetTriggered();
4210 webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4211 EXPECT_FALSE(client.triggered());
4212 }
4213 }
4214
enableVirtualViewport(WebSettings * settings)4215 static void enableVirtualViewport(WebSettings* settings)
4216 {
4217 settings->setPinchVirtualViewportEnabled(true);
4218 settings->setViewportEnabled(true);
4219 settings->setViewportMetaEnabled(true);
4220 settings->setShrinksViewportContentToFit(true);
4221 }
4222
TEST_F(WebFrameTest,DisambiguationPopupPinchViewport)4223 TEST_F(WebFrameTest, DisambiguationPopupPinchViewport)
4224 {
4225 UseMockScrollbarSettings mockScrollbarSettings;
4226 const std::string htmlFile = "disambiguation_popup_200_by_800.html";
4227 registerMockedHttpURLLoad(htmlFile);
4228
4229 DisambiguationPopupTestWebViewClient client;
4230
4231 FrameTestHelpers::WebViewHelper webViewHelper;
4232 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableVirtualViewport);
4233
4234 WebViewImpl* webViewImpl = webViewHelper.webViewImpl();
4235 ASSERT_TRUE(webViewImpl);
4236 LocalFrame* frame = webViewImpl->mainFrameImpl()->frame();
4237 ASSERT_TRUE(frame);
4238
4239 webViewHelper.webView()->resize(WebSize(100, 200));
4240
4241 // Scroll main frame to the bottom of the document
4242 webViewImpl->setMainFrameScrollOffset(WebPoint(0, 400));
4243 EXPECT_POINT_EQ(IntPoint(0, 400), frame->view()->scrollPosition());
4244
4245 webViewImpl->setPageScaleFactor(2.0);
4246
4247 // Scroll pinch viewport to the top of the main frame.
4248 PinchViewport& pinchViewport = frame->page()->frameHost().pinchViewport();
4249 pinchViewport.setLocation(FloatPoint(0, 0));
4250 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.location());
4251
4252 // Tap at the top: there is nothing there.
4253 client.resetTriggered();
4254 webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4255 EXPECT_FALSE(client.triggered());
4256
4257 // Scroll pinch viewport to the bottom of the main frame.
4258 pinchViewport.setLocation(FloatPoint(0, 200));
4259 EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 200), pinchViewport.location());
4260
4261 // Now the tap with the same coordinates should hit two elements.
4262 client.resetTriggered();
4263 webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4264 EXPECT_TRUE(client.triggered());
4265 }
4266
TEST_F(WebFrameTest,DisambiguationPopupBlacklist)4267 TEST_F(WebFrameTest, DisambiguationPopupBlacklist)
4268 {
4269 const unsigned viewportWidth = 500;
4270 const unsigned viewportHeight = 1000;
4271 const unsigned divHeight = 100;
4272 const std::string htmlFile = "disambiguation_popup_blacklist.html";
4273 registerMockedHttpURLLoad(htmlFile);
4274
4275 DisambiguationPopupTestWebViewClient client;
4276
4277 // Make sure we initialize to minimum scale, even if the window size
4278 // only becomes available after the load begins.
4279 FrameTestHelpers::WebViewHelper webViewHelper;
4280 webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4281 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
4282 webViewHelper.webView()->layout();
4283
4284 // Click somewhere where the popup shouldn't appear.
4285 client.resetTriggered();
4286 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, 0));
4287 EXPECT_FALSE(client.triggered());
4288
4289 // Click directly in between two container divs with click handlers, with children that don't handle clicks.
4290 client.resetTriggered();
4291 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight));
4292 EXPECT_TRUE(client.triggered());
4293
4294 // The third div container should be blacklisted if you click on the link it contains.
4295 client.resetTriggered();
4296 webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight * 3.25));
4297 EXPECT_FALSE(client.triggered());
4298 }
4299
TEST_F(WebFrameTest,DisambiguationPopupPageScale)4300 TEST_F(WebFrameTest, DisambiguationPopupPageScale)
4301 {
4302 registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
4303
4304 DisambiguationPopupTestWebViewClient client;
4305
4306 // Make sure we initialize to minimum scale, even if the window size
4307 // only becomes available after the load begins.
4308 FrameTestHelpers::WebViewHelper webViewHelper;
4309 webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_page_scale.html", true, 0, &client);
4310 webViewHelper.webView()->resize(WebSize(1000, 1000));
4311 webViewHelper.webView()->layout();
4312
4313 client.resetTriggered();
4314 webViewHelper.webView()->handleInputEvent(fatTap(80, 80));
4315 EXPECT_TRUE(client.triggered());
4316
4317 client.resetTriggered();
4318 webViewHelper.webView()->handleInputEvent(fatTap(230, 190));
4319 EXPECT_TRUE(client.triggered());
4320
4321 webViewHelper.webView()->setPageScaleFactor(3.0f);
4322 webViewHelper.webView()->layout();
4323
4324 client.resetTriggered();
4325 webViewHelper.webView()->handleInputEvent(fatTap(240, 240));
4326 EXPECT_TRUE(client.triggered());
4327
4328 client.resetTriggered();
4329 webViewHelper.webView()->handleInputEvent(fatTap(690, 570));
4330 EXPECT_FALSE(client.triggered());
4331 }
4332
4333 class TestSubstituteDataWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4334 public:
TestSubstituteDataWebFrameClient()4335 TestSubstituteDataWebFrameClient()
4336 : m_commitCalled(false)
4337 {
4338 }
4339
didFailProvisionalLoad(WebLocalFrame * frame,const WebURLError & error)4340 virtual void didFailProvisionalLoad(WebLocalFrame* frame, const WebURLError& error)
4341 {
4342 frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true);
4343 }
4344
didCommitProvisionalLoad(WebLocalFrame * frame,const WebHistoryItem &,WebHistoryCommitType)4345 virtual void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType)
4346 {
4347 if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank")))
4348 m_commitCalled = true;
4349 }
4350
commitCalled() const4351 bool commitCalled() const { return m_commitCalled; }
4352
4353 private:
4354 bool m_commitCalled;
4355 };
4356
TEST_F(WebFrameTest,ReplaceNavigationAfterHistoryNavigation)4357 TEST_F(WebFrameTest, ReplaceNavigationAfterHistoryNavigation)
4358 {
4359 TestSubstituteDataWebFrameClient webFrameClient;
4360
4361 FrameTestHelpers::WebViewHelper webViewHelper;
4362 webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
4363 WebFrame* frame = webViewHelper.webView()->mainFrame();
4364
4365 // Load a url as a history navigation that will return an error. TestSubstituteDataWebFrameClient
4366 // will start a SubstituteData load in response to the load failure, which should get fully committed.
4367 // Due to https://bugs.webkit.org/show_bug.cgi?id=91685, FrameLoader::didReceiveData() wasn't getting
4368 // called in this case, which resulted in the SubstituteData document not getting displayed.
4369 WebURLError error;
4370 error.reason = 1337;
4371 error.domain = "WebFrameTest";
4372 std::string errorURL = "http://0.0.0.0";
4373 WebURLResponse response;
4374 response.initialize();
4375 response.setURL(URLTestHelpers::toKURL(errorURL));
4376 response.setMIMEType("text/html");
4377 response.setHTTPStatusCode(500);
4378 WebHistoryItem errorHistoryItem;
4379 errorHistoryItem.initialize();
4380 errorHistoryItem.setURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
4381 Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
4382 FrameTestHelpers::loadHistoryItem(frame, errorHistoryItem, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
4383
4384 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
4385 EXPECT_EQ("This should appear", text.utf8());
4386 EXPECT_TRUE(webFrameClient.commitCalled());
4387 }
4388
4389 class TestWillInsertBodyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4390 public:
TestWillInsertBodyWebFrameClient()4391 TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false)
4392 {
4393 }
4394
didCommitProvisionalLoad(WebLocalFrame *,const WebHistoryItem &,WebHistoryCommitType)4395 virtual void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
4396 {
4397 m_numBodies = 0;
4398 m_didLoad = true;
4399 }
4400
didCreateDocumentElement(WebLocalFrame *)4401 virtual void didCreateDocumentElement(WebLocalFrame*) OVERRIDE
4402 {
4403 EXPECT_EQ(0, m_numBodies);
4404 }
4405
willInsertBody(WebLocalFrame *)4406 virtual void willInsertBody(WebLocalFrame*) OVERRIDE
4407 {
4408 m_numBodies++;
4409 }
4410
4411 int m_numBodies;
4412 bool m_didLoad;
4413 };
4414
TEST_F(WebFrameTest,HTMLDocument)4415 TEST_F(WebFrameTest, HTMLDocument)
4416 {
4417 registerMockedHttpURLLoad("clipped-body.html");
4418
4419 TestWillInsertBodyWebFrameClient webFrameClient;
4420 FrameTestHelpers::WebViewHelper webViewHelper;
4421 webViewHelper.initializeAndLoad(m_baseURL + "clipped-body.html", false, &webFrameClient);
4422
4423 EXPECT_TRUE(webFrameClient.m_didLoad);
4424 EXPECT_EQ(1, webFrameClient.m_numBodies);
4425 }
4426
TEST_F(WebFrameTest,EmptyDocument)4427 TEST_F(WebFrameTest, EmptyDocument)
4428 {
4429 registerMockedHttpURLLoad("pageserializer/green_rectangle.svg");
4430
4431 TestWillInsertBodyWebFrameClient webFrameClient;
4432 FrameTestHelpers::WebViewHelper webViewHelper;
4433 webViewHelper.initialize(false, &webFrameClient);
4434
4435 EXPECT_FALSE(webFrameClient.m_didLoad);
4436 EXPECT_EQ(1, webFrameClient.m_numBodies); // The empty document that a new frame starts with triggers this.
4437 }
4438
TEST_F(WebFrameTest,MoveCaretSelectionTowardsWindowPointWithNoSelection)4439 TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection)
4440 {
4441 FrameTestHelpers::WebViewHelper webViewHelper;
4442 webViewHelper.initializeAndLoad("about:blank", true);
4443 WebFrame* frame = webViewHelper.webView()->mainFrame();
4444
4445 // This test passes if this doesn't crash.
4446 frame->moveCaretSelection(WebPoint(0, 0));
4447 }
4448
TEST_F(WebFrameTest,NavigateToSandboxedMarkup)4449 TEST_F(WebFrameTest, NavigateToSandboxedMarkup)
4450 {
4451 FrameTestHelpers::WebViewHelper webViewHelper;
4452 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad("about:blank", true);
4453 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4454
4455 frame->document().setIsTransitionDocument();
4456
4457 std::string markup("<div id='foo'></div><script>document.getElementById('foo').setAttribute('dir', 'rtl')</script>");
4458 frame->navigateToSandboxedMarkup(WebData(markup.data(), markup.length()));
4459 FrameTestHelpers::runPendingTasks();
4460
4461 WebDocument document = webViewImpl->mainFrame()->document();
4462 WebElement transitionElement = document.getElementById("foo");
4463 // Check that the markup got navigated to successfully.
4464 EXPECT_FALSE(transitionElement.isNull());
4465
4466 // Check that the inline script was not executed.
4467 EXPECT_FALSE(transitionElement.hasAttribute("dir"));
4468 }
4469
4470 class SpellCheckClient : public WebSpellCheckClient {
4471 public:
SpellCheckClient(uint32_t hash=0)4472 explicit SpellCheckClient(uint32_t hash = 0) : m_numberOfTimesChecked(0), m_hash(hash) { }
~SpellCheckClient()4473 virtual ~SpellCheckClient() { }
requestCheckingOfText(const WebString &,const WebVector<uint32_t> &,const WebVector<unsigned> &,WebTextCheckingCompletion * completion)4474 virtual void requestCheckingOfText(const WebString&, const WebVector<uint32_t>&, const WebVector<unsigned>&, WebTextCheckingCompletion* completion) OVERRIDE
4475 {
4476 ++m_numberOfTimesChecked;
4477 Vector<WebTextCheckingResult> results;
4478 const int misspellingStartOffset = 1;
4479 const int misspellingLength = 8;
4480 results.append(WebTextCheckingResult(WebTextDecorationTypeSpelling, misspellingStartOffset, misspellingLength, WebString(), m_hash));
4481 completion->didFinishCheckingText(results);
4482 }
numberOfTimesChecked() const4483 int numberOfTimesChecked() const { return m_numberOfTimesChecked; }
4484 private:
4485 int m_numberOfTimesChecked;
4486 uint32_t m_hash;
4487 };
4488
TEST_F(WebFrameTest,ReplaceMisspelledRange)4489 TEST_F(WebFrameTest, ReplaceMisspelledRange)
4490 {
4491 registerMockedHttpURLLoad("spell.html");
4492 FrameTestHelpers::WebViewHelper webViewHelper;
4493 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4494 SpellCheckClient spellcheck;
4495 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4496
4497 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4498 Document* document = frame->frame()->document();
4499 Element* element = document->getElementById("data");
4500
4501 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4502 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4503 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4504
4505 element->focus();
4506 document->execCommand("InsertText", false, "_wellcome_.");
4507
4508 const int allTextBeginOffset = 0;
4509 const int allTextLength = 11;
4510 frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4511 RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4512
4513 EXPECT_EQ(1, spellcheck.numberOfTimesChecked());
4514 EXPECT_EQ(1U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4515
4516 frame->replaceMisspelledRange("welcome");
4517 EXPECT_EQ("_welcome_.", frame->contentAsText(std::numeric_limits<size_t>::max()).utf8());
4518 }
4519
TEST_F(WebFrameTest,RemoveSpellingMarkers)4520 TEST_F(WebFrameTest, RemoveSpellingMarkers)
4521 {
4522 registerMockedHttpURLLoad("spell.html");
4523 FrameTestHelpers::WebViewHelper webViewHelper;
4524 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4525 SpellCheckClient spellcheck;
4526 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4527
4528 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4529 Document* document = frame->frame()->document();
4530 Element* element = document->getElementById("data");
4531
4532 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4533 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4534 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4535
4536 element->focus();
4537 document->execCommand("InsertText", false, "_wellcome_.");
4538
4539 frame->removeSpellingMarkers();
4540
4541 const int allTextBeginOffset = 0;
4542 const int allTextLength = 11;
4543 frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4544 RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4545
4546 EXPECT_EQ(0U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4547 }
4548
TEST_F(WebFrameTest,RemoveSpellingMarkersUnderWords)4549 TEST_F(WebFrameTest, RemoveSpellingMarkersUnderWords)
4550 {
4551 registerMockedHttpURLLoad("spell.html");
4552 FrameTestHelpers::WebViewHelper webViewHelper;
4553 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4554 SpellCheckClient spellcheck;
4555 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4556
4557 LocalFrame* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame())->frame();
4558 Document* document = frame->document();
4559 Element* element = document->getElementById("data");
4560
4561 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4562 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4563 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4564
4565 element->focus();
4566 document->execCommand("InsertText", false, " wellcome ");
4567
4568 WebVector<uint32_t> documentMarkers1;
4569 webViewHelper.webView()->spellingMarkers(&documentMarkers1);
4570 EXPECT_EQ(1U, documentMarkers1.size());
4571
4572 Vector<String> words;
4573 words.append("wellcome");
4574 frame->removeSpellingMarkersUnderWords(words);
4575
4576 WebVector<uint32_t> documentMarkers2;
4577 webViewHelper.webView()->spellingMarkers(&documentMarkers2);
4578 EXPECT_EQ(0U, documentMarkers2.size());
4579 }
4580
TEST_F(WebFrameTest,MarkerHashIdentifiers)4581 TEST_F(WebFrameTest, MarkerHashIdentifiers) {
4582 registerMockedHttpURLLoad("spell.html");
4583 FrameTestHelpers::WebViewHelper webViewHelper;
4584 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4585
4586 static const uint32_t kHash = 42;
4587 SpellCheckClient spellcheck(kHash);
4588 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4589
4590 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4591 Document* document = frame->frame()->document();
4592 Element* element = document->getElementById("data");
4593
4594 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4595 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4596 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4597
4598 element->focus();
4599 document->execCommand("InsertText", false, "wellcome.");
4600
4601 WebVector<uint32_t> documentMarkers;
4602 webViewHelper.webView()->spellingMarkers(&documentMarkers);
4603 EXPECT_EQ(1U, documentMarkers.size());
4604 EXPECT_EQ(kHash, documentMarkers[0]);
4605 }
4606
4607 class StubbornSpellCheckClient : public WebSpellCheckClient {
4608 public:
StubbornSpellCheckClient()4609 StubbornSpellCheckClient() : m_completion(0) { }
~StubbornSpellCheckClient()4610 virtual ~StubbornSpellCheckClient() { }
4611
requestCheckingOfText(const WebString &,const WebVector<uint32_t> &,const WebVector<unsigned> &,WebTextCheckingCompletion * completion)4612 virtual void requestCheckingOfText(
4613 const WebString&,
4614 const WebVector<uint32_t>&,
4615 const WebVector<unsigned>&,
4616 WebTextCheckingCompletion* completion) OVERRIDE
4617 {
4618 m_completion = completion;
4619 }
4620
kickNoResults()4621 void kickNoResults()
4622 {
4623 kick(-1, -1, WebTextDecorationTypeSpelling);
4624 }
4625
kick()4626 void kick()
4627 {
4628 kick(1, 8, WebTextDecorationTypeSpelling);
4629 }
4630
kickGrammar()4631 void kickGrammar()
4632 {
4633 kick(1, 8, WebTextDecorationTypeGrammar);
4634 }
4635
kickInvisibleSpellcheck()4636 void kickInvisibleSpellcheck()
4637 {
4638 kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck);
4639 }
4640
4641 private:
kick(int misspellingStartOffset,int misspellingLength,WebTextDecorationType type)4642 void kick(int misspellingStartOffset, int misspellingLength, WebTextDecorationType type)
4643 {
4644 if (!m_completion)
4645 return;
4646 Vector<WebTextCheckingResult> results;
4647 if (misspellingStartOffset >= 0 && misspellingLength > 0)
4648 results.append(WebTextCheckingResult(type, misspellingStartOffset, misspellingLength));
4649 m_completion->didFinishCheckingText(results);
4650 m_completion = 0;
4651 }
4652
4653 WebTextCheckingCompletion* m_completion;
4654 };
4655
TEST_F(WebFrameTest,SlowSpellcheckMarkerPosition)4656 TEST_F(WebFrameTest, SlowSpellcheckMarkerPosition)
4657 {
4658 registerMockedHttpURLLoad("spell.html");
4659 FrameTestHelpers::WebViewHelper webViewHelper;
4660 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4661
4662 StubbornSpellCheckClient spellcheck;
4663 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4664
4665 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4666 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4667 Document* document = frame->frame()->document();
4668 Element* element = document->getElementById("data");
4669
4670 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4671 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4672 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4673
4674 element->focus();
4675 document->execCommand("InsertText", false, "wellcome ");
4676 webInputElement.setSelectionRange(0, 0);
4677 document->execCommand("InsertText", false, "he");
4678
4679 spellcheck.kick();
4680
4681 WebVector<uint32_t> documentMarkers;
4682 webViewHelper.webView()->spellingMarkers(&documentMarkers);
4683 EXPECT_EQ(0U, documentMarkers.size());
4684 }
4685
4686 // This test verifies that cancelling spelling request does not cause a
4687 // write-after-free when there's no spellcheck client set.
TEST_F(WebFrameTest,CancelSpellingRequestCrash)4688 TEST_F(WebFrameTest, CancelSpellingRequestCrash)
4689 {
4690 registerMockedHttpURLLoad("spell.html");
4691 FrameTestHelpers::WebViewHelper webViewHelper;
4692 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4693 webViewHelper.webView()->setSpellCheckClient(0);
4694
4695 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4696 Document* document = frame->frame()->document();
4697 Element* element = document->getElementById("data");
4698
4699 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4700 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4701 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4702
4703 element->focus();
4704 frame->frame()->editor().replaceSelectionWithText("A", false, false);
4705 frame->frame()->spellChecker().cancelCheck();
4706 }
4707
TEST_F(WebFrameTest,SpellcheckResultErasesMarkers)4708 TEST_F(WebFrameTest, SpellcheckResultErasesMarkers)
4709 {
4710 registerMockedHttpURLLoad("spell.html");
4711 FrameTestHelpers::WebViewHelper webViewHelper;
4712 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4713
4714 StubbornSpellCheckClient spellcheck;
4715 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4716
4717 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4718 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4719 Document* document = frame->frame()->document();
4720 Element* element = document->getElementById("data");
4721
4722 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4723 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4724 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4725
4726 element->focus();
4727 document->execCommand("InsertText", false, "welcome ");
4728 document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Spelling);
4729 document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Grammar);
4730 document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::InvisibleSpellcheck);
4731 EXPECT_EQ(3U, document->markers().markers().size());
4732
4733 spellcheck.kickNoResults();
4734 EXPECT_EQ(0U, document->markers().markers().size());
4735 }
4736
TEST_F(WebFrameTest,SpellcheckResultsSavedInDocument)4737 TEST_F(WebFrameTest, SpellcheckResultsSavedInDocument)
4738 {
4739 registerMockedHttpURLLoad("spell.html");
4740 FrameTestHelpers::WebViewHelper webViewHelper;
4741 webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4742
4743 StubbornSpellCheckClient spellcheck;
4744 webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4745
4746 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4747 WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4748 Document* document = frame->frame()->document();
4749 Element* element = document->getElementById("data");
4750
4751 webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4752 webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4753 webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4754
4755 element->focus();
4756 document->execCommand("InsertText", false, "wellcome ");
4757
4758 spellcheck.kick();
4759 ASSERT_EQ(1U, document->markers().markers().size());
4760 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4761 EXPECT_EQ(DocumentMarker::Spelling, document->markers().markers()[0]->type());
4762
4763 document->execCommand("InsertText", false, "wellcome ");
4764
4765 spellcheck.kickGrammar();
4766 ASSERT_EQ(1U, document->markers().markers().size());
4767 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4768 EXPECT_EQ(DocumentMarker::Grammar, document->markers().markers()[0]->type());
4769
4770 document->execCommand("InsertText", false, "wellcome ");
4771
4772 spellcheck.kickInvisibleSpellcheck();
4773 ASSERT_EQ(1U, document->markers().markers().size());
4774 ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4775 EXPECT_EQ(DocumentMarker::InvisibleSpellcheck, document->markers().markers()[0]->type());
4776 }
4777
4778 class TestAccessInitialDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4779 public:
TestAccessInitialDocumentWebFrameClient()4780 TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false)
4781 {
4782 }
4783
didAccessInitialDocument(WebLocalFrame * frame)4784 virtual void didAccessInitialDocument(WebLocalFrame* frame)
4785 {
4786 EXPECT_TRUE(!m_didAccessInitialDocument);
4787 m_didAccessInitialDocument = true;
4788 }
4789
4790 bool m_didAccessInitialDocument;
4791 };
4792
TEST_F(WebFrameTest,DidAccessInitialDocumentBody)4793 TEST_F(WebFrameTest, DidAccessInitialDocumentBody)
4794 {
4795 // FIXME: Why is this local webViewClient needed instead of the default
4796 // WebViewHelper one? With out it there's some mysterious crash in the
4797 // WebViewHelper destructor.
4798 FrameTestHelpers::TestWebViewClient webViewClient;
4799 TestAccessInitialDocumentWebFrameClient webFrameClient;
4800 FrameTestHelpers::WebViewHelper webViewHelper;
4801 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4802 runPendingTasks();
4803 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4804
4805 // Create another window that will try to access it.
4806 FrameTestHelpers::WebViewHelper newWebViewHelper;
4807 WebView* newView = newWebViewHelper.initialize(true);
4808 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4809 runPendingTasks();
4810 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4811
4812 // Access the initial document by modifying the body.
4813 newView->mainFrame()->executeScript(
4814 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4815 runPendingTasks();
4816 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4817
4818 // Access the initial document again, to ensure we don't notify twice.
4819 newView->mainFrame()->executeScript(
4820 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4821 runPendingTasks();
4822 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4823 }
4824
TEST_F(WebFrameTest,DidAccessInitialDocumentNavigator)4825 TEST_F(WebFrameTest, DidAccessInitialDocumentNavigator)
4826 {
4827 // FIXME: Why is this local webViewClient needed instead of the default
4828 // WebViewHelper one? With out it there's some mysterious crash in the
4829 // WebViewHelper destructor.
4830 FrameTestHelpers::TestWebViewClient webViewClient;
4831 TestAccessInitialDocumentWebFrameClient webFrameClient;
4832 FrameTestHelpers::WebViewHelper webViewHelper;
4833 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4834 runPendingTasks();
4835 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4836
4837 // Create another window that will try to access it.
4838 FrameTestHelpers::WebViewHelper newWebViewHelper;
4839 WebView* newView = newWebViewHelper.initialize(true);
4840 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4841 runPendingTasks();
4842 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4843
4844 // Access the initial document to get to the navigator object.
4845 newView->mainFrame()->executeScript(
4846 WebScriptSource("console.log(window.opener.navigator);"));
4847 runPendingTasks();
4848 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4849 }
4850
TEST_F(WebFrameTest,DidAccessInitialDocumentViaJavascriptUrl)4851 TEST_F(WebFrameTest, DidAccessInitialDocumentViaJavascriptUrl)
4852 {
4853 TestAccessInitialDocumentWebFrameClient webFrameClient;
4854 FrameTestHelpers::WebViewHelper webViewHelper;
4855 webViewHelper.initialize(true, &webFrameClient);
4856 runPendingTasks();
4857 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4858
4859 // Access the initial document from a javascript: URL.
4860 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Modified'))");
4861 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4862 }
4863
4864 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4865 #if OS(WIN)
TEST_F(WebFrameTest,DISABLED_DidAccessInitialDocumentBodyBeforeModalDialog)4866 TEST_F(WebFrameTest, DISABLED_DidAccessInitialDocumentBodyBeforeModalDialog)
4867 #else
4868 TEST_F(WebFrameTest, DidAccessInitialDocumentBodyBeforeModalDialog)
4869 #endif
4870 {
4871 // FIXME: Why is this local webViewClient needed instead of the default
4872 // WebViewHelper one? With out it there's some mysterious crash in the
4873 // WebViewHelper destructor.
4874 FrameTestHelpers::TestWebViewClient webViewClient;
4875 TestAccessInitialDocumentWebFrameClient webFrameClient;
4876 FrameTestHelpers::WebViewHelper webViewHelper;
4877 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4878 runPendingTasks();
4879 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4880
4881 // Create another window that will try to access it.
4882 FrameTestHelpers::WebViewHelper newWebViewHelper;
4883 WebView* newView = newWebViewHelper.initialize(true);
4884 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4885 runPendingTasks();
4886 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4887
4888 // Access the initial document by modifying the body. We normally set a
4889 // timer to notify the client.
4890 newView->mainFrame()->executeScript(
4891 WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4892 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4893
4894 // Make sure that a modal dialog forces us to notify right away.
4895 newView->mainFrame()->executeScript(
4896 WebScriptSource("window.opener.confirm('Modal');"));
4897 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4898
4899 // Ensure that we don't notify again later.
4900 runPendingTasks();
4901 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4902 }
4903
4904 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4905 #if OS(WIN)
TEST_F(WebFrameTest,DISABLED_DidWriteToInitialDocumentBeforeModalDialog)4906 TEST_F(WebFrameTest, DISABLED_DidWriteToInitialDocumentBeforeModalDialog)
4907 #else
4908 TEST_F(WebFrameTest, DidWriteToInitialDocumentBeforeModalDialog)
4909 #endif
4910 {
4911 // FIXME: Why is this local webViewClient needed instead of the default
4912 // WebViewHelper one? With out it there's some mysterious crash in the
4913 // WebViewHelper destructor.
4914 FrameTestHelpers::TestWebViewClient webViewClient;
4915 TestAccessInitialDocumentWebFrameClient webFrameClient;
4916 FrameTestHelpers::WebViewHelper webViewHelper;
4917 webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4918 runPendingTasks();
4919 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4920
4921 // Create another window that will try to access it.
4922 FrameTestHelpers::WebViewHelper newWebViewHelper;
4923 WebView* newView = newWebViewHelper.initialize(true);
4924 newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4925 runPendingTasks();
4926 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4927
4928 // Access the initial document with document.write, which moves us past the
4929 // initial empty document state of the state machine. We normally set a
4930 // timer to notify the client.
4931 newView->mainFrame()->executeScript(
4932 WebScriptSource("window.opener.document.write('Modified');"));
4933 EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4934
4935 // Make sure that a modal dialog forces us to notify right away.
4936 newView->mainFrame()->executeScript(
4937 WebScriptSource("window.opener.confirm('Modal');"));
4938 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4939
4940 // Ensure that we don't notify again later.
4941 runPendingTasks();
4942 EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4943 }
4944
4945 class TestMainFrameUserOrProgrammaticScrollFrameClient : public FrameTestHelpers::TestWebFrameClient {
4946 public:
TestMainFrameUserOrProgrammaticScrollFrameClient()4947 TestMainFrameUserOrProgrammaticScrollFrameClient() { reset(); }
reset()4948 void reset()
4949 {
4950 m_didScrollMainFrame = false;
4951 m_wasProgrammaticScroll = false;
4952 }
wasUserScroll() const4953 bool wasUserScroll() const { return m_didScrollMainFrame && !m_wasProgrammaticScroll; }
wasProgrammaticScroll() const4954 bool wasProgrammaticScroll() const { return m_didScrollMainFrame && m_wasProgrammaticScroll; }
4955
4956 // WebFrameClient:
didChangeScrollOffset(WebLocalFrame * frame)4957 virtual void didChangeScrollOffset(WebLocalFrame* frame) OVERRIDE
4958 {
4959 if (frame->parent())
4960 return;
4961 EXPECT_FALSE(m_didScrollMainFrame);
4962 FrameView* view = toWebLocalFrameImpl(frame)->frameView();
4963 // FrameView can be scrolled in FrameView::setFixedVisibleContentRect
4964 // which is called from LocalFrame::createView (before the frame is associated
4965 // with the the view).
4966 if (view) {
4967 m_didScrollMainFrame = true;
4968 m_wasProgrammaticScroll = view->inProgrammaticScroll();
4969 }
4970 }
4971 private:
4972 bool m_didScrollMainFrame;
4973 bool m_wasProgrammaticScroll;
4974 };
4975
TEST_F(WebFrameTest,CompositorScrollIsUserScrollLongPage)4976 TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage)
4977 {
4978 registerMockedHttpURLLoad("long_scroll.html");
4979 TestMainFrameUserOrProgrammaticScrollFrameClient client;
4980
4981 // Make sure we initialize to minimum scale, even if the window size
4982 // only becomes available after the load begins.
4983 FrameTestHelpers::WebViewHelper webViewHelper;
4984 webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, &client);
4985 webViewHelper.webView()->resize(WebSize(1000, 1000));
4986 webViewHelper.webView()->layout();
4987
4988 EXPECT_FALSE(client.wasUserScroll());
4989 EXPECT_FALSE(client.wasProgrammaticScroll());
4990
4991 // Do a compositor scroll, verify that this is counted as a user scroll.
4992 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(0, 1), 1.1f, 0);
4993 EXPECT_TRUE(client.wasUserScroll());
4994 client.reset();
4995
4996 EXPECT_FALSE(client.wasUserScroll());
4997 EXPECT_FALSE(client.wasProgrammaticScroll());
4998
4999 // The page scale 1.0f and scroll.
5000 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(0, 1), 1.0f, 0);
5001 EXPECT_TRUE(client.wasUserScroll());
5002 client.reset();
5003
5004 // No scroll event if there is no scroll delta.
5005 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.0f, 0);
5006 EXPECT_FALSE(client.wasUserScroll());
5007 EXPECT_FALSE(client.wasProgrammaticScroll());
5008 client.reset();
5009
5010 // Non zero page scale and scroll.
5011 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(9, 13), 0.6f, 0);
5012 EXPECT_TRUE(client.wasUserScroll());
5013 client.reset();
5014
5015 // Programmatic scroll.
5016 WebLocalFrameImpl* frameImpl = webViewHelper.webViewImpl()->mainFrameImpl();
5017 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5018 EXPECT_FALSE(client.wasUserScroll());
5019 EXPECT_TRUE(client.wasProgrammaticScroll());
5020 client.reset();
5021
5022 // Programmatic scroll to same offset. No scroll event should be generated.
5023 frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5024 EXPECT_FALSE(client.wasProgrammaticScroll());
5025 EXPECT_FALSE(client.wasUserScroll());
5026 client.reset();
5027 }
5028
TEST_F(WebFrameTest,CompositorScrollIsUserScrollShortPage)5029 TEST_F(WebFrameTest, CompositorScrollIsUserScrollShortPage)
5030 {
5031 registerMockedHttpURLLoad("short_scroll.html");
5032
5033 TestMainFrameUserOrProgrammaticScrollFrameClient client;
5034
5035 // Short page tests.
5036 FrameTestHelpers::WebViewHelper webViewHelper;
5037 webViewHelper.initializeAndLoad(m_baseURL + "short_scroll.html", true, &client);
5038
5039 webViewHelper.webView()->resize(WebSize(1000, 1000));
5040 webViewHelper.webView()->layout();
5041
5042 EXPECT_FALSE(client.wasUserScroll());
5043 EXPECT_FALSE(client.wasProgrammaticScroll());
5044
5045 // Non zero page scale and scroll.
5046 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(9, 13), 2.0f, 0);
5047 EXPECT_FALSE(client.wasProgrammaticScroll());
5048 EXPECT_TRUE(client.wasUserScroll());
5049 client.reset();
5050 }
5051
TEST_F(WebFrameTest,FirstPartyForCookiesForRedirect)5052 TEST_F(WebFrameTest, FirstPartyForCookiesForRedirect)
5053 {
5054 WTF::String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
5055 filePath.append("/Source/web/tests/data/first_party.html");
5056
5057 WebURL testURL(toKURL("http://www.test.com/first_party_redirect.html"));
5058 char redirect[] = "http://www.test.com/first_party.html";
5059 WebURL redirectURL(toKURL(redirect));
5060 WebURLResponse redirectResponse;
5061 redirectResponse.initialize();
5062 redirectResponse.setMIMEType("text/html");
5063 redirectResponse.setHTTPStatusCode(302);
5064 redirectResponse.setHTTPHeaderField("Location", redirect);
5065 Platform::current()->unitTestSupport()->registerMockedURL(testURL, redirectResponse, filePath);
5066
5067 WebURLResponse finalResponse;
5068 finalResponse.initialize();
5069 finalResponse.setMIMEType("text/html");
5070 Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, finalResponse, filePath);
5071
5072 FrameTestHelpers::WebViewHelper webViewHelper;
5073 webViewHelper.initializeAndLoad(m_baseURL + "first_party_redirect.html", true);
5074 EXPECT_TRUE(webViewHelper.webView()->mainFrame()->document().firstPartyForCookies() == redirectURL);
5075 }
5076
5077 class TestNavigationPolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5078 public:
5079
didNavigateWithinPage(WebLocalFrame *,const WebHistoryItem &,WebHistoryCommitType)5080 virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
5081 {
5082 EXPECT_TRUE(false);
5083 }
5084 };
5085
TEST_F(WebFrameTest,SimulateFragmentAnchorMiddleClick)5086 TEST_F(WebFrameTest, SimulateFragmentAnchorMiddleClick)
5087 {
5088 registerMockedHttpURLLoad("fragment_middle_click.html");
5089 TestNavigationPolicyWebFrameClient client;
5090 FrameTestHelpers::WebViewHelper webViewHelper;
5091 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true, &client);
5092
5093 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5094 KURL destination = document->url();
5095 destination.setFragmentIdentifier("test");
5096
5097 RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5098 document->domWindow(), 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 1, nullptr, nullptr);
5099 FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5100 frameRequest.setTriggeringEvent(event);
5101 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5102 }
5103
5104 class TestNewWindowWebViewClient : public FrameTestHelpers::TestWebViewClient {
5105 public:
createView(WebLocalFrame *,const WebURLRequest &,const WebWindowFeatures &,const WebString &,WebNavigationPolicy,bool)5106 virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&,
5107 const WebString&, WebNavigationPolicy, bool) OVERRIDE
5108 {
5109 EXPECT_TRUE(false);
5110 return 0;
5111 }
5112 };
5113
5114 class TestNewWindowWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5115 public:
TestNewWindowWebFrameClient()5116 TestNewWindowWebFrameClient()
5117 : m_decidePolicyCallCount(0)
5118 {
5119 }
5120
decidePolicyForNavigation(const NavigationPolicyInfo & info)5121 virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE
5122 {
5123 m_decidePolicyCallCount++;
5124 return info.defaultPolicy;
5125 }
5126
decidePolicyCallCount() const5127 int decidePolicyCallCount() const { return m_decidePolicyCallCount; }
5128
5129 private:
5130 int m_decidePolicyCallCount;
5131 };
5132
TEST_F(WebFrameTest,ModifiedClickNewWindow)5133 TEST_F(WebFrameTest, ModifiedClickNewWindow)
5134 {
5135 registerMockedHttpURLLoad("ctrl_click.html");
5136 registerMockedHttpURLLoad("hello_world.html");
5137 TestNewWindowWebViewClient webViewClient;
5138 TestNewWindowWebFrameClient webFrameClient;
5139 FrameTestHelpers::WebViewHelper webViewHelper;
5140 webViewHelper.initializeAndLoad(m_baseURL + "ctrl_click.html", true, &webFrameClient, &webViewClient);
5141
5142 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5143 KURL destination = toKURL(m_baseURL + "hello_world.html");
5144
5145 // ctrl+click event
5146 RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5147 document->domWindow(), 0, 0, 0, 0, 0, 0, 0, true, false, false, false, 0, nullptr, nullptr);
5148 FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5149 frameRequest.setTriggeringEvent(event);
5150 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5151 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5152 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5153
5154 // decidePolicyForNavigation should be called both for the original request and the ctrl+click.
5155 EXPECT_EQ(2, webFrameClient.decidePolicyCallCount());
5156 }
5157
TEST_F(WebFrameTest,BackToReload)5158 TEST_F(WebFrameTest, BackToReload)
5159 {
5160 registerMockedHttpURLLoad("fragment_middle_click.html");
5161 FrameTestHelpers::WebViewHelper webViewHelper;
5162 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5163 WebFrame* frame = webViewHelper.webView()->mainFrame();
5164 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5165 RefPtr<HistoryItem> firstItem = mainFrameLoader.currentItem();
5166 EXPECT_TRUE(firstItem);
5167
5168 registerMockedHttpURLLoad("white-1x1.png");
5169 FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5170 EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5171
5172 FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem.get()), WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5173 EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5174
5175 FrameTestHelpers::reloadFrame(frame);
5176 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5177 }
5178
TEST_F(WebFrameTest,BackDuringChildFrameReload)5179 TEST_F(WebFrameTest, BackDuringChildFrameReload)
5180 {
5181 registerMockedHttpURLLoad("page_with_blank_iframe.html");
5182 FrameTestHelpers::WebViewHelper webViewHelper;
5183 webViewHelper.initializeAndLoad(m_baseURL + "page_with_blank_iframe.html", true);
5184 WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
5185 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5186 WebFrame* childFrame = mainFrame->firstChild();
5187 ASSERT_TRUE(childFrame);
5188
5189 // Start a history navigation, then have a different frame commit a navigation.
5190 // In this case, reload an about:blank frame, which will commit synchronously.
5191 // After the history navigation completes, both the appropriate document url and
5192 // the current history item should reflect the history navigation.
5193 registerMockedHttpURLLoad("white-1x1.png");
5194 WebHistoryItem item;
5195 item.initialize();
5196 WebURL historyURL(toKURL(m_baseURL + "white-1x1.png"));
5197 item.setURLString(historyURL.string());
5198 mainFrame->loadHistoryItem(item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5199
5200 FrameTestHelpers::reloadFrame(childFrame);
5201 EXPECT_EQ(item.urlString(), mainFrame->document().url().string());
5202 EXPECT_EQ(item.urlString(), WebString(mainFrameLoader.currentItem()->urlString()));
5203 }
5204
TEST_F(WebFrameTest,ReloadPost)5205 TEST_F(WebFrameTest, ReloadPost)
5206 {
5207 registerMockedHttpURLLoad("reload_post.html");
5208 FrameTestHelpers::WebViewHelper webViewHelper;
5209 webViewHelper.initializeAndLoad(m_baseURL + "reload_post.html", true);
5210 WebFrame* frame = webViewHelper.webView()->mainFrame();
5211
5212 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.forms[0].submit()");
5213 // Pump requests one more time after the javascript URL has executed to
5214 // trigger the actual POST load request.
5215 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5216 EXPECT_EQ(WebString::fromUTF8("POST"), frame->dataSource()->request().httpMethod());
5217
5218 FrameTestHelpers::reloadFrame(frame);
5219 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5220 EXPECT_EQ(WebNavigationTypeFormResubmitted, frame->dataSource()->navigationType());
5221 }
5222
TEST_F(WebFrameTest,LoadHistoryItemReload)5223 TEST_F(WebFrameTest, LoadHistoryItemReload)
5224 {
5225 registerMockedHttpURLLoad("fragment_middle_click.html");
5226 FrameTestHelpers::WebViewHelper webViewHelper;
5227 webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5228 WebFrame* frame = webViewHelper.webView()->mainFrame();
5229 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5230 RefPtr<HistoryItem> firstItem = mainFrameLoader.currentItem();
5231 EXPECT_TRUE(firstItem);
5232
5233 registerMockedHttpURLLoad("white-1x1.png");
5234 FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5235 EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5236
5237 // Cache policy overrides should take.
5238 FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem), WebHistoryDifferentDocumentLoad, WebURLRequest::ReloadIgnoringCacheData);
5239 EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5240 EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5241 }
5242
5243
5244 class TestCachePolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5245 public:
TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient * parentClient)5246 explicit TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient* parentClient)
5247 : m_parentClient(parentClient)
5248 , m_policy(WebURLRequest::UseProtocolCachePolicy)
5249 , m_childClient(0)
5250 , m_willSendRequestCallCount(0)
5251 , m_childFrameCreationCount(0)
5252 {
5253 }
5254
setChildWebFrameClient(TestCachePolicyWebFrameClient * client)5255 void setChildWebFrameClient(TestCachePolicyWebFrameClient* client) { m_childClient = client; }
cachePolicy() const5256 WebURLRequest::CachePolicy cachePolicy() const { return m_policy; }
willSendRequestCallCount() const5257 int willSendRequestCallCount() const { return m_willSendRequestCallCount; }
childFrameCreationCount() const5258 int childFrameCreationCount() const { return m_childFrameCreationCount; }
5259
createChildFrame(WebLocalFrame * parent,const WebString &)5260 virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString&)
5261 {
5262 ASSERT(m_childClient);
5263 m_childFrameCreationCount++;
5264 WebFrame* frame = WebLocalFrame::create(m_childClient);
5265 parent->appendChild(frame);
5266 return frame;
5267 }
5268
didStartLoading(bool toDifferentDocument)5269 virtual void didStartLoading(bool toDifferentDocument)
5270 {
5271 if (m_parentClient) {
5272 m_parentClient->didStartLoading(toDifferentDocument);
5273 return;
5274 }
5275 TestWebFrameClient::didStartLoading(toDifferentDocument);
5276 }
5277
didStopLoading()5278 virtual void didStopLoading()
5279 {
5280 if (m_parentClient) {
5281 m_parentClient->didStopLoading();
5282 return;
5283 }
5284 TestWebFrameClient::didStopLoading();
5285 }
5286
willSendRequest(WebLocalFrame * frame,unsigned,WebURLRequest & request,const WebURLResponse &)5287 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) OVERRIDE
5288 {
5289 m_policy = request.cachePolicy();
5290 m_willSendRequestCallCount++;
5291 }
5292
5293 private:
5294 TestCachePolicyWebFrameClient* m_parentClient;
5295
5296 WebURLRequest::CachePolicy m_policy;
5297 TestCachePolicyWebFrameClient* m_childClient;
5298 int m_willSendRequestCallCount;
5299 int m_childFrameCreationCount;
5300 };
5301
TEST_F(WebFrameTest,ReloadIframe)5302 TEST_F(WebFrameTest, ReloadIframe)
5303 {
5304 registerMockedHttpURLLoad("iframe_reload.html");
5305 registerMockedHttpURLLoad("visible_iframe.html");
5306 TestCachePolicyWebFrameClient mainClient(0);
5307 TestCachePolicyWebFrameClient childClient(&mainClient);
5308 mainClient.setChildWebFrameClient(&childClient);
5309
5310 FrameTestHelpers::WebViewHelper webViewHelper;
5311 webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, &mainClient);
5312
5313 WebLocalFrameImpl* mainFrame = webViewHelper.webViewImpl()->mainFrameImpl();
5314 RefPtrWillBeRawPtr<WebLocalFrameImpl> childFrame = toWebLocalFrameImpl(mainFrame->firstChild());
5315 ASSERT_EQ(childFrame->client(), &childClient);
5316 EXPECT_EQ(mainClient.childFrameCreationCount(), 1);
5317 EXPECT_EQ(childClient.willSendRequestCallCount(), 1);
5318 EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::UseProtocolCachePolicy);
5319
5320 FrameTestHelpers::reloadFrame(mainFrame);
5321
5322 // A new WebFrame should have been created, but the child WebFrameClient should be reused.
5323 ASSERT_NE(childFrame, toWebLocalFrameImpl(mainFrame->firstChild()));
5324 ASSERT_EQ(toWebLocalFrameImpl(mainFrame->firstChild())->client(), &childClient);
5325
5326 EXPECT_EQ(mainClient.childFrameCreationCount(), 2);
5327 EXPECT_EQ(childClient.willSendRequestCallCount(), 2);
5328 EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::ReloadIgnoringCacheData);
5329 }
5330
5331 class TestSameDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5332 public:
TestSameDocumentWebFrameClient()5333 TestSameDocumentWebFrameClient()
5334 : m_frameLoadTypeSameSeen(false)
5335 {
5336 }
5337
willSendRequest(WebLocalFrame * frame,unsigned,WebURLRequest &,const WebURLResponse &)5338 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest&, const WebURLResponse&)
5339 {
5340 if (toWebLocalFrameImpl(frame)->frame()->loader().loadType() == FrameLoadTypeSame)
5341 m_frameLoadTypeSameSeen = true;
5342 }
5343
frameLoadTypeSameSeen() const5344 bool frameLoadTypeSameSeen() const { return m_frameLoadTypeSameSeen; }
5345
5346 private:
5347 bool m_frameLoadTypeSameSeen;
5348 };
5349
TEST_F(WebFrameTest,NavigateToSame)5350 TEST_F(WebFrameTest, NavigateToSame)
5351 {
5352 registerMockedHttpURLLoad("navigate_to_same.html");
5353 TestSameDocumentWebFrameClient client;
5354 FrameTestHelpers::WebViewHelper webViewHelper;
5355 webViewHelper.initializeAndLoad(m_baseURL + "navigate_to_same.html", true, &client);
5356 EXPECT_FALSE(client.frameLoadTypeSameSeen());
5357
5358 FrameLoadRequest frameRequest(0, ResourceRequest(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document()->url()));
5359 toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5360 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5361
5362 EXPECT_TRUE(client.frameLoadTypeSameSeen());
5363 }
5364
5365 class TestSameDocumentWithImageWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5366 public:
TestSameDocumentWithImageWebFrameClient()5367 TestSameDocumentWithImageWebFrameClient()
5368 : m_numOfImageRequests(0)
5369 {
5370 }
5371
willSendRequest(WebLocalFrame * frame,unsigned,WebURLRequest & request,const WebURLResponse &)5372 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&)
5373 {
5374 if (request.requestContext() == WebURLRequest::RequestContextImage) {
5375 m_numOfImageRequests++;
5376 EXPECT_EQ(WebURLRequest::UseProtocolCachePolicy, request.cachePolicy());
5377 }
5378 }
5379
numOfImageRequests() const5380 int numOfImageRequests() const { return m_numOfImageRequests; }
5381
5382 private:
5383 int m_numOfImageRequests;
5384 };
5385
TEST_F(WebFrameTest,NavigateToSameNoConditionalRequestForSubresource)5386 TEST_F(WebFrameTest, NavigateToSameNoConditionalRequestForSubresource)
5387 {
5388 registerMockedHttpURLLoad("foo_with_image.html");
5389 registerMockedHttpURLLoad("white-1x1.png");
5390 TestSameDocumentWithImageWebFrameClient client;
5391 FrameTestHelpers::WebViewHelper webViewHelper;
5392 webViewHelper.initializeAndLoad(m_baseURL + "foo_with_image.html", true, &client, 0, &configureLoadsImagesAutomatically);
5393
5394 WebCache::clear();
5395 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "foo_with_image.html");
5396
5397 EXPECT_EQ(client.numOfImageRequests(), 2);
5398 }
5399
TEST_F(WebFrameTest,WebNodeImageContents)5400 TEST_F(WebFrameTest, WebNodeImageContents)
5401 {
5402 FrameTestHelpers::WebViewHelper webViewHelper;
5403 webViewHelper.initializeAndLoad("about:blank", true);
5404 WebFrame* frame = webViewHelper.webView()->mainFrame();
5405
5406 static const char bluePNG[] = "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYV2NkYPj/n4EIwDiqEF8oUT94AFIQE/cCn90IAAAAAElFTkSuQmCC\">";
5407
5408 // Load up the image and test that we can extract the contents.
5409 KURL testURL = toKURL("about:blank");
5410 FrameTestHelpers::loadHTMLString(frame, bluePNG, testURL);
5411
5412 WebNode node = frame->document().body().firstChild();
5413 EXPECT_TRUE(node.isElementNode());
5414 WebElement element = node.to<WebElement>();
5415 WebImage image = element.imageContents();
5416 ASSERT_FALSE(image.isNull());
5417 EXPECT_EQ(image.size().width, 10);
5418 EXPECT_EQ(image.size().height, 10);
5419 // FIXME: The rest of this test is disabled since the ImageDecodeCache state may be inconsistent when this test runs.
5420 // crbug.com/266088
5421 // SkBitmap bitmap = image.getSkBitmap();
5422 // SkAutoLockPixels locker(bitmap);
5423 // EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorBLUE);
5424 }
5425
5426 class TestStartStopCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5427 public:
TestStartStopCallbackWebFrameClient()5428 TestStartStopCallbackWebFrameClient()
5429 : m_startLoadingCount(0)
5430 , m_stopLoadingCount(0)
5431 , m_differentDocumentStartCount(0)
5432 {
5433 }
5434
didStartLoading(bool toDifferentDocument)5435 virtual void didStartLoading(bool toDifferentDocument) OVERRIDE
5436 {
5437 TestWebFrameClient::didStartLoading(toDifferentDocument);
5438 m_startLoadingCount++;
5439 if (toDifferentDocument)
5440 m_differentDocumentStartCount++;
5441 }
5442
didStopLoading()5443 virtual void didStopLoading() OVERRIDE
5444 {
5445 TestWebFrameClient::didStopLoading();
5446 m_stopLoadingCount++;
5447 }
5448
startLoadingCount() const5449 int startLoadingCount() const { return m_startLoadingCount; }
stopLoadingCount() const5450 int stopLoadingCount() const { return m_stopLoadingCount; }
differentDocumentStartCount() const5451 int differentDocumentStartCount() const { return m_differentDocumentStartCount; }
5452
5453 private:
5454 int m_startLoadingCount;
5455 int m_stopLoadingCount;
5456 int m_differentDocumentStartCount;
5457 };
5458
TEST_F(WebFrameTest,PushStateStartsAndStops)5459 TEST_F(WebFrameTest, PushStateStartsAndStops)
5460 {
5461 registerMockedHttpURLLoad("push_state.html");
5462 TestStartStopCallbackWebFrameClient client;
5463 FrameTestHelpers::WebViewHelper webViewHelper;
5464 webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5465
5466 EXPECT_EQ(client.startLoadingCount(), 2);
5467 EXPECT_EQ(client.stopLoadingCount(), 2);
5468 EXPECT_EQ(client.differentDocumentStartCount(), 1);
5469 }
5470
5471 class TestDidNavigateCommitTypeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5472 public:
TestDidNavigateCommitTypeWebFrameClient()5473 TestDidNavigateCommitTypeWebFrameClient()
5474 : m_lastCommitType(WebHistoryInertCommit)
5475 {
5476 }
5477
didNavigateWithinPage(WebLocalFrame *,const WebHistoryItem &,WebHistoryCommitType type)5478 virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType type) OVERRIDE
5479 {
5480 m_lastCommitType = type;
5481 }
5482
lastCommitType() const5483 WebHistoryCommitType lastCommitType() const { return m_lastCommitType; }
5484
5485 private:
5486 WebHistoryCommitType m_lastCommitType;
5487 };
5488
TEST_F(WebFrameTest,SameDocumentHistoryNavigationCommitType)5489 TEST_F(WebFrameTest, SameDocumentHistoryNavigationCommitType)
5490 {
5491 registerMockedHttpURLLoad("push_state.html");
5492 TestDidNavigateCommitTypeWebFrameClient client;
5493 FrameTestHelpers::WebViewHelper webViewHelper;
5494 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5495 RefPtr<HistoryItem> item = toLocalFrame(webViewImpl->page()->mainFrame())->loader().currentItem();
5496 runPendingTasks();
5497
5498 toLocalFrame(webViewImpl->page()->mainFrame())->loader().loadHistoryItem(item.get(), HistorySameDocumentLoad);
5499 EXPECT_EQ(WebBackForwardCommit, client.lastCommitType());
5500 }
5501
5502 class TestHistoryWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5503 public:
TestHistoryWebFrameClient()5504 TestHistoryWebFrameClient()
5505 {
5506 m_replacesCurrentHistoryItem = false;
5507 m_frame = 0;
5508 }
5509
didStartProvisionalLoad(WebLocalFrame * frame,bool isTransitionNavigation)5510 void didStartProvisionalLoad(WebLocalFrame* frame, bool isTransitionNavigation)
5511 {
5512 WebDataSource* ds = frame->provisionalDataSource();
5513 m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem();
5514 m_frame = frame;
5515 }
5516
replacesCurrentHistoryItem()5517 bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; }
frame()5518 WebFrame* frame() { return m_frame; }
5519
5520 private:
5521 bool m_replacesCurrentHistoryItem;
5522 WebFrame* m_frame;
5523 };
5524
5525 // Test which ensures that the first navigation in a subframe will always
5526 // result in history entry being replaced and not a new one added.
TEST_F(WebFrameTest,DISABLED_FirstFrameNavigationReplacesHistory)5527 TEST_F(WebFrameTest, DISABLED_FirstFrameNavigationReplacesHistory)
5528 {
5529 registerMockedHttpURLLoad("history.html");
5530 registerMockedHttpURLLoad("find.html");
5531
5532 FrameTestHelpers::WebViewHelper webViewHelper;
5533 TestHistoryWebFrameClient client;
5534 webViewHelper.initializeAndLoad("about:blank", true, &client);
5535 EXPECT_TRUE(client.replacesCurrentHistoryItem());
5536
5537 WebFrame* frame = webViewHelper.webView()->mainFrame();
5538
5539 FrameTestHelpers::loadFrame(frame,
5540 "javascript:document.body.appendChild(document.createElement('iframe'))");
5541 WebFrame* iframe = frame->firstChild();
5542 EXPECT_EQ(client.frame(), iframe);
5543 EXPECT_TRUE(client.replacesCurrentHistoryItem());
5544
5545 FrameTestHelpers::loadFrame(frame,
5546 "javascript:window.frames[0].location.assign('" + m_baseURL + "history.html')");
5547 EXPECT_EQ(client.frame(), iframe);
5548 EXPECT_TRUE(client.replacesCurrentHistoryItem());
5549
5550 FrameTestHelpers::loadFrame(frame,
5551 "javascript:window.frames[0].location.assign('" + m_baseURL + "find.html')");
5552 EXPECT_EQ(client.frame(), iframe);
5553 EXPECT_FALSE(client.replacesCurrentHistoryItem());
5554
5555 // Repeat the test, but start out the iframe with initial URL, which is not
5556 // "about:blank".
5557 FrameTestHelpers::loadFrame(frame,
5558 "javascript:var f = document.createElement('iframe'); "
5559 "f.src = '" + m_baseURL + "history.html';"
5560 "document.body.appendChild(f)");
5561
5562 iframe = frame->firstChild()->nextSibling();
5563 EXPECT_EQ(client.frame(), iframe);
5564 EXPECT_TRUE(client.replacesCurrentHistoryItem());
5565
5566 FrameTestHelpers::loadFrame(frame,
5567 "javascript:window.frames[1].location.assign('" + m_baseURL + "find.html')");
5568 EXPECT_EQ(client.frame(), iframe);
5569 EXPECT_FALSE(client.replacesCurrentHistoryItem());
5570 }
5571
5572 // Test verifies that layout will change a layer's scrollable attibutes
TEST_F(WebFrameTest,overflowHiddenRewrite)5573 TEST_F(WebFrameTest, overflowHiddenRewrite)
5574 {
5575 registerMockedHttpURLLoad("non-scrollable.html");
5576 TestMainFrameUserOrProgrammaticScrollFrameClient client;
5577 OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
5578 FrameTestHelpers::WebViewHelper webViewHelper;
5579 webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
5580
5581 webViewHelper.webView()->resize(WebSize(100, 100));
5582 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "non-scrollable.html");
5583
5584 RenderLayerCompositor* compositor = webViewHelper.webViewImpl()->compositor();
5585 ASSERT_TRUE(compositor->scrollLayer());
5586
5587 // Verify that the WebLayer is not scrollable initially.
5588 GraphicsLayer* scrollLayer = compositor->scrollLayer();
5589 WebLayer* webScrollLayer = scrollLayer->platformLayer();
5590 ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
5591 ASSERT_FALSE(webScrollLayer->userScrollableVertical());
5592
5593 // Call javascript to make the layer scrollable, and verify it.
5594 WebLocalFrameImpl* frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
5595 frame->executeScript(WebScriptSource("allowScroll();"));
5596 webViewHelper.webView()->layout();
5597 ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
5598 ASSERT_TRUE(webScrollLayer->userScrollableVertical());
5599 }
5600
5601 // Test that currentHistoryItem reflects the current page, not the provisional load.
TEST_F(WebFrameTest,CurrentHistoryItem)5602 TEST_F(WebFrameTest, CurrentHistoryItem)
5603 {
5604 registerMockedHttpURLLoad("fixed_layout.html");
5605 std::string url = m_baseURL + "fixed_layout.html";
5606
5607 FrameTestHelpers::WebViewHelper webViewHelper;
5608 webViewHelper.initialize();
5609 WebFrame* frame = webViewHelper.webView()->mainFrame();
5610 const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5611 WebURLRequest request;
5612 request.initialize();
5613 request.setURL(toKURL(url));
5614 frame->loadRequest(request);
5615
5616 // Before commit, there is no history item.
5617 EXPECT_FALSE(mainFrameLoader.currentItem());
5618
5619 FrameTestHelpers::pumpPendingRequestsDoNotUse(frame);
5620
5621 // After commit, there is.
5622 HistoryItem* item = mainFrameLoader.currentItem();
5623 ASSERT_TRUE(item);
5624 EXPECT_EQ(WTF::String(url.data()), item->urlString());
5625 }
5626
5627 class FailCreateChildFrame : public FrameTestHelpers::TestWebFrameClient {
5628 public:
FailCreateChildFrame()5629 FailCreateChildFrame() : m_callCount(0) { }
5630
createChildFrame(WebLocalFrame * parent,const WebString & frameName)5631 virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE
5632 {
5633 ++m_callCount;
5634 return 0;
5635 }
5636
callCount() const5637 int callCount() const { return m_callCount; }
5638
5639 private:
5640 int m_callCount;
5641 };
5642
5643 // Test that we don't crash if WebFrameClient::createChildFrame() fails.
TEST_F(WebFrameTest,CreateChildFrameFailure)5644 TEST_F(WebFrameTest, CreateChildFrameFailure)
5645 {
5646 registerMockedHttpURLLoad("create_child_frame_fail.html");
5647 FailCreateChildFrame client;
5648 FrameTestHelpers::WebViewHelper webViewHelper;
5649 webViewHelper.initializeAndLoad(m_baseURL + "create_child_frame_fail.html", true, &client);
5650
5651 EXPECT_EQ(1, client.callCount());
5652 }
5653
TEST_F(WebFrameTest,fixedPositionInFixedViewport)5654 TEST_F(WebFrameTest, fixedPositionInFixedViewport)
5655 {
5656 UseMockScrollbarSettings mockScrollbarSettings;
5657 registerMockedHttpURLLoad("fixed-position-in-fixed-viewport.html");
5658 FrameTestHelpers::WebViewHelper webViewHelper;
5659 webViewHelper.initializeAndLoad(m_baseURL + "fixed-position-in-fixed-viewport.html", true, 0, 0, enableViewportSettings);
5660
5661 WebView* webView = webViewHelper.webView();
5662 webView->resize(WebSize(100, 100));
5663 webView->layout();
5664
5665 Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5666 Element* bottomFixed = document->getElementById("bottom-fixed");
5667 Element* topBottomFixed = document->getElementById("top-bottom-fixed");
5668 Element* rightFixed = document->getElementById("right-fixed");
5669 Element* leftRightFixed = document->getElementById("left-right-fixed");
5670
5671 webView->resize(WebSize(100, 200));
5672 webView->layout();
5673 EXPECT_EQ(200, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5674 EXPECT_EQ(200, topBottomFixed->offsetHeight());
5675
5676 webView->settings()->setMainFrameResizesAreOrientationChanges(false);
5677 webView->resize(WebSize(200, 200));
5678 webView->layout();
5679 EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5680 EXPECT_EQ(200, leftRightFixed->offsetWidth());
5681
5682 webView->settings()->setMainFrameResizesAreOrientationChanges(true);
5683 // Will scale the page by 1.5.
5684 webView->resize(WebSize(300, 330));
5685 webView->layout();
5686 EXPECT_EQ(220, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5687 EXPECT_EQ(220, topBottomFixed->offsetHeight());
5688 EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5689 EXPECT_EQ(200, leftRightFixed->offsetWidth());
5690 }
5691
TEST_F(WebFrameTest,FrameViewSetFrameRect)5692 TEST_F(WebFrameTest, FrameViewSetFrameRect)
5693 {
5694 FrameTestHelpers::WebViewHelper webViewHelper;
5695 webViewHelper.initializeAndLoad("about:blank");
5696
5697 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
5698 frameView->setFrameRect(IntRect(0, 0, 200, 200));
5699 EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), frameView->frameRect());
5700 frameView->setFrameRect(IntRect(100, 100, 200, 200));
5701 EXPECT_RECT_EQ(IntRect(100, 100, 200, 200), frameView->frameRect());
5702 }
5703
5704 // FIXME(bokan) Renable once Chromium-side of patch lands
TEST_F(WebFrameTest,DISABLED_FrameViewScrollAccountsForTopControls)5705 TEST_F(WebFrameTest, DISABLED_FrameViewScrollAccountsForTopControls)
5706 {
5707 FrameTestHelpers::WebViewHelper webViewHelper;
5708 webViewHelper.initializeAndLoad("about:blank");
5709
5710 WebViewImpl* webView = webViewHelper.webViewImpl();
5711 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
5712
5713 webView->setTopControlsLayoutHeight(0);
5714 webView->resize(WebSize(100, 100));
5715 webView->setPageScaleFactor(2.0f);
5716 webView->layout();
5717
5718 webView->setMainFrameScrollOffset(WebPoint(20, 100));
5719 EXPECT_EQ_POINT(IntPoint(20, 50), IntPoint(frameView->scrollOffset()));
5720
5721 // Simulate the top controls showing by 20px, thus shrinking the viewport
5722 // and allowing it to scroll an additional 10px (since we're 2X zoomed).
5723 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 20.0f);
5724 EXPECT_EQ_POINT(IntPoint(50, 60), frameView->maximumScrollPosition());
5725
5726 // Show more, make sure the scroll actually gets clamped. Horizontal
5727 // direction shouldn't be affected.
5728 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 20.0f);
5729 webView->setMainFrameScrollOffset(WebPoint(100, 100));
5730 EXPECT_EQ_POINT(IntPoint(50, 70), IntPoint(frameView->scrollOffset()));
5731
5732 // Hide until there's 10px showing.
5733 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, -30.0f);
5734 EXPECT_EQ_POINT(IntPoint(50, 55), frameView->maximumScrollPosition());
5735
5736 // Simulate a RenderWidget::resize. The frame is resized to accomodate
5737 // the top controls and Blink's view of the top controls matches that of
5738 // the CC
5739 webView->setTopControlsLayoutHeight(10.0f);
5740 webView->resize(WebSize(100, 90));
5741 webView->layout();
5742 EXPECT_EQ_POINT(IntPoint(50, 45), frameView->maximumScrollPosition());
5743
5744 // Now simulate hiding.
5745 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, -10.0f);
5746 EXPECT_EQ_POINT(IntPoint(50, 40), frameView->maximumScrollPosition());
5747
5748 // Reset to original state: 100px widget height, top controls fully hidden.
5749 webView->setTopControlsLayoutHeight(0.0f);
5750 webView->resize(WebSize(100, 100));
5751 webView->layout();
5752 EXPECT_EQ_POINT(IntPoint(50, 50), frameView->maximumScrollPosition());
5753
5754 // Show the top controls by just 1px, since we're zoomed in to 2X, that
5755 // should allow an extra 0.5px of scrolling, but since we quantize to ints
5756 // it should clamp such that we don't show anything outside bounds.
5757 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 1.0f);
5758 EXPECT_EQ_POINT(IntPoint(50, 50), frameView->maximumScrollPosition());
5759
5760 webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 2.0f);
5761 EXPECT_EQ_POINT(IntPoint(50, 51), frameView->maximumScrollPosition());
5762
5763
5764 }
5765
TEST_F(WebFrameTest,FullscreenLayerNonScrollable)5766 TEST_F(WebFrameTest, FullscreenLayerNonScrollable)
5767 {
5768 FakeCompositingWebViewClient client;
5769 registerMockedHttpURLLoad("fullscreen_div.html");
5770 FrameTestHelpers::WebViewHelper webViewHelper;
5771 int viewportWidth = 640;
5772 int viewportHeight = 480;
5773 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5774 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5775 webViewImpl->layout();
5776
5777 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5778 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5779 Element* divFullscreen = document->getElementById("div1");
5780 Fullscreen::from(*document).requestFullscreen(*divFullscreen, Fullscreen::PrefixedRequest);
5781 webViewImpl->didEnterFullScreen();
5782 webViewImpl->layout();
5783
5784 // Verify that the main frame bounds are empty.
5785 ASSERT_TRUE(Fullscreen::isFullScreen(*document));
5786 WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5787 ASSERT_EQ(WebSize(), webScrollLayer->bounds());
5788
5789 // Verify that the main frame is scrollable upon exiting fullscreen.
5790 webViewImpl->didExitFullScreen();
5791 webViewImpl->layout();
5792 ASSERT_FALSE(Fullscreen::isFullScreen(*document));
5793 webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5794 ASSERT_NE(WebSize(), webScrollLayer->bounds());
5795 }
5796
TEST_F(WebFrameTest,FullscreenMainFrameScrollable)5797 TEST_F(WebFrameTest, FullscreenMainFrameScrollable)
5798 {
5799 FakeCompositingWebViewClient client;
5800 registerMockedHttpURLLoad("fullscreen_div.html");
5801 FrameTestHelpers::WebViewHelper webViewHelper;
5802 int viewportWidth = 640;
5803 int viewportHeight = 480;
5804 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5805 webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5806 webViewImpl->layout();
5807
5808 Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5809 UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5810 Fullscreen::from(*document).requestFullscreen(*document->documentElement(), Fullscreen::PrefixedRequest);
5811 webViewImpl->didEnterFullScreen();
5812 webViewImpl->layout();
5813
5814 // Verify that the main frame is still scrollable.
5815 ASSERT_TRUE(Fullscreen::isFullScreen(*document));
5816 WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5817 ASSERT_TRUE(webScrollLayer->scrollable());
5818 }
5819
TEST_F(WebFrameTest,RenderBlockPercentHeightDescendants)5820 TEST_F(WebFrameTest, RenderBlockPercentHeightDescendants)
5821 {
5822 registerMockedHttpURLLoad("percent-height-descendants.html");
5823 FrameTestHelpers::WebViewHelper webViewHelper;
5824 webViewHelper.initializeAndLoad(m_baseURL + "percent-height-descendants.html");
5825
5826 WebView* webView = webViewHelper.webView();
5827 webView->resize(WebSize(800, 800));
5828 webView->layout();
5829
5830 Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5831 RenderBlock* container = toRenderBlock(document->getElementById("container")->renderer());
5832 RenderBox* percentHeightInAnonymous = toRenderBox(document->getElementById("percent-height-in-anonymous")->renderer());
5833 RenderBox* percentHeightDirectChild = toRenderBox(document->getElementById("percent-height-direct-child")->renderer());
5834
5835 EXPECT_TRUE(RenderBlock::hasPercentHeightDescendant(percentHeightInAnonymous));
5836 EXPECT_TRUE(RenderBlock::hasPercentHeightDescendant(percentHeightDirectChild));
5837
5838 ASSERT_TRUE(container->percentHeightDescendants());
5839 ASSERT_TRUE(container->hasPercentHeightDescendants());
5840 EXPECT_EQ(2U, container->percentHeightDescendants()->size());
5841 EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightInAnonymous));
5842 EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightDirectChild));
5843
5844 RenderBlock* anonymousBlock = percentHeightInAnonymous->containingBlock();
5845 EXPECT_TRUE(anonymousBlock->isAnonymous());
5846 EXPECT_FALSE(anonymousBlock->hasPercentHeightDescendants());
5847 }
5848
TEST_F(WebFrameTest,HasVisibleContentOnVisibleFrames)5849 TEST_F(WebFrameTest, HasVisibleContentOnVisibleFrames)
5850 {
5851 registerMockedHttpURLLoad("visible_frames.html");
5852 FrameTestHelpers::WebViewHelper webViewHelper;
5853 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "visible_frames.html");
5854 for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5855 EXPECT_TRUE(frame->hasVisibleContent());
5856 }
5857 }
5858
TEST_F(WebFrameTest,HasVisibleContentOnHiddenFrames)5859 TEST_F(WebFrameTest, HasVisibleContentOnHiddenFrames)
5860 {
5861 registerMockedHttpURLLoad("hidden_frames.html");
5862 FrameTestHelpers::WebViewHelper webViewHelper;
5863 WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "hidden_frames.html");
5864 for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5865 EXPECT_FALSE(frame->hasVisibleContent());
5866 }
5867 }
5868
5869 class ManifestChangeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5870 public:
ManifestChangeWebFrameClient()5871 ManifestChangeWebFrameClient() : m_manifestChangeCount(0) { }
didChangeManifest(WebLocalFrame *)5872 virtual void didChangeManifest(WebLocalFrame*) OVERRIDE
5873 {
5874 ++m_manifestChangeCount;
5875 }
5876
manifestChangeCount()5877 int manifestChangeCount() { return m_manifestChangeCount; }
5878
5879 private:
5880 int m_manifestChangeCount;
5881 };
5882
TEST_F(WebFrameTest,NotifyManifestChange)5883 TEST_F(WebFrameTest, NotifyManifestChange)
5884 {
5885 registerMockedHttpURLLoad("link-manifest-change.html");
5886
5887 ManifestChangeWebFrameClient webFrameClient;
5888 FrameTestHelpers::WebViewHelper webViewHelper;
5889 webViewHelper.initializeAndLoad(m_baseURL + "link-manifest-change.html", true, &webFrameClient);
5890
5891 EXPECT_EQ(14, webFrameClient.manifestChangeCount());
5892 }
5893
TEST_F(WebFrameTest,ReloadBypassingCache)5894 TEST_F(WebFrameTest, ReloadBypassingCache)
5895 {
5896 // Check that a reload ignoring cache on a frame will result in the cache
5897 // policy of the request being set to ReloadBypassingCache.
5898 registerMockedHttpURLLoad("foo.html");
5899 FrameTestHelpers::WebViewHelper webViewHelper;
5900 webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
5901 WebFrame* frame = webViewHelper.webView()->mainFrame();
5902 FrameTestHelpers::reloadFrameIgnoringCache(frame);
5903 EXPECT_EQ(WebURLRequest::ReloadBypassingCache, frame->dataSource()->request().cachePolicy());
5904 }
5905
nodeImageTestValidation(const IntSize & referenceBitmapSize,DragImage * dragImage)5906 static void nodeImageTestValidation(const IntSize& referenceBitmapSize, DragImage* dragImage)
5907 {
5908 // Prepare the reference bitmap.
5909 SkBitmap bitmap;
5910 bitmap.allocN32Pixels(referenceBitmapSize.width(), referenceBitmapSize.height());
5911 SkCanvas canvas(bitmap);
5912 canvas.drawColor(SK_ColorGREEN);
5913
5914 EXPECT_EQ(referenceBitmapSize.width(), dragImage->size().width());
5915 EXPECT_EQ(referenceBitmapSize.height(), dragImage->size().height());
5916 const SkBitmap& dragBitmap = dragImage->bitmap();
5917 SkAutoLockPixels lockPixel(dragBitmap);
5918 EXPECT_EQ(0, memcmp(bitmap.getPixels(), dragBitmap.getPixels(), bitmap.getSize()));
5919 }
5920
TEST_F(WebFrameTest,NodeImageTestCSSTransform)5921 TEST_F(WebFrameTest, NodeImageTestCSSTransform)
5922 {
5923 FrameTestHelpers::WebViewHelper webViewHelper;
5924 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-transform"));
5925 EXPECT_TRUE(dragImage);
5926
5927 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5928 }
5929
TEST_F(WebFrameTest,NodeImageTestCSS3DTransform)5930 TEST_F(WebFrameTest, NodeImageTestCSS3DTransform)
5931 {
5932 FrameTestHelpers::WebViewHelper webViewHelper;
5933 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-3dtransform"));
5934 EXPECT_TRUE(dragImage);
5935
5936 nodeImageTestValidation(IntSize(20, 40), dragImage.get());
5937 }
5938
TEST_F(WebFrameTest,NodeImageTestInlineBlock)5939 TEST_F(WebFrameTest, NodeImageTestInlineBlock)
5940 {
5941 FrameTestHelpers::WebViewHelper webViewHelper;
5942 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-inlineblock"));
5943 EXPECT_TRUE(dragImage);
5944
5945 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5946 }
5947
TEST_F(WebFrameTest,NodeImageTestFloatLeft)5948 TEST_F(WebFrameTest, NodeImageTestFloatLeft)
5949 {
5950 FrameTestHelpers::WebViewHelper webViewHelper;
5951 OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-float-left-overflow-hidden"));
5952 EXPECT_TRUE(dragImage);
5953
5954 nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5955 }
5956
5957 // Crashes on Android: http://crbug.com/403804
5958 #if OS(ANDROID)
TEST_F(WebFrameTest,DISABLED_PrintingBasic)5959 TEST_F(WebFrameTest, DISABLED_PrintingBasic)
5960 #else
5961 TEST_F(WebFrameTest, PrintingBasic)
5962 #endif
5963 {
5964 FrameTestHelpers::WebViewHelper webViewHelper;
5965 webViewHelper.initializeAndLoad("data:text/html,Hello, world.");
5966
5967 WebFrame* frame = webViewHelper.webView()->mainFrame();
5968
5969 WebPrintParams printParams;
5970 printParams.printContentArea.width = 500;
5971 printParams.printContentArea.height = 500;
5972
5973 int pageCount = frame->printBegin(printParams);
5974 EXPECT_EQ(1, pageCount);
5975 frame->printEnd();
5976 }
5977
5978 class ThemeColorTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5979 public:
ThemeColorTestWebFrameClient()5980 ThemeColorTestWebFrameClient()
5981 : m_didNotify(false)
5982 {
5983 }
5984
reset()5985 void reset()
5986 {
5987 m_didNotify = false;
5988 }
5989
didNotify() const5990 bool didNotify() const
5991 {
5992 return m_didNotify;
5993 }
5994
5995 private:
didChangeThemeColor()5996 virtual void didChangeThemeColor()
5997 {
5998 m_didNotify = true;
5999 }
6000
6001 bool m_didNotify;
6002 };
6003
TEST_F(WebFrameTest,ThemeColor)6004 TEST_F(WebFrameTest, ThemeColor)
6005 {
6006 registerMockedHttpURLLoad("theme_color_test.html");
6007 FrameTestHelpers::WebViewHelper webViewHelper;
6008 ThemeColorTestWebFrameClient client;
6009 webViewHelper.initializeAndLoad(m_baseURL + "theme_color_test.html", true, &client);
6010 EXPECT_TRUE(client.didNotify());
6011 WebLocalFrameImpl* frame = webViewHelper.webViewImpl()->mainFrameImpl();
6012 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6013 // Change color by rgb.
6014 client.reset();
6015 frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'rgb(0, 0, 0)');"));
6016 EXPECT_TRUE(client.didNotify());
6017 EXPECT_EQ(0xff000000, frame->document().themeColor());
6018 // Change color by hsl.
6019 client.reset();
6020 frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'hsl(240,100%, 50%)');"));
6021 EXPECT_TRUE(client.didNotify());
6022 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6023 // Change of second theme-color meta tag will not change frame's theme
6024 // color.
6025 client.reset();
6026 frame->executeScript(WebScriptSource("document.getElementById('tc2').setAttribute('content', '#00FF00');"));
6027 EXPECT_TRUE(client.didNotify());
6028 EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6029 }
6030
6031 class WebFrameSwapTest : public WebFrameTest {
6032 protected:
WebFrameSwapTest()6033 WebFrameSwapTest()
6034 {
6035 registerMockedHttpURLLoad("frame-a-b-c.html");
6036 registerMockedHttpURLLoad("subframe-a.html");
6037 registerMockedHttpURLLoad("subframe-b.html");
6038 registerMockedHttpURLLoad("subframe-c.html");
6039 registerMockedHttpURLLoad("subframe-hello.html");
6040
6041 m_webViewHelper.initializeAndLoad(m_baseURL + "frame-a-b-c.html");
6042 }
6043
reset()6044 void reset() { m_webViewHelper.reset(); }
mainFrame() const6045 WebFrame* mainFrame() const { return m_webViewHelper.webView()->mainFrame(); }
6046
6047 private:
6048 FrameTestHelpers::WebViewHelper m_webViewHelper;
6049 };
6050
6051 // FIXME: We should have tests for main frame swaps, but it interacts poorly
6052 // with the geolocation inspector agent, since the lifetime of the inspector
6053 // agent is tied to the Page, but the inspector agent is created by the
6054 // instantiation of the main frame.
6055
swapAndVerifyFirstChildConsistency(const char * const message,WebFrame * parent,WebFrame * newChild)6056 void swapAndVerifyFirstChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6057 {
6058 SCOPED_TRACE(message);
6059 parent->firstChild()->swap(newChild);
6060
6061 EXPECT_EQ(newChild, parent->firstChild());
6062 EXPECT_EQ(newChild->parent(), parent);
6063 EXPECT_EQ(newChild, parent->lastChild()->previousSibling()->previousSibling());
6064 EXPECT_EQ(newChild->nextSibling(), parent->lastChild()->previousSibling());
6065 }
6066
TEST_F(WebFrameSwapTest,SwapFirstChild)6067 TEST_F(WebFrameSwapTest, SwapFirstChild)
6068 {
6069 WebFrame* remoteFrame = WebRemoteFrame::create(0);
6070 swapAndVerifyFirstChildConsistency("local->remote", mainFrame(), remoteFrame);
6071
6072 FrameTestHelpers::TestWebFrameClient client;
6073 WebFrame* localFrame = WebLocalFrame::create(&client);
6074 swapAndVerifyFirstChildConsistency("remote->local", mainFrame(), localFrame);
6075
6076 // FIXME: This almost certainly fires more load events on the iframe element
6077 // than it should.
6078 // Finally, make sure an embedder triggered load in the local frame swapped
6079 // back in works.
6080 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6081 std::string content = localFrame->contentAsText(1024).utf8();
6082 EXPECT_EQ("hello", content);
6083
6084 // Manually reset to break WebViewHelper's dependency on the stack allocated
6085 // TestWebFrameClient.
6086 reset();
6087 remoteFrame->close();
6088 }
6089
swapAndVerifyMiddleChildConsistency(const char * const message,WebFrame * parent,WebFrame * newChild)6090 void swapAndVerifyMiddleChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6091 {
6092 SCOPED_TRACE(message);
6093 parent->firstChild()->nextSibling()->swap(newChild);
6094
6095 EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
6096 EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
6097 EXPECT_EQ(newChild->parent(), parent);
6098 EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
6099 EXPECT_EQ(newChild->previousSibling(), parent->firstChild());
6100 EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
6101 EXPECT_EQ(newChild->nextSibling(), parent->lastChild());
6102 }
6103
TEST_F(WebFrameSwapTest,SwapMiddleChild)6104 TEST_F(WebFrameSwapTest, SwapMiddleChild)
6105 {
6106 WebFrame* remoteFrame = WebRemoteFrame::create(0);
6107 swapAndVerifyMiddleChildConsistency("local->remote", mainFrame(), remoteFrame);
6108
6109 FrameTestHelpers::TestWebFrameClient client;
6110 WebFrame* localFrame = WebLocalFrame::create(&client);
6111 swapAndVerifyMiddleChildConsistency("remote->local", mainFrame(), localFrame);
6112
6113 // FIXME: This almost certainly fires more load events on the iframe element
6114 // than it should.
6115 // Finally, make sure an embedder triggered load in the local frame swapped
6116 // back in works.
6117 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6118 std::string content = localFrame->contentAsText(1024).utf8();
6119 EXPECT_EQ("hello", content);
6120
6121 // Manually reset to break WebViewHelper's dependency on the stack allocated
6122 // TestWebFrameClient.
6123 reset();
6124 remoteFrame->close();
6125 }
6126
swapAndVerifyLastChildConsistency(const char * const message,WebFrame * parent,WebFrame * newChild)6127 void swapAndVerifyLastChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6128 {
6129 SCOPED_TRACE(message);
6130 parent->lastChild()->swap(newChild);
6131
6132 EXPECT_EQ(newChild, parent->lastChild());
6133 EXPECT_EQ(newChild->parent(), parent);
6134 EXPECT_EQ(newChild, parent->firstChild()->nextSibling()->nextSibling());
6135 EXPECT_EQ(newChild->previousSibling(), parent->firstChild()->nextSibling());
6136 }
6137
TEST_F(WebFrameSwapTest,SwapLastChild)6138 TEST_F(WebFrameSwapTest, SwapLastChild)
6139 {
6140 WebFrame* remoteFrame = WebRemoteFrame::create(0);
6141 swapAndVerifyLastChildConsistency("local->remote", mainFrame(), remoteFrame);
6142
6143 FrameTestHelpers::TestWebFrameClient client;
6144 WebFrame* localFrame = WebLocalFrame::create(&client);
6145 swapAndVerifyLastChildConsistency("remote->local", mainFrame(), localFrame);
6146
6147 // FIXME: This almost certainly fires more load events on the iframe element
6148 // than it should.
6149 // Finally, make sure an embedder triggered load in the local frame swapped
6150 // back in works.
6151 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6152 std::string content = localFrame->contentAsText(1024).utf8();
6153 EXPECT_EQ("hello", content);
6154
6155 // Manually reset to break WebViewHelper's dependency on the stack allocated
6156 // TestWebFrameClient.
6157 reset();
6158 remoteFrame->close();
6159 }
6160
swapAndVerifySubframeConsistency(const char * const message,WebFrame * oldFrame,WebFrame * newFrame)6161 void swapAndVerifySubframeConsistency(const char* const message, WebFrame* oldFrame, WebFrame* newFrame)
6162 {
6163 SCOPED_TRACE(message);
6164
6165 EXPECT_TRUE(oldFrame->firstChild());
6166 oldFrame->swap(newFrame);
6167
6168 EXPECT_FALSE(newFrame->firstChild());
6169 EXPECT_FALSE(newFrame->lastChild());
6170 }
6171
TEST_F(WebFrameSwapTest,SwapParentShouldDetachChildren)6172 TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren)
6173 {
6174 WebRemoteFrame* remoteFrame = WebRemoteFrame::create(0);
6175 WebFrame* targetFrame = mainFrame()->firstChild()->nextSibling();
6176 EXPECT_TRUE(targetFrame);
6177 swapAndVerifySubframeConsistency("local->remote", targetFrame, remoteFrame);
6178
6179 targetFrame = mainFrame()->firstChild()->nextSibling();
6180 EXPECT_TRUE(targetFrame);
6181
6182 // Create child frames in the target frame before testing the swap.
6183 FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
6184 remoteFrame->createRemoteChild("", &remoteFrameClient);
6185
6186 FrameTestHelpers::TestWebFrameClient client;
6187 WebFrame* localFrame = WebLocalFrame::create(&client);
6188 swapAndVerifySubframeConsistency("remote->local", targetFrame, localFrame);
6189
6190 // FIXME: This almost certainly fires more load events on the iframe element
6191 // than it should.
6192 // Finally, make sure an embedder triggered load in the local frame swapped
6193 // back in works.
6194 FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6195 std::string content = localFrame->contentAsText(1024).utf8();
6196 EXPECT_EQ("hello", content);
6197
6198 // Manually reset to break WebViewHelper's dependency on the stack allocated
6199 // TestWebFrameClient.
6200 reset();
6201 remoteFrame->close();
6202 }
6203
6204 class MockDocumentThreadableLoaderClient : public DocumentThreadableLoaderClient {
6205 public:
MockDocumentThreadableLoaderClient()6206 MockDocumentThreadableLoaderClient() : m_failed(false) { }
didFail(const ResourceError &)6207 virtual void didFail(const ResourceError&) OVERRIDE { m_failed = true;}
6208
reset()6209 void reset() { m_failed = false; }
failed()6210 bool failed() { return m_failed; }
6211
6212 bool m_failed;
6213 };
6214
6215 // FIXME: This would be better as a unittest on DocumentThreadableLoader but it
6216 // requires spin-up of a frame. It may be possible to remove that requirement
6217 // and convert it to a unittest.
TEST_F(WebFrameTest,LoaderOriginAccess)6218 TEST_F(WebFrameTest, LoaderOriginAccess)
6219 {
6220 FrameTestHelpers::WebViewHelper webViewHelper;
6221 webViewHelper.initializeAndLoad("about:blank");
6222
6223 SchemeRegistry::registerURLSchemeAsDisplayIsolated("chrome");
6224
6225 // Cross-origin request.
6226 KURL resourceUrl(ParsedURLString, "chrome://test.pdf");
6227 registerMockedChromeURLLoad("test.pdf");
6228
6229 RefPtrWillBeRawPtr<LocalFrame> frame(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame()));
6230
6231 MockDocumentThreadableLoaderClient client;
6232 ThreadableLoaderOptions options;
6233
6234 // First try to load the request with regular access. Should fail.
6235 options.crossOriginRequestPolicy = UseAccessControl;
6236 ResourceLoaderOptions resourceLoaderOptions;
6237 DocumentThreadableLoader::loadResourceSynchronously(
6238 *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
6239 EXPECT_TRUE(client.failed());
6240
6241 client.reset();
6242 // Try to load the request with cross origin access. Should succeed.
6243 options.crossOriginRequestPolicy = AllowCrossOriginRequests;
6244 DocumentThreadableLoader::loadResourceSynchronously(
6245 *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
6246 EXPECT_FALSE(client.failed());
6247 }
6248
6249 class NavigationTransitionCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6250 public:
NavigationTransitionCallbackWebFrameClient()6251 NavigationTransitionCallbackWebFrameClient()
6252 : m_navigationalDataReceivedCount(0)
6253 , m_provisionalLoadCount(0)
6254 , m_wasLastProvisionalLoadATransition(false) { }
6255
addNavigationTransitionData(const WebString & allowedDestinationOrigin,const WebString & selector,const WebString & markup)6256 virtual void addNavigationTransitionData(const WebString& allowedDestinationOrigin, const WebString& selector, const WebString& markup) OVERRIDE
6257 {
6258 m_navigationalDataReceivedCount++;
6259 }
6260
didStartProvisionalLoad(WebLocalFrame * localFrame,bool isTransitionNavigation)6261 virtual void didStartProvisionalLoad(WebLocalFrame* localFrame, bool isTransitionNavigation) OVERRIDE
6262 {
6263 m_provisionalLoadCount++;
6264 m_wasLastProvisionalLoadATransition = isTransitionNavigation;
6265 }
6266
navigationalDataReceivedCount() const6267 unsigned navigationalDataReceivedCount() const { return m_navigationalDataReceivedCount; }
provisionalLoadCount() const6268 unsigned provisionalLoadCount() const { return m_provisionalLoadCount; }
wasLastProvisionalLoadATransition() const6269 bool wasLastProvisionalLoadATransition() const { return m_wasLastProvisionalLoadATransition; }
6270
6271 private:
6272 unsigned m_navigationalDataReceivedCount;
6273 unsigned m_provisionalLoadCount;
6274 bool m_wasLastProvisionalLoadATransition;
6275 };
6276
TEST_F(WebFrameTest,NavigationTransitionCallbacks)6277 TEST_F(WebFrameTest, NavigationTransitionCallbacks)
6278 {
6279 RuntimeEnabledFeatures::setNavigationTransitionsEnabled(true);
6280 FrameTestHelpers::WebViewHelper viewHelper;
6281 NavigationTransitionCallbackWebFrameClient frameClient;
6282 WebLocalFrame* localFrame = viewHelper.initialize(true, &frameClient)->mainFrame()->toWebLocalFrame();
6283
6284 const char* transitionHTMLString =
6285 "<!DOCTYPE html>"
6286 "<meta name='transition-elements' content='#foo;*'>"
6287 "<div id='foo'>";
6288
6289 // Initial document load should not be a transition.
6290 FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("http://www.test.com"));
6291 EXPECT_EQ(1u, frameClient.provisionalLoadCount());
6292 EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6293 EXPECT_EQ(0u, frameClient.navigationalDataReceivedCount());
6294
6295 // Going from www.test.com containing transition elements to about:blank, should be a transition.
6296 FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("about:blank"));
6297 EXPECT_EQ(2u, frameClient.provisionalLoadCount());
6298 EXPECT_TRUE(frameClient.wasLastProvisionalLoadATransition());
6299 EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6300
6301 // Navigating to the URL of the current page shouldn't be a transition.
6302 FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("about:blank"));
6303 EXPECT_EQ(3u, frameClient.provisionalLoadCount());
6304 EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6305 EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6306
6307 // Neither should a page reload.
6308 localFrame->reload();
6309 EXPECT_EQ(4u, frameClient.provisionalLoadCount());
6310 EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6311 EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6312 }
6313
6314 } // namespace
6315