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