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