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