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
98using namespace blink;
99using WebCore::Document;
100using WebCore::DocumentMarker;
101using WebCore::Element;
102using WebCore::FloatRect;
103using WebCore::HitTestRequest;
104using WebCore::Range;
105using blink::URLTestHelpers::toKURL;
106using blink::FrameTestHelpers::runPendingTasks;
107
108namespace {
109
110const 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
118class FakeCompositingWebViewClient : public FrameTestHelpers::TestWebViewClient {
119public:
120    virtual bool enterFullScreen() OVERRIDE { return true; }
121};
122
123class WebFrameTest : public testing::Test {
124protected:
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
188class UseMockScrollbarSettings {
189public:
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
204TEST_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
223TEST_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
238TEST_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
255TEST_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
274TEST_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
294TEST_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
314TEST_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
333class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
334public:
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
342void 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
358class WebFrameCSSCallbackTest : public testing::Test {
359protected:
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
403TEST_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
439TEST_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
479TEST_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
497TEST_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
543TEST_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
566TEST_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
583TEST_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
601TEST_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
630TEST_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
645class 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
653static void enableViewportSettings(WebSettings* settings)
654{
655    settings->setViewportMetaEnabled(true);
656    settings->setViewportEnabled(true);
657    settings->setMainFrameResizesAreOrientationChanges(true);
658    settings->setShrinksViewportContentToFit(true);
659}
660
661TEST_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.
688static 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
703static bool setTextAutosizingMultiplier(Document* document, float multiplier)
704{
705    return checkOrSetTextAutosizingMultiplier(document, multiplier, true);
706}
707
708static bool checkTextAutosizingMultiplier(Document* document, float multiplier)
709{
710    return checkOrSetTextAutosizingMultiplier(document, multiplier, false);
711}
712
713TEST_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
742TEST_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
784TEST_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
805TEST_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
828TEST_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
852TEST_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
880TEST_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
908TEST_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
925TEST_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
954TEST_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
991TEST_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
1028TEST_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
1052TEST_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
1072TEST_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
1093TEST_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
1114TEST_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
1136TEST_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
1157TEST_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
1176TEST_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
1197TEST_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
1216TEST_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
1248TEST_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
1268TEST_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
1287TEST_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
1323TEST_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
1345TEST_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
1371TEST_F(WebFrameTest, SetForceZeroLayoutHeight)
1372{
1373    UseMockScrollbarSettings mockScrollbarSettings;
1374    registerMockedHttpURLLoad("200-by-300.html");
1375
1376    FixedLayoutTestWebViewClient client;
1377    client.m_screenInfo.deviceScaleFactor = 1;
1378    int viewportWidth = 640;
1379    int viewportHeight = 480;
1380
1381    FrameTestHelpers::WebViewHelper webViewHelper;
1382
1383    webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1384    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1385    webViewHelper.webView()->layout();
1386
1387    EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1388    webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1389    EXPECT_TRUE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1390
1391    EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1392
1393    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight * 2));
1394    EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1395    EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1396
1397    webViewHelper.webView()->resize(WebSize(viewportWidth * 2, viewportHeight));
1398    webViewHelper.webView()->layout();
1399    EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1400
1401    webViewHelper.webView()->settings()->setForceZeroLayoutHeight(false);
1402    EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1403}
1404
1405TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations)
1406{
1407    UseMockScrollbarSettings mockScrollbarSettings;
1408    registerMockedHttpURLLoad("200-by-300.html");
1409    registerMockedHttpURLLoad("large-div.html");
1410
1411    FixedLayoutTestWebViewClient client;
1412    client.m_screenInfo.deviceScaleFactor = 1;
1413    int viewportWidth = 640;
1414    int viewportHeight = 480;
1415
1416    FrameTestHelpers::WebViewHelper webViewHelper;
1417
1418    webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1419    webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1420    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1421    webViewHelper.webView()->layout();
1422
1423    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
1424    webViewHelper.webView()->layout();
1425
1426    EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1427}
1428
1429TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk)
1430{
1431    UseMockScrollbarSettings mockScrollbarSettings;
1432    registerMockedHttpURLLoad("200-by-300.html");
1433
1434    FixedLayoutTestWebViewClient client;
1435    client.m_screenInfo.deviceScaleFactor = 1;
1436    int viewportWidth = 640;
1437    int viewportHeight = 480;
1438
1439    FrameTestHelpers::WebViewHelper webViewHelper;
1440
1441    webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings);
1442    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1443    webViewHelper.webView()->settings()->setUseWideViewport(true);
1444    webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
1445    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1446    webViewHelper.webView()->layout();
1447
1448    EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1449}
1450
1451TEST_F(WebFrameTest, WideViewportAndWideContentWithInitialScale)
1452{
1453    UseMockScrollbarSettings mockScrollbarSettings;
1454    registerMockedHttpURLLoad("wide_document_width_viewport.html");
1455
1456    FixedLayoutTestWebViewClient client;
1457    client.m_screenInfo.deviceScaleFactor = 1;
1458    int viewportWidth = 600;
1459    int viewportHeight = 800;
1460
1461    FrameTestHelpers::WebViewHelper webViewHelper;
1462    webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1463    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1464    webViewHelper.webView()->settings()->setUseWideViewport(true);
1465    webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1466    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1467
1468    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "wide_document_width_viewport.html");
1469    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1470
1471    int wideDocumentWidth = 800;
1472    float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth;
1473    EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1474    EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor());
1475}
1476
1477TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight)
1478{
1479    UseMockScrollbarSettings mockScrollbarSettings;
1480    registerMockedHttpURLLoad("viewport-height-1000.html");
1481
1482    FixedLayoutTestWebViewClient client;
1483    client.m_screenInfo.deviceScaleFactor = 1;
1484    int viewportWidth = 600;
1485    int viewportHeight = 800;
1486
1487    FrameTestHelpers::WebViewHelper webViewHelper;
1488    webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1489    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1490    webViewHelper.webView()->settings()->setUseWideViewport(false);
1491    webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1492    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1493
1494    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-height-1000.html");
1495    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1496
1497    EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1498    EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1499}
1500
1501TEST_F(WebFrameTest, LayoutSize320Quirk)
1502{
1503    UseMockScrollbarSettings mockScrollbarSettings;
1504    registerMockedHttpURLLoad("viewport/viewport-30.html");
1505
1506    FixedLayoutTestWebViewClient client;
1507    client.m_screenInfo.deviceScaleFactor = 1;
1508    int viewportWidth = 600;
1509    int viewportHeight = 800;
1510
1511    FrameTestHelpers::WebViewHelper webViewHelper;
1512    webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings);
1513    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1514    webViewHelper.webView()->settings()->setUseWideViewport(true);
1515    webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1516    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1517
1518    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport/viewport-30.html");
1519    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1520
1521    EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1522    EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1523    EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
1524
1525    // The magic number to snap to device-width is 320, so test that 321 is
1526    // respected.
1527    WebCore::Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
1528    WebCore::ViewportDescription description = document->viewportDescription();
1529    description.minWidth = WebCore::Length(321, WebCore::Fixed);
1530    description.maxWidth = WebCore::Length(321, WebCore::Fixed);
1531    document->setViewportDescription(description);
1532    webViewHelper.webView()->layout();
1533    EXPECT_EQ(321, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1534
1535    description.minWidth = WebCore::Length(320, WebCore::Fixed);
1536    description.maxWidth = WebCore::Length(320, WebCore::Fixed);
1537    document->setViewportDescription(description);
1538    webViewHelper.webView()->layout();
1539    EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1540
1541    description = document->viewportDescription();
1542    description.maxHeight = WebCore::Length(1000, WebCore::Fixed);
1543    document->setViewportDescription(description);
1544    webViewHelper.webView()->layout();
1545    EXPECT_EQ(1000, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1546
1547    description.maxHeight = WebCore::Length(320, WebCore::Fixed);
1548    document->setViewportDescription(description);
1549    webViewHelper.webView()->layout();
1550    EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height());
1551}
1552
1553TEST_F(WebFrameTest, ZeroValuesQuirk)
1554{
1555    UseMockScrollbarSettings mockScrollbarSettings;
1556    registerMockedHttpURLLoad("viewport-zero-values.html");
1557
1558    FixedLayoutTestWebViewClient client;
1559    client.m_screenInfo.deviceScaleFactor = 1;
1560    int viewportWidth = 640;
1561    int viewportHeight = 480;
1562
1563    FrameTestHelpers::WebViewHelper webViewHelper;
1564    webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1565    webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1566    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1567    webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
1568    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-zero-values.html");
1569    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1570
1571    EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1572    EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1573
1574    webViewHelper.webView()->settings()->setUseWideViewport(true);
1575    webViewHelper.webView()->layout();
1576    EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1577    EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
1578}
1579
1580TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling)
1581{
1582    registerMockedHttpURLLoad("body-overflow-hidden.html");
1583
1584    FixedLayoutTestWebViewClient client;
1585    client.m_screenInfo.deviceScaleFactor = 1;
1586    int viewportWidth = 640;
1587    int viewportHeight = 480;
1588
1589    FrameTestHelpers::WebViewHelper webViewHelper;
1590    webViewHelper.initialize(true, 0, &client);
1591    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1592    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1593
1594    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1595    EXPECT_FALSE(view->userInputScrollable(WebCore::VerticalScrollbar));
1596}
1597
1598TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk)
1599{
1600    registerMockedHttpURLLoad("body-overflow-hidden.html");
1601
1602    FixedLayoutTestWebViewClient client;
1603    client.m_screenInfo.deviceScaleFactor = 1;
1604    int viewportWidth = 640;
1605    int viewportHeight = 480;
1606
1607    FrameTestHelpers::WebViewHelper webViewHelper;
1608    webViewHelper.initialize(true, 0, &client);
1609    webViewHelper.webView()->settings()->setIgnoreMainFrameOverflowHiddenQuirk(true);
1610    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html");
1611    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1612
1613    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1614    EXPECT_TRUE(view->userInputScrollable(WebCore::VerticalScrollbar));
1615}
1616
1617TEST_F(WebFrameTest, NonZeroValuesNoQuirk)
1618{
1619    UseMockScrollbarSettings mockScrollbarSettings;
1620    registerMockedHttpURLLoad("viewport-nonzero-values.html");
1621
1622    FixedLayoutTestWebViewClient client;
1623    client.m_screenInfo.deviceScaleFactor = 1;
1624    int viewportWidth = 640;
1625    int viewportHeight = 480;
1626    float expectedPageScaleFactor = 0.5f;
1627
1628    FrameTestHelpers::WebViewHelper webViewHelper;
1629    webViewHelper.initialize(true, 0, &client, enableViewportSettings);
1630    webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
1631    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1632    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-nonzero-values.html");
1633    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1634
1635    EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1636    EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1637
1638    webViewHelper.webView()->settings()->setUseWideViewport(true);
1639    webViewHelper.webView()->layout();
1640    EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width());
1641    EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
1642}
1643
1644TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout)
1645{
1646    UseMockScrollbarSettings mockScrollbarSettings;
1647    registerMockedHttpURLLoad("fixed_layout.html");
1648
1649    FixedLayoutTestWebViewClient client;
1650    client.m_screenInfo.deviceScaleFactor = 1;
1651    // Small viewport to ensure there are always scrollbars.
1652    int viewportWidth = 64;
1653    int viewportHeight = 48;
1654
1655    FrameTestHelpers::WebViewHelper webViewHelper;
1656    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1657    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1658    webViewHelper.webView()->layout();
1659
1660    int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1661    webViewHelper.webViewImpl()->setPageScaleFactor(3);
1662    EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1663    EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1664}
1665
1666TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout)
1667{
1668    UseMockScrollbarSettings mockScrollbarSettings;
1669
1670    registerMockedHttpURLLoad("fixed_layout.html");
1671
1672    FixedLayoutTestWebViewClient client;
1673    client.m_screenInfo.deviceScaleFactor = 1;
1674    int viewportWidth = 640;
1675    int viewportHeight = 480;
1676
1677    FrameTestHelpers::WebViewHelper webViewHelper;
1678    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1679    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1680    webViewHelper.webView()->layout();
1681
1682    int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount();
1683    webViewHelper.webViewImpl()->setPageScaleFactor(30);
1684    EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout());
1685    EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount());
1686
1687}
1688
1689TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem)
1690{
1691    UseMockScrollbarSettings mockScrollbarSettings;
1692    registerMockedHttpURLLoad("fixed_layout.html");
1693
1694    FixedLayoutTestWebViewClient client;
1695    client.m_screenInfo.deviceScaleFactor = 1;
1696    int viewportWidth = 640;
1697    int viewportHeight = 480;
1698
1699    FrameTestHelpers::WebViewHelper webViewHelper;
1700    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1701    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1702    webViewHelper.webView()->layout();
1703
1704    webViewHelper.webView()->setPageScaleFactor(3);
1705    EXPECT_EQ(3, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1706}
1707
1708TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem)
1709{
1710    UseMockScrollbarSettings mockScrollbarSettings;
1711    registerMockedHttpURLLoad("fixed_layout.html");
1712
1713    FixedLayoutTestWebViewClient client;
1714    client.m_screenInfo.deviceScaleFactor = 1;
1715    int viewportWidth = 640;
1716    int viewportHeight = 480;
1717
1718    FrameTestHelpers::WebViewHelper webViewHelper;
1719    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1720    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1721    webViewHelper.webView()->layout();
1722
1723    int defaultFixedLayoutWidth = 980;
1724    float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
1725    EXPECT_EQ(minimumPageScaleFactor, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor());
1726}
1727
1728TEST_F(WebFrameTest, pageScaleFactorShrinksViewport)
1729{
1730    UseMockScrollbarSettings mockScrollbarSettings;
1731    registerMockedHttpURLLoad("large-div.html");
1732
1733    FixedLayoutTestWebViewClient client;
1734    client.m_screenInfo.deviceScaleFactor = 1;
1735    // Small viewport to ensure there are always scrollbars.
1736    int viewportWidth = 64;
1737    int viewportHeight = 48;
1738
1739    FrameTestHelpers::WebViewHelper webViewHelper;
1740    webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1741    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1742    webViewHelper.webView()->layout();
1743
1744    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
1745    int viewportWidthMinusScrollbar = viewportWidth - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
1746    int viewportHeightMinusScrollbar = viewportHeight - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
1747
1748    webViewHelper.webView()->setPageScaleFactor(2);
1749
1750    WebCore::IntSize unscaledSize = view->unscaledVisibleContentSize(WebCore::IncludeScrollbars);
1751    EXPECT_EQ(viewportWidth, unscaledSize.width());
1752    EXPECT_EQ(viewportHeight, unscaledSize.height());
1753
1754    WebCore::IntSize unscaledSizeMinusScrollbar = view->unscaledVisibleContentSize(WebCore::ExcludeScrollbars);
1755    EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width());
1756    EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height());
1757
1758    WebCore::IntSize scaledSize = view->visibleContentRect().size();
1759    EXPECT_EQ(ceil(viewportWidthMinusScrollbar / 2.0), scaledSize.width());
1760    EXPECT_EQ(ceil(viewportHeightMinusScrollbar / 2.0), scaledSize.height());
1761}
1762
1763TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform)
1764{
1765    UseMockScrollbarSettings mockScrollbarSettings;
1766    registerMockedHttpURLLoad("fixed_layout.html");
1767
1768    FixedLayoutTestWebViewClient client;
1769    client.m_screenInfo.deviceScaleFactor = 1;
1770    int viewportWidth = 640;
1771    int viewportHeight = 480;
1772
1773    FrameTestHelpers::WebViewHelper webViewHelper;
1774    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
1775    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1776    webViewHelper.webView()->layout();
1777
1778    webViewHelper.webView()->setPageScaleFactor(2);
1779
1780    EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentRenderer()->unscaledDocumentRect().width());
1781    EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width());
1782}
1783
1784TEST_F(WebFrameTest, targetDensityDpiHigh)
1785{
1786    UseMockScrollbarSettings mockScrollbarSettings;
1787    registerMockedHttpURLLoad("viewport-target-densitydpi-high.html");
1788
1789    FixedLayoutTestWebViewClient client;
1790    // high-dpi = 240
1791    float targetDpi = 240.0f;
1792    float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1793    int viewportWidth = 640;
1794    int viewportHeight = 480;
1795
1796    for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1797        float deviceScaleFactor = deviceScaleFactors[i];
1798        float deviceDpi = deviceScaleFactor * 160.0f;
1799        client.m_screenInfo.deviceScaleFactor = deviceScaleFactor;
1800
1801        FrameTestHelpers::WebViewHelper webViewHelper;
1802        webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-high.html", true, 0, &client, enableViewportSettings);
1803        webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1804        webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1805        webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1806
1807        // We need to account for the fact that logical pixels are unconditionally multiplied by deviceScaleFactor to produce
1808        // physical pixels.
1809        float densityDpiScaleRatio = deviceScaleFactor * targetDpi / deviceDpi;
1810        EXPECT_NEAR(viewportWidth * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1811        EXPECT_NEAR(viewportHeight * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1812        EXPECT_NEAR(1.0f / densityDpiScaleRatio, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1813    }
1814}
1815
1816TEST_F(WebFrameTest, targetDensityDpiDevice)
1817{
1818    UseMockScrollbarSettings mockScrollbarSettings;
1819    registerMockedHttpURLLoad("viewport-target-densitydpi-device.html");
1820
1821    float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1822
1823    FixedLayoutTestWebViewClient client;
1824    int viewportWidth = 640;
1825    int viewportHeight = 480;
1826
1827    for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1828        client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
1829
1830        FrameTestHelpers::WebViewHelper webViewHelper;
1831        webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device.html", true, 0, &client, enableViewportSettings);
1832        webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1833        webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1834        webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1835
1836        EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1837        EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1838        EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1839    }
1840}
1841
1842TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth)
1843{
1844    UseMockScrollbarSettings mockScrollbarSettings;
1845    registerMockedHttpURLLoad("viewport-target-densitydpi-device-and-fixed-width.html");
1846
1847    float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f };
1848
1849    FixedLayoutTestWebViewClient client;
1850    int viewportWidth = 640;
1851    int viewportHeight = 480;
1852
1853    for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) {
1854        client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
1855
1856        FrameTestHelpers::WebViewHelper webViewHelper;
1857        webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device-and-fixed-width.html", true, 0, &client, enableViewportSettings);
1858        webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1859        webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1860        webViewHelper.webView()->settings()->setUseWideViewport(true);
1861        webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1862
1863        EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1864        EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1865        EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1866    }
1867}
1868
1869TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne)
1870{
1871    UseMockScrollbarSettings mockScrollbarSettings;
1872    registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
1873
1874    FixedLayoutTestWebViewClient client;
1875    client.m_screenInfo.deviceScaleFactor = 1.33f;
1876    int viewportWidth = 640;
1877    int viewportHeight = 480;
1878
1879    FrameTestHelpers::WebViewHelper webViewHelper;
1880    webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1.html", true, 0, &client, enableViewportSettings);
1881    webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1882    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1883    webViewHelper.webView()->settings()->setUseWideViewport(false);
1884    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1885    webViewHelper.webView()->layout();
1886
1887    EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1888    EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1889    EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1890}
1891
1892TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth)
1893{
1894    UseMockScrollbarSettings mockScrollbarSettings;
1895    registerMockedHttpURLLoad("viewport-initial-scale-less-than-1-device-width.html");
1896
1897    FixedLayoutTestWebViewClient client;
1898    client.m_screenInfo.deviceScaleFactor = 1.33f;
1899    int viewportWidth = 640;
1900    int viewportHeight = 480;
1901
1902    FrameTestHelpers::WebViewHelper webViewHelper;
1903    webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true, 0, &client, enableViewportSettings);
1904    webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1905    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1906    webViewHelper.webView()->settings()->setUseWideViewport(false);
1907    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1908    webViewHelper.webView()->layout();
1909
1910    const float pageZoom = 0.25f;
1911    EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1912    EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1913    EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1914}
1915
1916TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride)
1917{
1918    UseMockScrollbarSettings mockScrollbarSettings;
1919    registerMockedHttpURLLoad("large-div.html");
1920
1921    FixedLayoutTestWebViewClient client;
1922    int viewportWidth = 640;
1923    int viewportHeight = 480;
1924    float enforcedPageScaleFactor = 5.0f;
1925
1926    FrameTestHelpers::WebViewHelper webViewHelper;
1927    webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings);
1928    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1929    webViewHelper.webView()->settings()->setUseWideViewport(false);
1930    webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
1931    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1932    webViewHelper.webView()->layout();
1933
1934    EXPECT_NEAR(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1935    EXPECT_NEAR(viewportHeight / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1936    EXPECT_NEAR(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1937}
1938
1939TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScale)
1940{
1941    UseMockScrollbarSettings mockScrollbarSettings;
1942    registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
1943
1944    FixedLayoutTestWebViewClient client;
1945    int viewportWidth = 640;
1946    int viewportHeight = 480;
1947
1948    FrameTestHelpers::WebViewHelper webViewHelper;
1949    webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
1950    webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1951    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1952    webViewHelper.webView()->layout();
1953
1954    EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1955    EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1956    EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1957}
1958
1959TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport)
1960{
1961    UseMockScrollbarSettings mockScrollbarSettings;
1962    registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
1963
1964    FixedLayoutTestWebViewClient client;
1965    client.m_screenInfo.deviceScaleFactor = 1.33f;
1966    int viewportWidth = 640;
1967    int viewportHeight = 480;
1968
1969    FrameTestHelpers::WebViewHelper webViewHelper;
1970    webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings);
1971    webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true);
1972    webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1973    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1974    webViewHelper.webView()->settings()->setUseWideViewport(false);
1975    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1976    webViewHelper.webView()->layout();
1977
1978    EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
1979    EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
1980    EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f);
1981}
1982
1983TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport)
1984{
1985    UseMockScrollbarSettings mockScrollbarSettings;
1986    registerMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html");
1987
1988    FixedLayoutTestWebViewClient client;
1989    int viewportWidth = 640;
1990    int viewportHeight = 480;
1991
1992    FrameTestHelpers::WebViewHelper webViewHelper;
1993    webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale-non-user-scalable.html", true, 0, &client, enableViewportSettings);
1994    webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true);
1995    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
1996    webViewHelper.webView()->settings()->setUseWideViewport(true);
1997    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
1998
1999    EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f);
2000    EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f);
2001    EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2002}
2003
2004TEST_F(WebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff)
2005{
2006    UseMockScrollbarSettings mockScrollbarSettings;
2007    registerMockedHttpURLLoad("no_viewport_tag.html");
2008
2009    FixedLayoutTestWebViewClient client;
2010    int viewportWidth = 640;
2011    int viewportHeight = 480;
2012
2013    FrameTestHelpers::WebViewHelper webViewHelper;
2014    webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings);
2015    webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
2016    webViewHelper.webView()->settings()->setUseWideViewport(false);
2017    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2018
2019    EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
2020    EXPECT_NEAR(1.0f, webViewHelper.webView()->minimumPageScaleFactor(), 0.01f);
2021    EXPECT_NEAR(5.0f, webViewHelper.webView()->maximumPageScaleFactor(), 0.01f);
2022}
2023
2024class WebFrameResizeTest : public WebFrameTest {
2025protected:
2026
2027    static WebCore::FloatSize computeRelativeOffset(const WebCore::IntPoint& absoluteOffset, const WebCore::LayoutRect& rect)
2028    {
2029        WebCore::FloatSize relativeOffset = WebCore::FloatPoint(absoluteOffset) - rect.location();
2030        relativeOffset.scale(1.f / rect.width(), 1.f / rect.height());
2031        return relativeOffset;
2032    }
2033
2034    void testResizeYieldsCorrectScrollAndScale(const char* url,
2035                                               const float initialPageScaleFactor,
2036                                               const WebSize scrollOffset,
2037                                               const WebSize viewportSize,
2038                                               const bool shouldScaleRelativeToViewportWidth) {
2039        UseMockScrollbarSettings mockScrollbarSettings;
2040        registerMockedHttpURLLoad(url);
2041
2042        const float aspectRatio = static_cast<float>(viewportSize.width) / viewportSize.height;
2043
2044        FrameTestHelpers::WebViewHelper webViewHelper;
2045        webViewHelper.initializeAndLoad(m_baseURL + url, true, 0, 0, enableViewportSettings);
2046
2047        // Origin scrollOffsets preserved under resize.
2048        {
2049            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
2050            webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
2051            ASSERT_EQ(viewportSize, webViewHelper.webViewImpl()->size());
2052            ASSERT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2053            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
2054            float expectedPageScaleFactor = initialPageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1);
2055            EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
2056            EXPECT_EQ(WebSize(), webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2057        }
2058
2059        // Resizing just the height should not affect pageScaleFactor or scrollOffset.
2060        {
2061            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
2062            webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor);
2063            webViewHelper.webViewImpl()->setMainFrameScrollOffset(WebPoint(scrollOffset.width, scrollOffset.height));
2064            webViewHelper.webViewImpl()->layout();
2065            const WebSize expectedScrollOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
2066            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
2067            EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2068            EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2069            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f));
2070            EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor());
2071            EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2072        }
2073
2074        // Generic resize preserves scrollOffset relative to anchor node located
2075        // the top center of the screen.
2076        {
2077            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
2078            float pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor();
2079            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height));
2080            float expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? aspectRatio : 1);
2081            EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
2082            webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(scrollOffset);
2083
2084            WebCore::IntPoint anchorPoint = WebCore::IntPoint(scrollOffset) + WebCore::IntPoint(viewportSize.width / 2, 0);
2085            RefPtrWillBeRawPtr<WebCore::Node> anchorNode = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->eventHandler().hitTestResultAtPoint(anchorPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent).innerNode();
2086            ASSERT(anchorNode);
2087
2088            pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor();
2089            const WebCore::FloatSize preResizeRelativeOffset
2090                = computeRelativeOffset(anchorPoint, anchorNode->boundingBox());
2091            webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width));
2092            WebCore::IntPoint newAnchorPoint = WebCore::IntPoint(webViewHelper.webViewImpl()->mainFrame()->scrollOffset()) + WebCore::IntPoint(viewportSize.height / 2, 0);
2093            const WebCore::FloatSize postResizeRelativeOffset
2094                = computeRelativeOffset(newAnchorPoint, anchorNode->boundingBox());
2095            EXPECT_NEAR(preResizeRelativeOffset.width(), postResizeRelativeOffset.width(), 0.15f);
2096            expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1);
2097            EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f);
2098        }
2099    }
2100};
2101
2102TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth)
2103{
2104    // With width=device-width, pageScaleFactor is preserved across resizes as
2105    // long as the content adjusts according to the device-width.
2106    const char* url = "resize_scroll_mobile.html";
2107    const float initialPageScaleFactor = 1;
2108    const WebSize scrollOffset(0, 50);
2109    const WebSize viewportSize(120, 160);
2110    const bool shouldScaleRelativeToViewportWidth = true;
2111
2112    testResizeYieldsCorrectScrollAndScale(
2113        url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2114}
2115
2116TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedWidth)
2117{
2118    // With a fixed width, pageScaleFactor scales by the relative change in viewport width.
2119    const char* url = "resize_scroll_fixed_width.html";
2120    const float initialPageScaleFactor = 2;
2121    const WebSize scrollOffset(0, 200);
2122    const WebSize viewportSize(240, 320);
2123    const bool shouldScaleRelativeToViewportWidth = true;
2124
2125    testResizeYieldsCorrectScrollAndScale(
2126        url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2127}
2128
2129TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout)
2130{
2131    // With a fixed layout, pageScaleFactor scales by the relative change in viewport width.
2132    const char* url = "resize_scroll_fixed_layout.html";
2133    const float initialPageScaleFactor = 2;
2134    const WebSize scrollOffset(200, 400);
2135    const WebSize viewportSize(320, 240);
2136    const bool shouldScaleRelativeToViewportWidth = true;
2137
2138    testResizeYieldsCorrectScrollAndScale(
2139        url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth);
2140}
2141
2142TEST_F(WebFrameTest, pageScaleFactorScalesPaintClip)
2143{
2144    UseMockScrollbarSettings mockScrollbarSettings;
2145    registerMockedHttpURLLoad("large-div.html");
2146
2147    FixedLayoutTestWebViewClient client;
2148    client.m_screenInfo.deviceScaleFactor = 1;
2149    int viewportWidth = 50;
2150    int viewportHeight = 50;
2151
2152    FrameTestHelpers::WebViewHelper webViewHelper;
2153    webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client);
2154    // FIXME: This test breaks if the viewport is enabled before loading the page due to the paint
2155    // calls below not working on composited layers. For some reason, enabling the viewport here
2156    // doesn't cause compositing
2157    webViewHelper.webView()->settings()->setViewportEnabled(true);
2158    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2159    webViewHelper.webView()->layout();
2160
2161    // Set <1 page scale so that the clip rect should be larger than
2162    // the viewport size as passed into resize().
2163    webViewHelper.webView()->setPageScaleFactor(0.5);
2164
2165    SkBitmap bitmap;
2166    ASSERT_TRUE(bitmap.allocN32Pixels(200, 200));
2167    bitmap.eraseColor(0);
2168    SkCanvas canvas(bitmap);
2169
2170    WebCore::GraphicsContext context(&canvas);
2171    context.setTrackOpaqueRegion(true);
2172
2173    EXPECT_EQ_RECT(WebCore::IntRect(0, 0, 0, 0), context.opaqueRegion().asRect());
2174
2175    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2176    WebCore::IntRect paintRect(0, 0, 200, 200);
2177    view->paint(&context, paintRect);
2178
2179    // FIXME: This test broke in release builds when changing the FixedLayoutTestWebViewClient
2180    // to return a non-null layerTreeView, which is what all our shipping configurations do,
2181    // so this is just exposing an existing bug.
2182    // crbug.com/365812
2183#ifndef NDEBUG
2184    int viewportWidthMinusScrollbar = 50 - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
2185    int viewportHeightMinusScrollbar = 50 - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
2186    WebCore::IntRect clippedRect(0, 0, viewportWidthMinusScrollbar * 2, viewportHeightMinusScrollbar * 2);
2187    EXPECT_EQ_RECT(clippedRect, context.opaqueRegion().asRect());
2188#endif
2189}
2190
2191TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars)
2192{
2193    UseMockScrollbarSettings mockScrollbarSettings;
2194    registerMockedHttpURLLoad("fixed_layout.html");
2195
2196    FixedLayoutTestWebViewClient client;
2197    client.m_screenInfo.deviceScaleFactor = 1;
2198    int viewportWidth = 640;
2199    int viewportHeight = 480;
2200
2201    FrameTestHelpers::WebViewHelper webViewHelper;
2202    webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings);
2203    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2204    webViewHelper.webView()->layout();
2205
2206    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2207    EXPECT_EQ(view->scrollSize(WebCore::HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2208    EXPECT_EQ(view->scrollSize(WebCore::VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2209
2210    webViewHelper.webView()->setPageScaleFactor(10);
2211
2212    EXPECT_EQ(view->scrollSize(WebCore::HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width());
2213    EXPECT_EQ(view->scrollSize(WebCore::VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height());
2214}
2215
2216TEST_F(WebFrameTest, CanOverrideScaleLimits)
2217{
2218    UseMockScrollbarSettings mockScrollbarSettings;
2219
2220    registerMockedHttpURLLoad("no_scale_for_you.html");
2221
2222    FixedLayoutTestWebViewClient client;
2223    client.m_screenInfo.deviceScaleFactor = 1;
2224    int viewportWidth = 640;
2225    int viewportHeight = 480;
2226
2227    FrameTestHelpers::WebViewHelper webViewHelper;
2228    webViewHelper.initializeAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client, enableViewportSettings);
2229    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2230
2231    EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor());
2232    EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor());
2233
2234    webViewHelper.webView()->setIgnoreViewportTagScaleLimits(true);
2235    webViewHelper.webView()->layout();
2236
2237    EXPECT_EQ(1.0f, webViewHelper.webView()->minimumPageScaleFactor());
2238    EXPECT_EQ(5.0f, webViewHelper.webView()->maximumPageScaleFactor());
2239
2240    webViewHelper.webView()->setIgnoreViewportTagScaleLimits(false);
2241    webViewHelper.webView()->layout();
2242
2243    EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor());
2244    EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor());
2245}
2246
2247TEST_F(WebFrameTest, updateOverlayScrollbarLayers)
2248{
2249    UseMockScrollbarSettings mockScrollbarSettings;
2250
2251    registerMockedHttpURLLoad("large-div.html");
2252
2253    int viewWidth = 500;
2254    int viewHeight = 500;
2255
2256    OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
2257    FrameTestHelpers::WebViewHelper webViewHelper;
2258    webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
2259
2260    webViewHelper.webView()->setPageScaleFactorLimits(1, 1);
2261    webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
2262    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html");
2263
2264    WebCore::FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2265    EXPECT_TRUE(view->renderView()->compositor()->layerForHorizontalScrollbar());
2266    EXPECT_TRUE(view->renderView()->compositor()->layerForVerticalScrollbar());
2267
2268    webViewHelper.webView()->resize(WebSize(viewWidth * 10, viewHeight * 10));
2269    webViewHelper.webView()->layout();
2270    EXPECT_FALSE(view->renderView()->compositor()->layerForHorizontalScrollbar());
2271    EXPECT_FALSE(view->renderView()->compositor()->layerForVerticalScrollbar());
2272}
2273
2274void setScaleAndScrollAndLayout(blink::WebView* webView, WebPoint scroll, float scale)
2275{
2276    webView->setPageScaleFactor(scale);
2277    webView->setMainFrameScrollOffset(WebPoint(scroll.x, scroll.y));
2278    webView->layout();
2279}
2280
2281TEST_F(WebFrameTest, DivAutoZoomParamsTest)
2282{
2283    registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_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_scale_for_auto_zoom_into_div_test.html");
2291    webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2292    webViewHelper.webView()->setPageScaleFactorLimits(0.01f, 4);
2293    webViewHelper.webView()->setPageScaleFactor(0.5f);
2294    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2295    webViewHelper.webView()->layout();
2296
2297    WebRect wideDiv(200, 100, 400, 150);
2298    WebRect tallDiv(200, 300, 400, 800);
2299    WebRect doubleTapPointWide(wideDiv.x + 50, wideDiv.y + 50, touchPointPadding, touchPointPadding);
2300    WebRect doubleTapPointTall(tallDiv.x + 50, tallDiv.y + 50, touchPointPadding, touchPointPadding);
2301    WebRect wideBlockBounds;
2302    WebRect tallBlockBounds;
2303    float scale;
2304    WebPoint scroll;
2305
2306    float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2307
2308    // Test double-tap zooming into wide div.
2309    wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false);
2310    webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2311    // The div should horizontally fill the screen (modulo margins), and
2312    // vertically centered (modulo integer rounding).
2313    EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
2314    EXPECT_NEAR(wideDiv.x, scroll.x, 20);
2315    EXPECT_EQ(0, scroll.y);
2316
2317    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
2318
2319    // Test zoom out back to minimum scale.
2320    wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false);
2321    webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2322
2323    scale = webViewHelper.webViewImpl()->minimumPageScaleFactor();
2324    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), scale);
2325
2326    // Test double-tap zooming into tall div.
2327    tallBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointTall, false);
2328    webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointTall.x, doubleTapPointTall.y), tallBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2329    // The div should start at the top left of the viewport.
2330    EXPECT_NEAR(viewportWidth / (float) tallDiv.width, scale, 0.1);
2331    EXPECT_NEAR(tallDiv.x, scroll.x, 20);
2332    EXPECT_NEAR(tallDiv.y, scroll.y, 20);
2333
2334    // Test for Non-doubletap scaling
2335    // Test zooming into div.
2336    webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(250, 250), webViewHelper.webViewImpl()->computeBlockBounds(WebRect(250, 250, 10, 10), true), 0, doubleTapZoomAlreadyLegibleScale, scale, scroll);
2337    EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
2338}
2339
2340void simulatePageScale(WebViewImpl* webViewImpl, float& scale)
2341{
2342    WebCore::IntSize scrollDelta = webViewImpl->fakePageScaleAnimationTargetPositionForTesting() - webViewImpl->mainFrameImpl()->frameView()->scrollPosition();
2343    float scaleDelta = webViewImpl->fakePageScaleAnimationPageScaleForTesting() / webViewImpl->pageScaleFactor();
2344    webViewImpl->applyScrollAndScale(scrollDelta, scaleDelta);
2345    scale = webViewImpl->pageScaleFactor();
2346}
2347
2348void simulateMultiTargetZoom(WebViewImpl* webViewImpl, const WebRect& rect, float& scale)
2349{
2350    if (webViewImpl->zoomToMultipleTargetsRect(rect))
2351        simulatePageScale(webViewImpl, scale);
2352}
2353
2354void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale)
2355{
2356    webViewImpl->animateDoubleTapZoom(point);
2357    EXPECT_TRUE(webViewImpl->fakeDoubleTapAnimationPendingForTesting());
2358    simulatePageScale(webViewImpl, scale);
2359}
2360
2361TEST_F(WebFrameTest, DivAutoZoomWideDivTest)
2362{
2363    registerMockedHttpURLLoad("get_wide_div_for_auto_zoom_test.html");
2364
2365    const float deviceScaleFactor = 2.0f;
2366    int viewportWidth = 640 / deviceScaleFactor;
2367    int viewportHeight = 1280 / deviceScaleFactor;
2368    float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2369    FrameTestHelpers::WebViewHelper webViewHelper;
2370    webViewHelper.initializeAndLoad(m_baseURL + "get_wide_div_for_auto_zoom_test.html");
2371    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2372    webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2373    webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2374    webViewHelper.webView()->setPageScaleFactor(1.0f);
2375    webViewHelper.webView()->layout();
2376
2377    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2378
2379    float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2380
2381    WebRect div(0, 100, viewportWidth, 150);
2382    WebPoint point(div.x + 50, div.y + 50);
2383    float scale;
2384    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2385
2386    simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2387    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2388    simulateDoubleTap(webViewHelper.webViewImpl(), point, scale);
2389    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2390}
2391
2392TEST_F(WebFrameTest, DivAutoZoomVeryTallTest)
2393{
2394    // When a block is taller than the viewport and a zoom targets a lower part
2395    // of it, then we should keep the target point onscreen instead of snapping
2396    // back up the top of the block.
2397    registerMockedHttpURLLoad("very_tall_div.html");
2398
2399    const float deviceScaleFactor = 2.0f;
2400    int viewportWidth = 640 / deviceScaleFactor;
2401    int viewportHeight = 1280 / deviceScaleFactor;
2402    FrameTestHelpers::WebViewHelper webViewHelper;
2403    webViewHelper.initializeAndLoad(m_baseURL + "very_tall_div.html", true, 0, 0, enableViewportSettings);
2404    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2405    webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2406    webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2407    webViewHelper.webView()->setPageScaleFactor(1.0f);
2408    webViewHelper.webView()->layout();
2409
2410    WebRect div(200, 300, 400, 5000);
2411    WebPoint point(div.x + 50, div.y + 3000);
2412    float scale;
2413    WebPoint scroll;
2414
2415    WebRect blockBounds = webViewHelper.webViewImpl()->computeBlockBounds(WebRect(point.x, point.y, 0, 0), true);
2416    webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(point, blockBounds, 0, 1.0f, scale, scroll);
2417    EXPECT_EQ(scale, 1.0f);
2418    EXPECT_EQ(scroll.y, 2660);
2419}
2420
2421TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest)
2422{
2423    registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2424
2425    const float deviceScaleFactor = 2.0f;
2426    int viewportWidth = 640 / deviceScaleFactor;
2427    int viewportHeight = 1280 / deviceScaleFactor;
2428    float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2429    FrameTestHelpers::WebViewHelper webViewHelper;
2430    webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
2431    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2432    webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2433    webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2434    webViewHelper.webView()->setPageScaleFactor(0.5f);
2435    webViewHelper.webView()->layout();
2436
2437    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2438
2439    WebRect topDiv(200, 100, 200, 150);
2440    WebRect bottomDiv(200, 300, 200, 150);
2441    WebPoint topPoint(topDiv.x + 50, topDiv.y + 50);
2442    WebPoint bottomPoint(bottomDiv.x + 50, bottomDiv.y + 50);
2443    float scale;
2444    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2445
2446    // Test double tap on two different divs
2447    // After first zoom, we should go back to minimum page scale with a second double tap.
2448    simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2449    EXPECT_FLOAT_EQ(1, scale);
2450    simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2451    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2452
2453    // If the user pinch zooms after double tap, a second double tap should zoom back to the div.
2454    simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale);
2455    EXPECT_FLOAT_EQ(1, scale);
2456    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 0.6f);
2457    simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2458    EXPECT_FLOAT_EQ(1, scale);
2459    simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2460    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2461
2462    // If we didn't yet get an auto-zoom update and a second double-tap arrives, should go back to minimum scale.
2463    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2464    webViewHelper.webViewImpl()->animateDoubleTapZoom(topPoint);
2465    EXPECT_TRUE(webViewHelper.webViewImpl()->fakeDoubleTapAnimationPendingForTesting());
2466    simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale);
2467    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2468}
2469
2470TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest)
2471{
2472    registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2473
2474    int viewportWidth = 320;
2475    int viewportHeight = 480;
2476    float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2477    FrameTestHelpers::WebViewHelper webViewHelper;
2478    webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
2479    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2480    webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2481    webViewHelper.webView()->layout();
2482
2483    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2484
2485    WebRect div(200, 100, 200, 150);
2486    WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2487    float scale;
2488
2489    // Test double tap scale bounds.
2490    // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1
2491    webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2492    webViewHelper.webView()->layout();
2493    float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2494    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2495    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2496    EXPECT_FLOAT_EQ(1, scale);
2497    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2498    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2499    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2500    EXPECT_FLOAT_EQ(1, scale);
2501
2502    // Zoom in to reset double_tap_zoom_in_effect flag.
2503    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2504    // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2505    webViewHelper.webView()->setPageScaleFactorLimits(1.1f, 4);
2506    webViewHelper.webView()->layout();
2507    doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2508    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2509    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2510    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2511    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2512    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2513    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2514    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2515
2516    // Zoom in to reset double_tap_zoom_in_effect flag.
2517    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2518    // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
2519    webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4);
2520    webViewHelper.webView()->layout();
2521    doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2522    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2523    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2524    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2525    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2526    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2527    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2528    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2529}
2530
2531TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest)
2532{
2533    registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
2534
2535    int viewportWidth = 320;
2536    int viewportHeight = 480;
2537    float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2538    float accessibilityFontScaleFactor = 1.13f;
2539    FrameTestHelpers::WebViewHelper webViewHelper;
2540    webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
2541    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2542    webViewHelper.webView()->layout();
2543
2544    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2545    webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(true);
2546    webViewHelper.webViewImpl()->page()->settings().setAccessibilityFontScaleFactor(accessibilityFontScaleFactor);
2547
2548    WebRect div(200, 100, 200, 150);
2549    WebPoint doubleTapPoint(div.x + 50, div.y + 50);
2550    float scale;
2551
2552    // Test double tap scale bounds.
2553    // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < accessibilityFontScaleFactor
2554    float legibleScale = accessibilityFontScaleFactor;
2555    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2556    float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2557    webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2558    webViewHelper.webView()->layout();
2559    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2560    EXPECT_FLOAT_EQ(legibleScale, scale);
2561    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2562    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2563    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2564    EXPECT_FLOAT_EQ(legibleScale, scale);
2565
2566    // Zoom in to reset double_tap_zoom_in_effect flag.
2567    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2568    // 1 < accessibilityFontScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale
2569    webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4);
2570    webViewHelper.webView()->layout();
2571    doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2572    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2573    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2574    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2575    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2576    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2577    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2578    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2579
2580    // Zoom in to reset double_tap_zoom_in_effect flag.
2581    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2582    // minimumPageScale < 1 < accessibilityFontScaleFactor < doubleTapZoomAlreadyLegibleScale
2583    webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4);
2584    webViewHelper.webView()->layout();
2585    doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2586    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2587    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2588    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2589    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2590    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2591    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2592    EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
2593
2594    // Zoom in to reset double_tap_zoom_in_effect flag.
2595    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.1f);
2596    // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < accessibilityFontScaleFactor
2597    webViewHelper.webView()->setPageScaleFactorLimits(0.9f, 4);
2598    webViewHelper.webView()->layout();
2599    doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
2600    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2601    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2602    EXPECT_FLOAT_EQ(legibleScale, scale);
2603    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2604    EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale);
2605    simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale);
2606    EXPECT_FLOAT_EQ(legibleScale, scale);
2607}
2608
2609TEST_F(WebFrameTest, DivMultipleTargetZoomMultipleDivsTest)
2610{
2611    registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
2612
2613    const float deviceScaleFactor = 2.0f;
2614    int viewportWidth = 640 / deviceScaleFactor;
2615    int viewportHeight = 1280 / deviceScaleFactor;
2616    float doubleTapZoomAlreadyLegibleRatio = 1.2f;
2617    FrameTestHelpers::WebViewHelper webViewHelper;
2618    webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
2619    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2620    webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4);
2621    webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor);
2622    webViewHelper.webView()->setPageScaleFactor(0.5f);
2623    webViewHelper.webView()->layout();
2624
2625    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2626
2627    WebRect viewportRect(0, 0, viewportWidth, viewportHeight);
2628    WebRect topDiv(200, 100, 200, 150);
2629    WebRect bottomDiv(200, 300, 200, 150);
2630    float scale;
2631    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
2632
2633    simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2634    EXPECT_FLOAT_EQ(1, scale);
2635    simulateMultiTargetZoom(webViewHelper.webViewImpl(), bottomDiv, scale);
2636    EXPECT_FLOAT_EQ(1, scale);
2637    simulateMultiTargetZoom(webViewHelper.webViewImpl(), viewportRect, scale);
2638    EXPECT_FLOAT_EQ(1, scale);
2639    webViewHelper.webViewImpl()->setPageScaleFactor(webViewHelper.webViewImpl()->minimumPageScaleFactor());
2640    simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale);
2641    EXPECT_FLOAT_EQ(1, scale);
2642}
2643
2644TEST_F(WebFrameTest, DivScrollIntoEditableTest)
2645{
2646    registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
2647
2648    int viewportWidth = 450;
2649    int viewportHeight = 300;
2650    float leftBoxRatio = 0.3f;
2651    int caretPadding = 10;
2652    float minReadableCaretHeight = 18.0f;
2653    FrameTestHelpers::WebViewHelper webViewHelper;
2654    webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
2655    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2656    webViewHelper.webView()->setPageScaleFactorLimits(1, 4);
2657    webViewHelper.webView()->layout();
2658    webViewHelper.webView()->setDeviceScaleFactor(1.5f);
2659    webViewHelper.webView()->settings()->setAutoZoomFocusedNodeToLegibleScale(true);
2660
2661    webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true);
2662
2663    WebRect editBoxWithText(200, 200, 250, 20);
2664    WebRect editBoxWithNoText(200, 250, 250, 20);
2665
2666    // Test scrolling the focused node
2667    // The edit box is shorter and narrower than the viewport when legible.
2668    webViewHelper.webView()->advanceFocus(false);
2669    // Set the caret to the end of the input box.
2670    webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(1000, 1000);
2671    setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2672    WebRect rect, caret;
2673    webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2674
2675    float scale;
2676    WebCore::IntPoint scroll;
2677    bool needAnimation;
2678    webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2679    EXPECT_TRUE(needAnimation);
2680    // The edit box should be left aligned with a margin for possible label.
2681    int hScroll = editBoxWithText.x - leftBoxRatio * viewportWidth / scale;
2682    EXPECT_NEAR(hScroll, scroll.x(), 1);
2683    int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
2684    EXPECT_NEAR(vScroll, scroll.y(), 1);
2685    EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2686
2687    // The edit box is wider than the viewport when legible.
2688    viewportWidth = 200;
2689    viewportHeight = 150;
2690    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
2691    setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2692    webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2693    webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2694    EXPECT_TRUE(needAnimation);
2695    // The caret should be right aligned since the caret would be offscreen when the edit box is left aligned.
2696    hScroll = caret.x + caret.width + caretPadding - viewportWidth / scale;
2697    EXPECT_NEAR(hScroll, scroll.x(), 1);
2698    EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2699
2700    setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1);
2701    // Move focus to edit box with text.
2702    webViewHelper.webView()->advanceFocus(false);
2703    webViewHelper.webViewImpl()->selectionBounds(caret, rect);
2704    webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2705    EXPECT_TRUE(needAnimation);
2706    // The edit box should be left aligned.
2707    hScroll = editBoxWithNoText.x;
2708    EXPECT_NEAR(hScroll, scroll.x(), 1);
2709    vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2;
2710    EXPECT_NEAR(vScroll, scroll.y(), 1);
2711    EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
2712
2713    setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale);
2714
2715    // Move focus back to the first edit box.
2716    webViewHelper.webView()->advanceFocus(true);
2717    webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation);
2718    // The position should have stayed the same since this box was already on screen with the right scale.
2719    EXPECT_FALSE(needAnimation);
2720}
2721
2722class TestReloadDoesntRedirectWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2723public:
2724    virtual WebNavigationPolicy decidePolicyForNavigation(
2725        WebLocalFrame*, WebDataSource::ExtraData*, const WebURLRequest&, WebNavigationType,
2726        WebNavigationPolicy defaultPolicy, bool isRedirect) OVERRIDE
2727    {
2728        EXPECT_FALSE(isRedirect);
2729        return WebNavigationPolicyCurrentTab;
2730    }
2731};
2732
2733TEST_F(WebFrameTest, ReloadDoesntSetRedirect)
2734{
2735    // Test for case in http://crbug.com/73104. Reloading a frame very quickly
2736    // would sometimes call decidePolicyForNavigation with isRedirect=true
2737    registerMockedHttpURLLoad("form.html");
2738
2739    TestReloadDoesntRedirectWebFrameClient webFrameClient;
2740    FrameTestHelpers::WebViewHelper webViewHelper;
2741    webViewHelper.initializeAndLoad(m_baseURL + "form.html", false, &webFrameClient);
2742
2743    webViewHelper.webView()->mainFrame()->reload(true);
2744    // start another reload before request is delivered.
2745    FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
2746}
2747
2748class ReloadWithOverrideURLTask : public WebThread::Task {
2749public:
2750    ReloadWithOverrideURLTask(WebFrame* frame, const WebCore::KURL& url, bool ignoreCache)
2751        : m_frame(frame), m_url(url), m_ignoreCache(ignoreCache)
2752    {
2753    }
2754
2755    virtual void run() OVERRIDE
2756    {
2757        m_frame->reloadWithOverrideURL(m_url, m_ignoreCache);
2758    }
2759
2760private:
2761    WebFrame* const m_frame;
2762    const WebCore::KURL m_url;
2763    const bool m_ignoreCache;
2764};
2765
2766TEST_F(WebFrameTest, ReloadWithOverrideURLPreservesState)
2767{
2768    const std::string firstURL = "find.html";
2769    const std::string secondURL = "form.html";
2770    const std::string thirdURL = "history.html";
2771    const float pageScaleFactor = 1.1684f;
2772    const int pageWidth = 640;
2773    const int pageHeight = 480;
2774
2775    registerMockedHttpURLLoad(firstURL);
2776    registerMockedHttpURLLoad(secondURL);
2777    registerMockedHttpURLLoad(thirdURL);
2778
2779    FrameTestHelpers::WebViewHelper webViewHelper;
2780    webViewHelper.initializeAndLoad(m_baseURL + firstURL, true);
2781    webViewHelper.webViewImpl()->resize(WebSize(pageWidth, pageHeight));
2782    webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(WebSize(pageWidth / 4, pageHeight / 4));
2783    webViewHelper.webViewImpl()->setPageScaleFactor(pageScaleFactor);
2784
2785    WebSize previousOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset();
2786    float previousScale = webViewHelper.webViewImpl()->pageScaleFactor();
2787
2788    // Reload the page using the cache.
2789    Platform::current()->currentThread()->postTask(
2790        new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + secondURL), false));
2791    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
2792    ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2793    ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor());
2794
2795    // Reload the page while ignoring the cache.
2796    Platform::current()->currentThread()->postTask(
2797        new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + thirdURL), true));
2798    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame());
2799    ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset());
2800    ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor());
2801}
2802
2803TEST_F(WebFrameTest, ReloadWhileProvisional)
2804{
2805    // Test that reloading while the previous load is still pending does not cause the initial
2806    // request to get lost.
2807    registerMockedHttpURLLoad("fixed_layout.html");
2808
2809    FrameTestHelpers::WebViewHelper webViewHelper;
2810    webViewHelper.initialize();
2811    WebURLRequest request;
2812    request.initialize();
2813    request.setURL(toKURL(m_baseURL + "fixed_layout.html"));
2814    webViewHelper.webView()->mainFrame()->loadRequest(request);
2815    // start reload before first request is delivered.
2816    FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
2817
2818    WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
2819    ASSERT_TRUE(dataSource);
2820    EXPECT_EQ(toKURL(m_baseURL + "fixed_layout.html"), toKURL(dataSource->request().url().spec()));
2821}
2822
2823TEST_F(WebFrameTest, AppendRedirects)
2824{
2825    const std::string firstURL = "about:blank";
2826    const std::string secondURL = "http://www.test.com";
2827
2828    FrameTestHelpers::WebViewHelper webViewHelper;
2829    webViewHelper.initializeAndLoad(firstURL, true);
2830
2831    WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource();
2832    ASSERT_TRUE(dataSource);
2833    dataSource->appendRedirect(toKURL(secondURL));
2834
2835    WebVector<WebURL> redirects;
2836    dataSource->redirectChain(redirects);
2837    ASSERT_EQ(2U, redirects.size());
2838    EXPECT_EQ(toKURL(firstURL), toKURL(redirects[0].spec().data()));
2839    EXPECT_EQ(toKURL(secondURL), toKURL(redirects[1].spec().data()));
2840}
2841
2842TEST_F(WebFrameTest, IframeRedirect)
2843{
2844    registerMockedHttpURLLoad("iframe_redirect.html");
2845    registerMockedHttpURLLoad("visible_iframe.html");
2846
2847    FrameTestHelpers::WebViewHelper webViewHelper;
2848    webViewHelper.initializeAndLoad(m_baseURL + "iframe_redirect.html", true);
2849    // Pump pending requests one more time. The test page loads script that navigates.
2850    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
2851
2852    WebFrame* iframe = webViewHelper.webView()->findFrameByName(WebString::fromUTF8("ifr"));
2853    ASSERT_TRUE(iframe);
2854    WebDataSource* iframeDataSource = iframe->dataSource();
2855    ASSERT_TRUE(iframeDataSource);
2856    WebVector<WebURL> redirects;
2857    iframeDataSource->redirectChain(redirects);
2858    ASSERT_EQ(2U, redirects.size());
2859    EXPECT_EQ(toKURL("about:blank"), toKURL(redirects[0].spec().data()));
2860    EXPECT_EQ(toKURL("http://www.test.com/visible_iframe.html"), toKURL(redirects[1].spec().data()));
2861}
2862
2863TEST_F(WebFrameTest, ClearFocusedNodeTest)
2864{
2865    registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
2866    registerMockedHttpURLLoad("autofocus_input_field_iframe.html");
2867
2868    FrameTestHelpers::WebViewHelper webViewHelper;
2869    webViewHelper.initializeAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true);
2870
2871    // Clear the focused node.
2872    webViewHelper.webView()->clearFocusedElement();
2873
2874    // Now retrieve the FocusedNode and test it should be null.
2875    EXPECT_EQ(0, webViewHelper.webViewImpl()->focusedElement());
2876}
2877
2878// Implementation of WebFrameClient that tracks the v8 contexts that are created
2879// and destroyed for verification.
2880class ContextLifetimeTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2881public:
2882    struct Notification {
2883    public:
2884        Notification(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId)
2885            : frame(frame)
2886            , context(context->GetIsolate(), context)
2887            , worldId(worldId)
2888        {
2889        }
2890
2891        ~Notification()
2892        {
2893            context.Reset();
2894        }
2895
2896        bool Equals(Notification* other)
2897        {
2898            return other && frame == other->frame && context == other->context && worldId == other->worldId;
2899        }
2900
2901        WebLocalFrame* frame;
2902        v8::Persistent<v8::Context> context;
2903        int worldId;
2904    };
2905
2906    virtual ~ContextLifetimeTestWebFrameClient()
2907    {
2908        reset();
2909    }
2910
2911    void reset()
2912    {
2913        for (size_t i = 0; i < createNotifications.size(); ++i)
2914            delete createNotifications[i];
2915
2916        for (size_t i = 0; i < releaseNotifications.size(); ++i)
2917            delete releaseNotifications[i];
2918
2919        createNotifications.clear();
2920        releaseNotifications.clear();
2921    }
2922
2923    std::vector<Notification*> createNotifications;
2924    std::vector<Notification*> releaseNotifications;
2925
2926 private:
2927    virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
2928    {
2929        createNotifications.push_back(new Notification(frame, context, worldId));
2930    }
2931
2932    virtual void willReleaseScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId) OVERRIDE
2933    {
2934        releaseNotifications.push_back(new Notification(frame, context, worldId));
2935    }
2936};
2937
2938// TODO(aa): Deflake this test.
2939TEST_F(WebFrameTest, FLAKY_ContextNotificationsLoadUnload)
2940{
2941    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
2942
2943    registerMockedHttpURLLoad("context_notifications_test.html");
2944    registerMockedHttpURLLoad("context_notifications_test_frame.html");
2945
2946    // Load a frame with an iframe, make sure we get the right create notifications.
2947    ContextLifetimeTestWebFrameClient webFrameClient;
2948    FrameTestHelpers::WebViewHelper webViewHelper;
2949    webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
2950
2951    WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
2952    WebFrame* childFrame = mainFrame->firstChild();
2953
2954    ASSERT_EQ(2u, webFrameClient.createNotifications.size());
2955    EXPECT_EQ(0u, webFrameClient.releaseNotifications.size());
2956
2957    ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0];
2958    ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1];
2959
2960    EXPECT_EQ(mainFrame, firstCreateNotification->frame);
2961    EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context);
2962    EXPECT_EQ(0, firstCreateNotification->worldId);
2963
2964    EXPECT_EQ(childFrame, secondCreateNotification->frame);
2965    EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context);
2966    EXPECT_EQ(0, secondCreateNotification->worldId);
2967
2968    // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order.
2969    webViewHelper.reset();
2970
2971    ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
2972    ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0];
2973    ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1];
2974
2975    ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification));
2976    ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification));
2977}
2978
2979TEST_F(WebFrameTest, ContextNotificationsReload)
2980{
2981    v8::HandleScope handleScope(v8::Isolate::GetCurrent());
2982
2983    registerMockedHttpURLLoad("context_notifications_test.html");
2984    registerMockedHttpURLLoad("context_notifications_test_frame.html");
2985
2986    ContextLifetimeTestWebFrameClient webFrameClient;
2987    FrameTestHelpers::WebViewHelper webViewHelper;
2988    webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
2989
2990    // Refresh, we should get two release notifications and two more create notifications.
2991    FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
2992    ASSERT_EQ(4u, webFrameClient.createNotifications.size());
2993    ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
2994
2995    // The two release notifications we got should be exactly the same as the first two create notifications.
2996    for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
2997      EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals(
2998          webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i]));
2999    }
3000
3001    // The last two create notifications should be for the current frames and context.
3002    WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
3003    WebFrame* childFrame = mainFrame->firstChild();
3004    ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2];
3005    ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3];
3006
3007    EXPECT_EQ(mainFrame, firstRefreshNotification->frame);
3008    EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context);
3009    EXPECT_EQ(0, firstRefreshNotification->worldId);
3010
3011    EXPECT_EQ(childFrame, secondRefreshNotification->frame);
3012    EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context);
3013    EXPECT_EQ(0, secondRefreshNotification->worldId);
3014}
3015
3016TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds)
3017{
3018    v8::Isolate* isolate = v8::Isolate::GetCurrent();
3019    v8::HandleScope handleScope(isolate);
3020
3021    registerMockedHttpURLLoad("context_notifications_test.html");
3022    registerMockedHttpURLLoad("context_notifications_test_frame.html");
3023
3024    ContextLifetimeTestWebFrameClient webFrameClient;
3025    FrameTestHelpers::WebViewHelper webViewHelper;
3026    webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
3027
3028    // Add an isolated world.
3029    webFrameClient.reset();
3030
3031    int isolatedWorldId = 42;
3032    WebScriptSource scriptSource("hi!");
3033    int numSources = 1;
3034    int extensionGroup = 0;
3035    webViewHelper.webView()->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup);
3036
3037    // We should now have a new create notification.
3038    ASSERT_EQ(1u, webFrameClient.createNotifications.size());
3039    ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0];
3040    ASSERT_EQ(isolatedWorldId, notification->worldId);
3041    ASSERT_EQ(webViewHelper.webView()->mainFrame(), notification->frame);
3042
3043    // 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.
3044    ASSERT_NE(webViewHelper.webView()->mainFrame()->mainWorldScriptContext(), v8::Local<v8::Context>::New(isolate, notification->context));
3045
3046    webViewHelper.reset();
3047
3048    // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context).
3049    ASSERT_EQ(3u, webFrameClient.releaseNotifications.size());
3050
3051    // And one of them should be exactly the same as the create notification for the isolated context.
3052    int matchCount = 0;
3053    for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
3054      if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0]))
3055        ++matchCount;
3056    }
3057    EXPECT_EQ(1, matchCount);
3058}
3059
3060TEST_F(WebFrameTest, FindInPage)
3061{
3062    registerMockedHttpURLLoad("find.html");
3063    FrameTestHelpers::WebViewHelper webViewHelper;
3064    webViewHelper.initializeAndLoad(m_baseURL + "find.html");
3065    WebFrame* frame = webViewHelper.webView()->mainFrame();
3066    const int findIdentifier = 12345;
3067    WebFindOptions options;
3068
3069    // Find in a <div> element.
3070    EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0));
3071    frame->stopFinding(false);
3072    WebRange range = frame->selectionRange();
3073    EXPECT_EQ(5, range.startOffset());
3074    EXPECT_EQ(9, range.endOffset());
3075    EXPECT_TRUE(frame->document().focusedElement().isNull());
3076
3077    // Find in an <input> value.
3078    EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0));
3079    // Confirm stopFinding(false) sets the selection on the found text.
3080    frame->stopFinding(false);
3081    range = frame->selectionRange();
3082    ASSERT_FALSE(range.isNull());
3083    EXPECT_EQ(5, range.startOffset());
3084    EXPECT_EQ(9, range.endOffset());
3085    EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedElement().tagName());
3086
3087    // Find in a <textarea> content.
3088    EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0));
3089    // Confirm stopFinding(false) sets the selection on the found text.
3090    frame->stopFinding(false);
3091    range = frame->selectionRange();
3092    ASSERT_FALSE(range.isNull());
3093    EXPECT_EQ(5, range.startOffset());
3094    EXPECT_EQ(9, range.endOffset());
3095    EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedElement().tagName());
3096
3097    // Find in a contentEditable element.
3098    EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0));
3099    // Confirm stopFinding(false) sets the selection on the found text.
3100    frame->stopFinding(false);
3101    range = frame->selectionRange();
3102    ASSERT_FALSE(range.isNull());
3103    EXPECT_EQ(0, range.startOffset());
3104    EXPECT_EQ(4, range.endOffset());
3105    // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>.
3106    EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedElement().tagName());
3107
3108    // Find in <select> content.
3109    EXPECT_FALSE(frame->find(findIdentifier, WebString::fromUTF8("bar5"), options, false, 0));
3110    // If there are any matches, stopFinding will set the selection on the found text.
3111    // However, we do not expect any matches, so check that the selection is null.
3112    frame->stopFinding(false);
3113    range = frame->selectionRange();
3114    ASSERT_TRUE(range.isNull());
3115}
3116
3117TEST_F(WebFrameTest, GetContentAsPlainText)
3118{
3119    FrameTestHelpers::WebViewHelper webViewHelper;
3120    webViewHelper.initializeAndLoad("about:blank", true);
3121    // We set the size because it impacts line wrapping, which changes the
3122    // resulting text value.
3123    webViewHelper.webView()->resize(WebSize(640, 480));
3124    WebFrame* frame = webViewHelper.webView()->mainFrame();
3125
3126    // Generate a simple test case.
3127    const char simpleSource[] = "<div>Foo bar</div><div></div>baz";
3128    WebCore::KURL testURL = toKURL("about:blank");
3129    FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3130
3131    // Make sure it comes out OK.
3132    const std::string expected("Foo bar\nbaz");
3133    WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3134    EXPECT_EQ(expected, text.utf8());
3135
3136    // Try reading the same one with clipping of the text.
3137    const int length = 5;
3138    text = frame->contentAsText(length);
3139    EXPECT_EQ(expected.substr(0, length), text.utf8());
3140
3141    // Now do a new test with a subframe.
3142    const char outerFrameSource[] = "Hello<iframe></iframe> world";
3143    FrameTestHelpers::loadHTMLString(frame, outerFrameSource, testURL);
3144
3145    // Load something into the subframe.
3146    WebFrame* subframe = frame->firstChild();
3147    ASSERT_TRUE(subframe);
3148    FrameTestHelpers::loadHTMLString(subframe, "sub<p>text", testURL);
3149
3150    text = frame->contentAsText(std::numeric_limits<size_t>::max());
3151    EXPECT_EQ("Hello world\n\nsub\ntext", text.utf8());
3152
3153    // Get the frame text where the subframe separator falls on the boundary of
3154    // what we'll take. There used to be a crash in this case.
3155    text = frame->contentAsText(12);
3156    EXPECT_EQ("Hello world", text.utf8());
3157}
3158
3159TEST_F(WebFrameTest, GetFullHtmlOfPage)
3160{
3161    FrameTestHelpers::WebViewHelper webViewHelper;
3162    webViewHelper.initializeAndLoad("about:blank", true);
3163    WebFrame* frame = webViewHelper.webView()->mainFrame();
3164
3165    // Generate a simple test case.
3166    const char simpleSource[] = "<p>Hello</p><p>World</p>";
3167    WebCore::KURL testURL = toKURL("about:blank");
3168    FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL);
3169
3170    WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
3171    EXPECT_EQ("Hello\n\nWorld", text.utf8());
3172
3173    const std::string html = frame->contentAsMarkup().utf8();
3174
3175    // Load again with the output html.
3176    FrameTestHelpers::loadHTMLString(frame, html, testURL);
3177
3178    EXPECT_EQ(html, frame->contentAsMarkup().utf8());
3179
3180    text = frame->contentAsText(std::numeric_limits<size_t>::max());
3181    EXPECT_EQ("Hello\n\nWorld", text.utf8());
3182
3183    // Test selection check
3184    EXPECT_FALSE(frame->hasSelection());
3185    frame->executeCommand(WebString::fromUTF8("SelectAll"));
3186    EXPECT_TRUE(frame->hasSelection());
3187    frame->executeCommand(WebString::fromUTF8("Unselect"));
3188    EXPECT_FALSE(frame->hasSelection());
3189    WebString selectionHtml = frame->selectionAsMarkup();
3190    EXPECT_TRUE(selectionHtml.isEmpty());
3191}
3192
3193class TestExecuteScriptDuringDidCreateScriptContext : public FrameTestHelpers::TestWebFrameClient {
3194public:
3195    virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
3196    {
3197        frame->executeScript(WebScriptSource("window.history = 'replaced';"));
3198    }
3199};
3200
3201TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext)
3202{
3203    registerMockedHttpURLLoad("hello_world.html");
3204
3205    TestExecuteScriptDuringDidCreateScriptContext webFrameClient;
3206    FrameTestHelpers::WebViewHelper webViewHelper;
3207    webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient);
3208
3209    FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
3210}
3211
3212class FindUpdateWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3213public:
3214    FindUpdateWebFrameClient()
3215        : m_findResultsAreReady(false)
3216        , m_count(-1)
3217    {
3218    }
3219
3220    virtual void reportFindInPageMatchCount(int, int count, bool finalUpdate) OVERRIDE
3221    {
3222        m_count = count;
3223        if (finalUpdate)
3224            m_findResultsAreReady = true;
3225    }
3226
3227    bool findResultsAreReady() const { return m_findResultsAreReady; }
3228    int count() const { return m_count; }
3229
3230private:
3231    bool m_findResultsAreReady;
3232    int m_count;
3233};
3234
3235// This fails on Mac https://bugs.webkit.org/show_bug.cgi?id=108574
3236// Also failing on Android: http://crbug.com/341314
3237#if OS(MACOSX) || OS(ANDROID)
3238TEST_F(WebFrameTest, DISABLED_FindInPageMatchRects)
3239#else
3240TEST_F(WebFrameTest, FindInPageMatchRects)
3241#endif
3242{
3243    registerMockedHttpURLLoad("find_in_page.html");
3244    registerMockedHttpURLLoad("find_in_page_frame.html");
3245
3246    FindUpdateWebFrameClient client;
3247    FrameTestHelpers::WebViewHelper webViewHelper;
3248    webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3249    webViewHelper.webView()->resize(WebSize(640, 480));
3250    webViewHelper.webView()->layout();
3251    runPendingTasks();
3252
3253    // Note that the 'result 19' in the <select> element is not expected to produce a match.
3254    static const char* kFindString = "result";
3255    static const int kFindIdentifier = 12345;
3256    static const int kNumResults = 19;
3257
3258    WebFindOptions options;
3259    WebString searchText = WebString::fromUTF8(kFindString);
3260    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3261    EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3262
3263    mainFrame->resetMatchCount();
3264
3265    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3266        frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3267
3268    runPendingTasks();
3269    EXPECT_TRUE(client.findResultsAreReady());
3270
3271    WebVector<WebFloatRect> webMatchRects;
3272    mainFrame->findMatchRects(webMatchRects);
3273    ASSERT_EQ(webMatchRects.size(), static_cast<size_t>(kNumResults));
3274    int rectsVersion = mainFrame->findMatchMarkersVersion();
3275
3276    for (int resultIndex = 0; resultIndex < kNumResults; ++resultIndex) {
3277        FloatRect resultRect = static_cast<FloatRect>(webMatchRects[resultIndex]);
3278
3279        // Select the match by the center of its rect.
3280        EXPECT_EQ(mainFrame->selectNearestFindMatch(resultRect.center(), 0), resultIndex + 1);
3281
3282        // Check that the find result ordering matches with our expectations.
3283        Range* result = mainFrame->activeMatchFrame()->activeMatch();
3284        ASSERT_TRUE(result);
3285        result->setEnd(result->endContainer(), result->endOffset() + 3);
3286        EXPECT_EQ(result->text(), String::format("%s %02d", kFindString, resultIndex));
3287
3288        // Verify that the expected match rect also matches the currently active match.
3289        // Compare the enclosing rects to prevent precision issues caused by CSS transforms.
3290        FloatRect activeMatch = mainFrame->activeFindMatchRect();
3291        EXPECT_EQ(enclosingIntRect(activeMatch), enclosingIntRect(resultRect));
3292
3293        // The rects version should not have changed.
3294        EXPECT_EQ(mainFrame->findMatchMarkersVersion(), rectsVersion);
3295    }
3296
3297    // All results after the first two ones should be below between them in find-in-page coordinates.
3298    // This is because results 2 to 9 are inside an iframe located between results 0 and 1. This applies to the fixed div too.
3299    EXPECT_TRUE(webMatchRects[0].y < webMatchRects[1].y);
3300    for (int resultIndex = 2; resultIndex < kNumResults; ++resultIndex) {
3301        EXPECT_TRUE(webMatchRects[0].y < webMatchRects[resultIndex].y);
3302        EXPECT_TRUE(webMatchRects[1].y > webMatchRects[resultIndex].y);
3303    }
3304
3305    // Result 3 should be below both 2 and 4. This is caused by the CSS transform in the containing div.
3306    // If the transform doesn't work then 3 will be between 2 and 4.
3307    EXPECT_TRUE(webMatchRects[3].y > webMatchRects[2].y);
3308    EXPECT_TRUE(webMatchRects[3].y > webMatchRects[4].y);
3309
3310    // Results 6, 7, 8 and 9 should be one below the other in that same order.
3311    // If overflow:scroll is not properly handled then result 8 would be below result 9 or
3312    // result 7 above result 6 depending on the scroll.
3313    EXPECT_TRUE(webMatchRects[6].y < webMatchRects[7].y);
3314    EXPECT_TRUE(webMatchRects[7].y < webMatchRects[8].y);
3315    EXPECT_TRUE(webMatchRects[8].y < webMatchRects[9].y);
3316
3317    // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are inside the table.
3318    EXPECT_TRUE(webMatchRects[11].y > webMatchRects[10].y);
3319    EXPECT_TRUE(webMatchRects[12].y > webMatchRects[10].y);
3320    EXPECT_TRUE(webMatchRects[13].y > webMatchRects[10].y);
3321    EXPECT_TRUE(webMatchRects[14].y > webMatchRects[10].y);
3322    EXPECT_TRUE(webMatchRects[11].y < webMatchRects[15].y);
3323    EXPECT_TRUE(webMatchRects[12].y < webMatchRects[15].y);
3324    EXPECT_TRUE(webMatchRects[13].y < webMatchRects[15].y);
3325    EXPECT_TRUE(webMatchRects[14].y < webMatchRects[15].y);
3326
3327    // Result 11 should be above 12, 13 and 14 as it's in the table header.
3328    EXPECT_TRUE(webMatchRects[11].y < webMatchRects[12].y);
3329    EXPECT_TRUE(webMatchRects[11].y < webMatchRects[13].y);
3330    EXPECT_TRUE(webMatchRects[11].y < webMatchRects[14].y);
3331
3332    // Result 11 should also be right to 12, 13 and 14 because of the colspan.
3333    EXPECT_TRUE(webMatchRects[11].x > webMatchRects[12].x);
3334    EXPECT_TRUE(webMatchRects[11].x > webMatchRects[13].x);
3335    EXPECT_TRUE(webMatchRects[11].x > webMatchRects[14].x);
3336
3337    // Result 12 should be left to results 11, 13 and 14 in the table layout.
3338    EXPECT_TRUE(webMatchRects[12].x < webMatchRects[11].x);
3339    EXPECT_TRUE(webMatchRects[12].x < webMatchRects[13].x);
3340    EXPECT_TRUE(webMatchRects[12].x < webMatchRects[14].x);
3341
3342    // Results 13, 12 and 14 should be one above the other in that order because of the rowspan
3343    // and vertical-align: middle by default.
3344    EXPECT_TRUE(webMatchRects[13].y < webMatchRects[12].y);
3345    EXPECT_TRUE(webMatchRects[12].y < webMatchRects[14].y);
3346
3347    // Result 16 should be below result 15.
3348    EXPECT_TRUE(webMatchRects[15].y > webMatchRects[14].y);
3349
3350    // Result 18 should be normalized with respect to the position:relative div, and not it's
3351    // immediate containing div. Consequently, result 18 should be above result 17.
3352    EXPECT_TRUE(webMatchRects[17].y > webMatchRects[18].y);
3353
3354    // Resizing should update the rects version.
3355    webViewHelper.webView()->resize(WebSize(800, 600));
3356    runPendingTasks();
3357    EXPECT_TRUE(mainFrame->findMatchMarkersVersion() != rectsVersion);
3358}
3359
3360TEST_F(WebFrameTest, FindInPageSkipsHiddenFrames)
3361{
3362    registerMockedHttpURLLoad("find_in_hidden_frame.html");
3363
3364    FindUpdateWebFrameClient client;
3365    FrameTestHelpers::WebViewHelper webViewHelper;
3366    webViewHelper.initializeAndLoad(m_baseURL + "find_in_hidden_frame.html", true, &client);
3367    webViewHelper.webView()->resize(WebSize(640, 480));
3368    webViewHelper.webView()->layout();
3369    runPendingTasks();
3370
3371    static const char* kFindString = "hello";
3372    static const int kFindIdentifier = 12345;
3373    static const int kNumResults = 1;
3374
3375    WebFindOptions options;
3376    WebString searchText = WebString::fromUTF8(kFindString);
3377    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3378    EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3379
3380    mainFrame->resetMatchCount();
3381
3382    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3383        frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3384
3385    runPendingTasks();
3386    EXPECT_TRUE(client.findResultsAreReady());
3387    EXPECT_EQ(kNumResults, client.count());
3388}
3389
3390TEST_F(WebFrameTest, FindOnDetachedFrame)
3391{
3392    registerMockedHttpURLLoad("find_in_page.html");
3393    registerMockedHttpURLLoad("find_in_page_frame.html");
3394
3395    FindUpdateWebFrameClient client;
3396    FrameTestHelpers::WebViewHelper webViewHelper;
3397    webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3398    webViewHelper.webView()->resize(WebSize(640, 480));
3399    webViewHelper.webView()->layout();
3400    runPendingTasks();
3401
3402    static const char* kFindString = "result";
3403    static const int kFindIdentifier = 12345;
3404
3405    WebFindOptions options;
3406    WebString searchText = WebString::fromUTF8(kFindString);
3407    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3408    RefPtr<WebLocalFrameImpl> secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3409    RefPtr<WebCore::LocalFrame> holdSecondFrame = secondFrame->frame();
3410
3411    // Detach the frame before finding.
3412    EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3413
3414    EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3415    EXPECT_FALSE(secondFrame->find(kFindIdentifier, searchText, options, false, 0));
3416
3417    runPendingTasks();
3418    EXPECT_FALSE(client.findResultsAreReady());
3419
3420    mainFrame->resetMatchCount();
3421
3422    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3423        frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3424
3425    runPendingTasks();
3426    EXPECT_TRUE(client.findResultsAreReady());
3427
3428    holdSecondFrame.release();
3429}
3430
3431TEST_F(WebFrameTest, FindDetachFrameBeforeScopeStrings)
3432{
3433    registerMockedHttpURLLoad("find_in_page.html");
3434    registerMockedHttpURLLoad("find_in_page_frame.html");
3435
3436    FindUpdateWebFrameClient client;
3437    FrameTestHelpers::WebViewHelper webViewHelper;
3438    webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3439    webViewHelper.webView()->resize(WebSize(640, 480));
3440    webViewHelper.webView()->layout();
3441    runPendingTasks();
3442
3443    static const char* kFindString = "result";
3444    static const int kFindIdentifier = 12345;
3445
3446    WebFindOptions options;
3447    WebString searchText = WebString::fromUTF8(kFindString);
3448    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3449    WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3450    RefPtr<WebCore::LocalFrame> holdSecondFrame = secondFrame->frame();
3451
3452    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3453        EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
3454
3455    runPendingTasks();
3456    EXPECT_FALSE(client.findResultsAreReady());
3457
3458    // Detach the frame between finding and scoping.
3459    EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3460
3461    mainFrame->resetMatchCount();
3462
3463    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3464        frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3465
3466    runPendingTasks();
3467    EXPECT_TRUE(client.findResultsAreReady());
3468
3469    holdSecondFrame.release();
3470}
3471
3472TEST_F(WebFrameTest, FindDetachFrameWhileScopingStrings)
3473{
3474    registerMockedHttpURLLoad("find_in_page.html");
3475    registerMockedHttpURLLoad("find_in_page_frame.html");
3476
3477    FindUpdateWebFrameClient client;
3478    FrameTestHelpers::WebViewHelper webViewHelper;
3479    webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client);
3480    webViewHelper.webView()->resize(WebSize(640, 480));
3481    webViewHelper.webView()->layout();
3482    runPendingTasks();
3483
3484    static const char* kFindString = "result";
3485    static const int kFindIdentifier = 12345;
3486
3487    WebFindOptions options;
3488    WebString searchText = WebString::fromUTF8(kFindString);
3489    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3490    WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false));
3491    RefPtr<WebCore::LocalFrame> holdSecondFrame = secondFrame->frame();
3492
3493    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3494        EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
3495
3496    runPendingTasks();
3497    EXPECT_FALSE(client.findResultsAreReady());
3498
3499    mainFrame->resetMatchCount();
3500
3501    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
3502        frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3503
3504    // The first scopeStringMatches will have reset the state. Detach before it actually scopes.
3505    EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
3506
3507    runPendingTasks();
3508    EXPECT_TRUE(client.findResultsAreReady());
3509
3510    holdSecondFrame.release();
3511}
3512
3513TEST_F(WebFrameTest, ResetMatchCount)
3514{
3515    registerMockedHttpURLLoad("find_in_generated_frame.html");
3516
3517    FindUpdateWebFrameClient client;
3518    FrameTestHelpers::WebViewHelper webViewHelper;
3519    webViewHelper.initializeAndLoad(m_baseURL + "find_in_generated_frame.html", true, &client);
3520    webViewHelper.webView()->resize(WebSize(640, 480));
3521    webViewHelper.webView()->layout();
3522    runPendingTasks();
3523
3524    static const char* kFindString = "result";
3525    static const int kFindIdentifier = 12345;
3526
3527    WebFindOptions options;
3528    WebString searchText = WebString::fromUTF8(kFindString);
3529    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3530
3531    // Check that child frame exists.
3532    EXPECT_TRUE(!!mainFrame->traverseNext(false));
3533
3534    for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) {
3535        EXPECT_FALSE(frame->find(kFindIdentifier, searchText, options, false, 0));
3536    }
3537
3538    runPendingTasks();
3539    EXPECT_FALSE(client.findResultsAreReady());
3540
3541    mainFrame->resetMatchCount();
3542}
3543
3544TEST_F(WebFrameTest, SetTickmarks)
3545{
3546    registerMockedHttpURLLoad("find.html");
3547
3548    FindUpdateWebFrameClient client;
3549    FrameTestHelpers::WebViewHelper webViewHelper;
3550    webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client);
3551    webViewHelper.webView()->resize(WebSize(640, 480));
3552    webViewHelper.webView()->layout();
3553    runPendingTasks();
3554
3555    static const char* kFindString = "foo";
3556    static const int kFindIdentifier = 12345;
3557
3558    WebFindOptions options;
3559    WebString searchText = WebString::fromUTF8(kFindString);
3560    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3561    EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3562
3563    mainFrame->resetMatchCount();
3564    mainFrame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3565
3566    runPendingTasks();
3567    EXPECT_TRUE(client.findResultsAreReady());
3568
3569    // Get the tickmarks for the original find request.
3570    WebCore::FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
3571    RefPtr<WebCore::Scrollbar> scrollbar = frameView->createScrollbar(WebCore::HorizontalScrollbar);
3572    Vector<WebCore::IntRect> originalTickmarks;
3573    scrollbar->getTickmarks(originalTickmarks);
3574    EXPECT_EQ(4u, originalTickmarks.size());
3575
3576    // Override the tickmarks.
3577    Vector<WebCore::IntRect> overridingTickmarksExpected;
3578    overridingTickmarksExpected.append(WebCore::IntRect(0, 0, 100, 100));
3579    overridingTickmarksExpected.append(WebCore::IntRect(0, 20, 100, 100));
3580    overridingTickmarksExpected.append(WebCore::IntRect(0, 30, 100, 100));
3581    mainFrame->setTickmarks(overridingTickmarksExpected);
3582
3583    // Check the tickmarks are overriden correctly.
3584    Vector<WebCore::IntRect> overridingTickmarksActual;
3585    scrollbar->getTickmarks(overridingTickmarksActual);
3586    EXPECT_EQ(overridingTickmarksExpected, overridingTickmarksActual);
3587
3588    // Reset the tickmark behavior.
3589    Vector<WebCore::IntRect> resetTickmarks;
3590    mainFrame->setTickmarks(resetTickmarks);
3591
3592    // Check that the original tickmarks are returned
3593    Vector<WebCore::IntRect> originalTickmarksAfterReset;
3594    scrollbar->getTickmarks(originalTickmarksAfterReset);
3595    EXPECT_EQ(originalTickmarks, originalTickmarksAfterReset);
3596}
3597
3598static WebPoint topLeft(const WebRect& rect)
3599{
3600    return WebPoint(rect.x, rect.y);
3601}
3602
3603static WebPoint bottomRightMinusOne(const WebRect& rect)
3604{
3605    // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
3606    // selection bounds, selectRange() will select the *next* element. That's
3607    // strictly correct, as hit-testing checks the pixel to the lower-right of
3608    // the input coordinate, but it's a wart on the API.
3609    return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1);
3610}
3611
3612static WebRect elementBounds(WebFrame* frame, const WebString& id)
3613{
3614    return frame->document().getElementById(id).boundsInViewportSpace();
3615}
3616
3617static std::string selectionAsString(WebFrame* frame)
3618{
3619    return frame->selectionAsText().utf8();
3620}
3621
3622TEST_F(WebFrameTest, SelectRange)
3623{
3624    WebFrame* frame;
3625    WebRect startWebRect;
3626    WebRect endWebRect;
3627
3628    registerMockedHttpURLLoad("select_range_basic.html");
3629    registerMockedHttpURLLoad("select_range_scroll.html");
3630
3631    FrameTestHelpers::WebViewHelper webViewHelper;
3632    initializeTextSelectionWebView(m_baseURL + "select_range_basic.html", &webViewHelper);
3633    frame = webViewHelper.webView()->mainFrame();
3634    EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3635    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3636    frame->executeCommand(WebString::fromUTF8("Unselect"));
3637    EXPECT_EQ("", selectionAsString(frame));
3638    frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3639    EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3640
3641    initializeTextSelectionWebView(m_baseURL + "select_range_scroll.html", &webViewHelper);
3642    frame = webViewHelper.webView()->mainFrame();
3643    EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3644    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3645    frame->executeCommand(WebString::fromUTF8("Unselect"));
3646    EXPECT_EQ("", selectionAsString(frame));
3647    frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3648    EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3649}
3650
3651TEST_F(WebFrameTest, SelectRangeInIframe)
3652{
3653    WebFrame* frame;
3654    WebRect startWebRect;
3655    WebRect endWebRect;
3656
3657    registerMockedHttpURLLoad("select_range_iframe.html");
3658    registerMockedHttpURLLoad("select_range_basic.html");
3659
3660    FrameTestHelpers::WebViewHelper webViewHelper;
3661    initializeTextSelectionWebView(m_baseURL + "select_range_iframe.html", &webViewHelper);
3662    frame = webViewHelper.webView()->mainFrame();
3663    WebFrame* subframe = frame->firstChild();
3664    EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3665    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3666    subframe->executeCommand(WebString::fromUTF8("Unselect"));
3667    EXPECT_EQ("", selectionAsString(subframe));
3668    subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3669    EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3670}
3671
3672TEST_F(WebFrameTest, SelectRangeDivContentEditable)
3673{
3674    WebFrame* frame;
3675    WebRect startWebRect;
3676    WebRect endWebRect;
3677
3678    registerMockedHttpURLLoad("select_range_div_editable.html");
3679
3680    // Select the middle of an editable element, then try to extend the selection to the top of the document.
3681    // The selection range should be clipped to the bounds of the editable element.
3682    FrameTestHelpers::WebViewHelper webViewHelper;
3683    initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3684    frame = webViewHelper.webView()->mainFrame();
3685    EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3686    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3687
3688    frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3689    EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3690
3691    // As above, but extending the selection to the bottom of the document.
3692    initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3693    frame = webViewHelper.webView()->mainFrame();
3694
3695    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3696    frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3697    EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3698    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3699
3700    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3701    frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3702    EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3703}
3704
3705// positionForPoint returns the wrong values for contenteditable spans. See
3706// http://crbug.com/238334.
3707TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable)
3708{
3709    WebFrame* frame;
3710    WebRect startWebRect;
3711    WebRect endWebRect;
3712
3713    registerMockedHttpURLLoad("select_range_span_editable.html");
3714
3715    // Select the middle of an editable element, then try to extend the selection to the top of the document.
3716    // The selection range should be clipped to the bounds of the editable element.
3717    FrameTestHelpers::WebViewHelper webViewHelper;
3718    initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3719    frame = webViewHelper.webView()->mainFrame();
3720    EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3721    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3722
3723    frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3724    EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3725
3726    // As above, but extending the selection to the bottom of the document.
3727    initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3728    frame = webViewHelper.webView()->mainFrame();
3729
3730    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3731    frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3732    EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3733    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3734
3735    EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3736    webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3737    frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3738    EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3739}
3740
3741TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart)
3742{
3743    registerMockedHttpURLLoad("text_selection.html");
3744    FrameTestHelpers::WebViewHelper webViewHelper;
3745    initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3746    WebFrame* frame = webViewHelper.webView()->mainFrame();
3747
3748    // Select second span. We can move the start to include the first span.
3749    frame->executeScript(WebScriptSource("selectElement('header_2');"));
3750    EXPECT_EQ("Header 2.", selectionAsString(frame));
3751    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3752    EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3753
3754    // We can move the start and end together.
3755    frame->executeScript(WebScriptSource("selectElement('header_1');"));
3756    EXPECT_EQ("Header 1.", selectionAsString(frame));
3757    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1")));
3758    EXPECT_EQ("", selectionAsString(frame));
3759    // Selection is a caret, not empty.
3760    EXPECT_FALSE(frame->selectionRange().isNull());
3761
3762    // We can move the start across the end.
3763    frame->executeScript(WebScriptSource("selectElement('header_1');"));
3764    EXPECT_EQ("Header 1.", selectionAsString(frame));
3765    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3766    EXPECT_EQ(" Header 2.", selectionAsString(frame));
3767
3768    // Can't extend the selection part-way into an editable element.
3769    frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3770    EXPECT_EQ("Footer 2.", selectionAsString(frame));
3771    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2")));
3772    EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame));
3773
3774    // Can extend the selection completely across editable elements.
3775    frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3776    EXPECT_EQ("Footer 2.", selectionAsString(frame));
3777    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2")));
3778    EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame));
3779
3780    // If the selection is editable text, we can't extend it into non-editable text.
3781    frame->executeScript(WebScriptSource("selectElement('editable_2');"));
3782    EXPECT_EQ("Editable 2.", selectionAsString(frame));
3783    frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2")));
3784    // positionForPoint returns the wrong values for contenteditable spans. See
3785    // http://crbug.com/238334.
3786    // EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame));
3787}
3788
3789TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd)
3790{
3791    registerMockedHttpURLLoad("text_selection.html");
3792    FrameTestHelpers::WebViewHelper webViewHelper;
3793    initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3794    WebFrame* frame = webViewHelper.webView()->mainFrame();
3795
3796    // Select first span. We can move the end to include the second span.
3797    frame->executeScript(WebScriptSource("selectElement('header_1');"));
3798    EXPECT_EQ("Header 1.", selectionAsString(frame));
3799    frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3800    EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3801
3802    // We can move the start and end together.
3803    frame->executeScript(WebScriptSource("selectElement('header_2');"));
3804    EXPECT_EQ("Header 2.", selectionAsString(frame));
3805    frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2")));
3806    EXPECT_EQ("", selectionAsString(frame));
3807    // Selection is a caret, not empty.
3808    EXPECT_FALSE(frame->selectionRange().isNull());
3809
3810    // We can move the end across the start.
3811    frame->executeScript(WebScriptSource("selectElement('header_2');"));
3812    EXPECT_EQ("Header 2.", selectionAsString(frame));
3813    frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3814    EXPECT_EQ("Header 1. ", selectionAsString(frame));
3815
3816    // Can't extend the selection part-way into an editable element.
3817    frame->executeScript(WebScriptSource("selectElement('header_1');"));
3818    EXPECT_EQ("Header 1.", selectionAsString(frame));
3819    frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1")));
3820    EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame));
3821
3822    // Can extend the selection completely across editable elements.
3823    frame->executeScript(WebScriptSource("selectElement('header_1');"));
3824    EXPECT_EQ("Header 1.", selectionAsString(frame));
3825    frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3826    EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame));
3827
3828    // If the selection is editable text, we can't extend it into non-editable text.
3829    frame->executeScript(WebScriptSource("selectElement('editable_1');"));
3830    EXPECT_EQ("Editable 1.", selectionAsString(frame));
3831    frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3832    // positionForPoint returns the wrong values for contenteditable spans. See
3833    // http://crbug.com/238334.
3834    // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
3835}
3836
3837static int computeOffset(WebCore::RenderObject* renderer, int x, int y)
3838{
3839    return WebCore::VisiblePosition(renderer->positionForPoint(WebCore::LayoutPoint(x, y))).deepEquivalent().computeOffsetInContainerNode();
3840}
3841
3842// positionForPoint returns the wrong values for contenteditable spans. See
3843// http://crbug.com/238334.
3844TEST_F(WebFrameTest, DISABLED_PositionForPointTest)
3845{
3846    registerMockedHttpURLLoad("select_range_span_editable.html");
3847    FrameTestHelpers::WebViewHelper webViewHelper;
3848    initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3849    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3850    WebCore::RenderObject* renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3851    EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3852    EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3853
3854    registerMockedHttpURLLoad("select_range_div_editable.html");
3855    initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3856    mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3857    renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3858    EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3859    EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3860}
3861
3862#if !OS(MACOSX) && !OS(LINUX)
3863TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved)
3864{
3865    registerMockedHttpURLLoad("move_caret.html");
3866
3867    FrameTestHelpers::WebViewHelper webViewHelper;
3868    initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3869    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3870
3871    WebRect initialStartRect;
3872    WebRect initialEndRect;
3873    WebRect startRect;
3874    WebRect endRect;
3875
3876    frame->executeScript(WebScriptSource("selectRange();"));
3877    webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3878    WebPoint movedStart(topLeft(initialStartRect));
3879
3880    movedStart.y += 40;
3881    frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3882    webViewHelper.webView()->selectionBounds(startRect, endRect);
3883    EXPECT_EQ(startRect, initialStartRect);
3884    EXPECT_EQ(endRect, initialEndRect);
3885
3886    movedStart.y -= 80;
3887    frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3888    webViewHelper.webView()->selectionBounds(startRect, endRect);
3889    EXPECT_EQ(startRect, initialStartRect);
3890    EXPECT_EQ(endRect, initialEndRect);
3891
3892    WebPoint movedEnd(bottomRightMinusOne(initialEndRect));
3893
3894    movedEnd.y += 40;
3895    frame->selectRange(topLeft(initialStartRect), movedEnd);
3896    webViewHelper.webView()->selectionBounds(startRect, endRect);
3897    EXPECT_EQ(startRect, initialStartRect);
3898    EXPECT_EQ(endRect, initialEndRect);
3899
3900    movedEnd.y -= 80;
3901    frame->selectRange(topLeft(initialStartRect), movedEnd);
3902    webViewHelper.webView()->selectionBounds(startRect, endRect);
3903    EXPECT_EQ(startRect, initialStartRect);
3904    EXPECT_EQ(endRect, initialEndRect);
3905}
3906
3907TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved)
3908{
3909    WebLocalFrameImpl* frame;
3910    registerMockedHttpURLLoad("move_caret.html");
3911
3912    FrameTestHelpers::WebViewHelper webViewHelper;
3913    initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3914    frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
3915
3916    WebRect initialStartRect;
3917    WebRect initialEndRect;
3918    WebRect startRect;
3919    WebRect endRect;
3920
3921    frame->executeScript(WebScriptSource("selectCaret();"));
3922    webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3923    WebPoint moveTo(topLeft(initialStartRect));
3924
3925    moveTo.y += 40;
3926    frame->moveCaretSelection(moveTo);
3927    webViewHelper.webView()->selectionBounds(startRect, endRect);
3928    EXPECT_EQ(startRect, initialStartRect);
3929    EXPECT_EQ(endRect, initialEndRect);
3930
3931    moveTo.y -= 80;
3932    frame->moveCaretSelection(moveTo);
3933    webViewHelper.webView()->selectionBounds(startRect, endRect);
3934    EXPECT_EQ(startRect, initialStartRect);
3935    EXPECT_EQ(endRect, initialEndRect);
3936}
3937#endif
3938
3939class DisambiguationPopupTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
3940public:
3941    virtual bool didTapMultipleTargets(const WebGestureEvent&, const WebVector<WebRect>& targetRects) OVERRIDE
3942    {
3943        EXPECT_GE(targetRects.size(), 2u);
3944        m_triggered = true;
3945        return true;
3946    }
3947
3948    bool triggered() const { return m_triggered; }
3949    void resetTriggered() { m_triggered = false; }
3950    bool m_triggered;
3951};
3952
3953static WebGestureEvent fatTap(int x, int y)
3954{
3955    WebGestureEvent event;
3956    event.type = WebInputEvent::GestureTap;
3957    event.x = x;
3958    event.y = y;
3959    event.data.tap.width = 50;
3960    event.data.tap.height = 50;
3961    return event;
3962}
3963
3964TEST_F(WebFrameTest, DisambiguationPopup)
3965{
3966    const std::string htmlFile = "disambiguation_popup.html";
3967    registerMockedHttpURLLoad(htmlFile);
3968
3969    DisambiguationPopupTestWebViewClient client;
3970
3971    // Make sure we initialize to minimum scale, even if the window size
3972    // only becomes available after the load begins.
3973    FrameTestHelpers::WebViewHelper webViewHelper;
3974    webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
3975    webViewHelper.webView()->resize(WebSize(1000, 1000));
3976    webViewHelper.webView()->layout();
3977
3978    client.resetTriggered();
3979    webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
3980    EXPECT_FALSE(client.triggered());
3981
3982    client.resetTriggered();
3983    webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
3984    EXPECT_FALSE(client.triggered());
3985
3986    for (int i = 0; i <= 46; i++) {
3987        client.resetTriggered();
3988        webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
3989
3990        int j = i % 10;
3991        if (j >= 7 && j <= 9)
3992            EXPECT_TRUE(client.triggered());
3993        else
3994            EXPECT_FALSE(client.triggered());
3995    }
3996
3997    for (int i = 0; i <= 46; i++) {
3998        client.resetTriggered();
3999        webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4000
4001        int j = i % 10;
4002        if (j >= 7 && j <= 9)
4003            EXPECT_TRUE(client.triggered());
4004        else
4005            EXPECT_FALSE(client.triggered());
4006    }
4007}
4008
4009TEST_F(WebFrameTest, DisambiguationPopupNoContainer)
4010{
4011    registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
4012
4013    DisambiguationPopupTestWebViewClient client;
4014
4015    // Make sure we initialize to minimum scale, even if the window size
4016    // only becomes available after the load begins.
4017    FrameTestHelpers::WebViewHelper webViewHelper;
4018    webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_no_container.html", true, 0, &client);
4019    webViewHelper.webView()->resize(WebSize(1000, 1000));
4020    webViewHelper.webView()->layout();
4021
4022    client.resetTriggered();
4023    webViewHelper.webView()->handleInputEvent(fatTap(50, 50));
4024    EXPECT_FALSE(client.triggered());
4025}
4026
4027TEST_F(WebFrameTest, DisambiguationPopupMobileSite)
4028{
4029    UseMockScrollbarSettings mockScrollbarSettings;
4030    const std::string htmlFile = "disambiguation_popup_mobile_site.html";
4031    registerMockedHttpURLLoad(htmlFile);
4032
4033    DisambiguationPopupTestWebViewClient client;
4034
4035    // Make sure we initialize to minimum scale, even if the window size
4036    // only becomes available after the load begins.
4037    FrameTestHelpers::WebViewHelper webViewHelper;
4038    webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4039    webViewHelper.webView()->resize(WebSize(1000, 1000));
4040    webViewHelper.webView()->layout();
4041
4042    client.resetTriggered();
4043    webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4044    EXPECT_FALSE(client.triggered());
4045
4046    client.resetTriggered();
4047    webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4048    EXPECT_FALSE(client.triggered());
4049
4050    for (int i = 0; i <= 46; i++) {
4051        client.resetTriggered();
4052        webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4053        EXPECT_FALSE(client.triggered());
4054    }
4055
4056    for (int i = 0; i <= 46; i++) {
4057        client.resetTriggered();
4058        webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4059        EXPECT_FALSE(client.triggered());
4060    }
4061}
4062
4063TEST_F(WebFrameTest, DisambiguationPopupViewportSite)
4064{
4065    UseMockScrollbarSettings mockScrollbarSettings;
4066    const std::string htmlFile = "disambiguation_popup_viewport_site.html";
4067    registerMockedHttpURLLoad(htmlFile);
4068
4069    DisambiguationPopupTestWebViewClient client;
4070
4071    // Make sure we initialize to minimum scale, even if the window size
4072    // only becomes available after the load begins.
4073    FrameTestHelpers::WebViewHelper webViewHelper;
4074    webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4075    webViewHelper.webView()->resize(WebSize(1000, 1000));
4076    webViewHelper.webView()->layout();
4077
4078    client.resetTriggered();
4079    webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4080    EXPECT_FALSE(client.triggered());
4081
4082    client.resetTriggered();
4083    webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4084    EXPECT_FALSE(client.triggered());
4085
4086    for (int i = 0; i <= 46; i++) {
4087        client.resetTriggered();
4088        webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4089        EXPECT_FALSE(client.triggered());
4090    }
4091
4092    for (int i = 0; i <= 46; i++) {
4093        client.resetTriggered();
4094        webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4095        EXPECT_FALSE(client.triggered());
4096    }
4097}
4098
4099TEST_F(WebFrameTest, DisambiguationPopupBlacklist)
4100{
4101    const unsigned viewportWidth = 500;
4102    const unsigned viewportHeight = 1000;
4103    const unsigned divHeight = 100;
4104    const std::string htmlFile = "disambiguation_popup_blacklist.html";
4105    registerMockedHttpURLLoad(htmlFile);
4106
4107    DisambiguationPopupTestWebViewClient client;
4108
4109    // Make sure we initialize to minimum scale, even if the window size
4110    // only becomes available after the load begins.
4111    FrameTestHelpers::WebViewHelper webViewHelper;
4112    webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4113    webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
4114    webViewHelper.webView()->layout();
4115
4116    // Click somewhere where the popup shouldn't appear.
4117    client.resetTriggered();
4118    webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, 0));
4119    EXPECT_FALSE(client.triggered());
4120
4121    // Click directly in between two container divs with click handlers, with children that don't handle clicks.
4122    client.resetTriggered();
4123    webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight));
4124    EXPECT_TRUE(client.triggered());
4125
4126    // The third div container should be blacklisted if you click on the link it contains.
4127    client.resetTriggered();
4128    webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight * 3.25));
4129    EXPECT_FALSE(client.triggered());
4130}
4131
4132TEST_F(WebFrameTest, DisambiguationPopupPageScale)
4133{
4134    registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
4135
4136    DisambiguationPopupTestWebViewClient client;
4137
4138    // Make sure we initialize to minimum scale, even if the window size
4139    // only becomes available after the load begins.
4140    FrameTestHelpers::WebViewHelper webViewHelper;
4141    webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_page_scale.html", true, 0, &client);
4142    webViewHelper.webView()->resize(WebSize(1000, 1000));
4143    webViewHelper.webView()->layout();
4144
4145    client.resetTriggered();
4146    webViewHelper.webView()->handleInputEvent(fatTap(80, 80));
4147    EXPECT_TRUE(client.triggered());
4148
4149    client.resetTriggered();
4150    webViewHelper.webView()->handleInputEvent(fatTap(230, 190));
4151    EXPECT_TRUE(client.triggered());
4152
4153    webViewHelper.webView()->setPageScaleFactor(3.0f);
4154    webViewHelper.webView()->layout();
4155
4156    client.resetTriggered();
4157    webViewHelper.webView()->handleInputEvent(fatTap(240, 240));
4158    EXPECT_TRUE(client.triggered());
4159
4160    client.resetTriggered();
4161    webViewHelper.webView()->handleInputEvent(fatTap(690, 570));
4162    EXPECT_FALSE(client.triggered());
4163}
4164
4165class TestSubstituteDataWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4166public:
4167    TestSubstituteDataWebFrameClient()
4168        : m_commitCalled(false)
4169    {
4170    }
4171
4172    virtual void didFailProvisionalLoad(WebLocalFrame* frame, const WebURLError& error)
4173    {
4174        frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true);
4175    }
4176
4177    virtual void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType)
4178    {
4179        if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank")))
4180            m_commitCalled = true;
4181    }
4182
4183    bool commitCalled() const { return m_commitCalled; }
4184
4185private:
4186    bool m_commitCalled;
4187};
4188
4189TEST_F(WebFrameTest, ReplaceNavigationAfterHistoryNavigation)
4190{
4191    TestSubstituteDataWebFrameClient webFrameClient;
4192
4193    FrameTestHelpers::WebViewHelper webViewHelper;
4194    webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
4195    WebFrame* frame = webViewHelper.webView()->mainFrame();
4196
4197    // Load a url as a history navigation that will return an error. TestSubstituteDataWebFrameClient
4198    // will start a SubstituteData load in response to the load failure, which should get fully committed.
4199    // Due to https://bugs.webkit.org/show_bug.cgi?id=91685, FrameLoader::didReceiveData() wasn't getting
4200    // called in this case, which resulted in the SubstituteData document not getting displayed.
4201    WebURLError error;
4202    error.reason = 1337;
4203    error.domain = "WebFrameTest";
4204    std::string errorURL = "http://0.0.0.0";
4205    WebURLResponse response;
4206    response.initialize();
4207    response.setURL(URLTestHelpers::toKURL(errorURL));
4208    response.setMIMEType("text/html");
4209    response.setHTTPStatusCode(500);
4210    WebHistoryItem errorHistoryItem;
4211    errorHistoryItem.initialize();
4212    errorHistoryItem.setURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
4213    Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
4214    FrameTestHelpers::loadHistoryItem(frame, errorHistoryItem, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
4215
4216    WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
4217    EXPECT_EQ("This should appear", text.utf8());
4218    EXPECT_TRUE(webFrameClient.commitCalled());
4219}
4220
4221class TestWillInsertBodyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4222public:
4223    TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false)
4224    {
4225    }
4226
4227    virtual void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
4228    {
4229        m_numBodies = 0;
4230        m_didLoad = true;
4231    }
4232
4233    virtual void didCreateDocumentElement(WebLocalFrame*) OVERRIDE
4234    {
4235        EXPECT_EQ(0, m_numBodies);
4236    }
4237
4238    virtual void willInsertBody(WebLocalFrame*) OVERRIDE
4239    {
4240        m_numBodies++;
4241    }
4242
4243    int m_numBodies;
4244    bool m_didLoad;
4245};
4246
4247TEST_F(WebFrameTest, HTMLDocument)
4248{
4249    registerMockedHttpURLLoad("clipped-body.html");
4250
4251    TestWillInsertBodyWebFrameClient webFrameClient;
4252    FrameTestHelpers::WebViewHelper webViewHelper;
4253    webViewHelper.initializeAndLoad(m_baseURL + "clipped-body.html", false, &webFrameClient);
4254
4255    EXPECT_TRUE(webFrameClient.m_didLoad);
4256    EXPECT_EQ(1, webFrameClient.m_numBodies);
4257}
4258
4259TEST_F(WebFrameTest, EmptyDocument)
4260{
4261    registerMockedHttpURLLoad("pageserializer/green_rectangle.svg");
4262
4263    TestWillInsertBodyWebFrameClient webFrameClient;
4264    FrameTestHelpers::WebViewHelper webViewHelper;
4265    webViewHelper.initialize(false, &webFrameClient);
4266
4267    EXPECT_FALSE(webFrameClient.m_didLoad);
4268    EXPECT_EQ(1, webFrameClient.m_numBodies); // The empty document that a new frame starts with triggers this.
4269}
4270
4271TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection)
4272{
4273    FrameTestHelpers::WebViewHelper webViewHelper;
4274    webViewHelper.initializeAndLoad("about:blank", true);
4275    WebFrame* frame = webViewHelper.webView()->mainFrame();
4276
4277    // This test passes if this doesn't crash.
4278    frame->moveCaretSelection(WebPoint(0, 0));
4279}
4280
4281class SpellCheckClient : public WebSpellCheckClient {
4282public:
4283    explicit SpellCheckClient(uint32_t hash = 0) : m_numberOfTimesChecked(0), m_hash(hash) { }
4284    virtual ~SpellCheckClient() { }
4285    virtual void requestCheckingOfText(const blink::WebString&, const blink::WebVector<uint32_t>&, const blink::WebVector<unsigned>&, blink::WebTextCheckingCompletion* completion) OVERRIDE
4286    {
4287        ++m_numberOfTimesChecked;
4288        Vector<WebTextCheckingResult> results;
4289        const int misspellingStartOffset = 1;
4290        const int misspellingLength = 8;
4291        results.append(WebTextCheckingResult(WebTextDecorationTypeSpelling, misspellingStartOffset, misspellingLength, WebString(), m_hash));
4292        completion->didFinishCheckingText(results);
4293    }
4294    int numberOfTimesChecked() const { return m_numberOfTimesChecked; }
4295private:
4296    int m_numberOfTimesChecked;
4297    uint32_t m_hash;
4298};
4299
4300TEST_F(WebFrameTest, ReplaceMisspelledRange)
4301{
4302    registerMockedHttpURLLoad("spell.html");
4303    FrameTestHelpers::WebViewHelper webViewHelper;
4304    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4305    SpellCheckClient spellcheck;
4306    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4307
4308    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4309    Document* document = frame->frame()->document();
4310    Element* element = document->getElementById("data");
4311
4312    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4313    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4314    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4315
4316    element->focus();
4317    document->execCommand("InsertText", false, "_wellcome_.");
4318
4319    const int allTextBeginOffset = 0;
4320    const int allTextLength = 11;
4321    frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4322    RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4323
4324    EXPECT_EQ(1, spellcheck.numberOfTimesChecked());
4325    EXPECT_EQ(1U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4326
4327    frame->replaceMisspelledRange("welcome");
4328    EXPECT_EQ("_welcome_.", frame->contentAsText(std::numeric_limits<size_t>::max()).utf8());
4329}
4330
4331TEST_F(WebFrameTest, RemoveSpellingMarkers)
4332{
4333    registerMockedHttpURLLoad("spell.html");
4334    FrameTestHelpers::WebViewHelper webViewHelper;
4335    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4336    SpellCheckClient spellcheck;
4337    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4338
4339    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4340    Document* document = frame->frame()->document();
4341    Element* element = document->getElementById("data");
4342
4343    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4344    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4345    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4346
4347    element->focus();
4348    document->execCommand("InsertText", false, "_wellcome_.");
4349
4350    frame->removeSpellingMarkers();
4351
4352    const int allTextBeginOffset = 0;
4353    const int allTextLength = 11;
4354    frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4355    RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4356
4357    EXPECT_EQ(0U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4358}
4359
4360TEST_F(WebFrameTest, MarkerHashIdentifiers) {
4361    registerMockedHttpURLLoad("spell.html");
4362    FrameTestHelpers::WebViewHelper webViewHelper;
4363    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4364
4365    static const uint32_t kHash = 42;
4366    SpellCheckClient spellcheck(kHash);
4367    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4368
4369    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4370    Document* document = frame->frame()->document();
4371    Element* element = document->getElementById("data");
4372
4373    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4374    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4375    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4376
4377    element->focus();
4378    document->execCommand("InsertText", false, "wellcome.");
4379
4380    WebVector<uint32_t> documentMarkers;
4381    webViewHelper.webView()->spellingMarkers(&documentMarkers);
4382    EXPECT_EQ(1U, documentMarkers.size());
4383    EXPECT_EQ(kHash, documentMarkers[0]);
4384}
4385
4386class StubbornSpellCheckClient : public WebSpellCheckClient {
4387public:
4388    StubbornSpellCheckClient() : m_completion(0) { }
4389    virtual ~StubbornSpellCheckClient() { }
4390
4391    virtual void requestCheckingOfText(
4392        const blink::WebString&,
4393        const blink::WebVector<uint32_t>&,
4394        const blink::WebVector<unsigned>&,
4395        blink::WebTextCheckingCompletion* completion) OVERRIDE
4396    {
4397        m_completion = completion;
4398    }
4399
4400    void kickNoResults()
4401    {
4402        kick(-1, -1, WebTextDecorationTypeSpelling);
4403    }
4404
4405    void kick()
4406    {
4407        kick(1, 8, WebTextDecorationTypeSpelling);
4408    }
4409
4410    void kickGrammar()
4411    {
4412        kick(1, 8, WebTextDecorationTypeGrammar);
4413    }
4414
4415    void kickInvisibleSpellcheck()
4416    {
4417        kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck);
4418    }
4419
4420private:
4421    void kick(int misspellingStartOffset, int misspellingLength, WebTextDecorationType type)
4422    {
4423        if (!m_completion)
4424            return;
4425        Vector<WebTextCheckingResult> results;
4426        if (misspellingStartOffset >= 0 && misspellingLength > 0)
4427            results.append(WebTextCheckingResult(type, misspellingStartOffset, misspellingLength));
4428        m_completion->didFinishCheckingText(results);
4429        m_completion = 0;
4430    }
4431
4432    blink::WebTextCheckingCompletion* m_completion;
4433};
4434
4435TEST_F(WebFrameTest, SlowSpellcheckMarkerPosition)
4436{
4437    registerMockedHttpURLLoad("spell.html");
4438    FrameTestHelpers::WebViewHelper webViewHelper;
4439    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4440
4441    StubbornSpellCheckClient spellcheck;
4442    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4443
4444    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4445    WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4446    Document* document = frame->frame()->document();
4447    Element* element = document->getElementById("data");
4448
4449    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4450    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4451    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4452
4453    element->focus();
4454    document->execCommand("InsertText", false, "wellcome ");
4455    webInputElement.setSelectionRange(0, 0);
4456    document->execCommand("InsertText", false, "he");
4457
4458    spellcheck.kick();
4459
4460    WebVector<uint32_t> documentMarkers;
4461    webViewHelper.webView()->spellingMarkers(&documentMarkers);
4462    EXPECT_EQ(0U, documentMarkers.size());
4463}
4464
4465// This test verifies that cancelling spelling request does not cause a
4466// write-after-free when there's no spellcheck client set.
4467TEST_F(WebFrameTest, CancelSpellingRequestCrash)
4468{
4469    registerMockedHttpURLLoad("spell.html");
4470    FrameTestHelpers::WebViewHelper webViewHelper;
4471    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4472    webViewHelper.webView()->setSpellCheckClient(0);
4473
4474    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4475    Document* document = frame->frame()->document();
4476    Element* element = document->getElementById("data");
4477
4478    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4479    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4480    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4481
4482    element->focus();
4483    frame->frame()->editor().replaceSelectionWithText("A", false, false);
4484    frame->frame()->spellChecker().cancelCheck();
4485}
4486
4487TEST_F(WebFrameTest, SpellcheckResultErasesMarkers)
4488{
4489    registerMockedHttpURLLoad("spell.html");
4490    FrameTestHelpers::WebViewHelper webViewHelper;
4491    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4492
4493    StubbornSpellCheckClient spellcheck;
4494    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4495
4496    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4497    WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4498    Document* document = frame->frame()->document();
4499    Element* element = document->getElementById("data");
4500
4501    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4502    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4503    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4504
4505    element->focus();
4506    document->execCommand("InsertText", false, "welcome ");
4507    document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Spelling);
4508    document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Grammar);
4509    document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::InvisibleSpellcheck);
4510    EXPECT_EQ(3U, document->markers().markers().size());
4511
4512    spellcheck.kickNoResults();
4513    EXPECT_EQ(0U, document->markers().markers().size());
4514}
4515
4516TEST_F(WebFrameTest, SpellcheckResultsSavedInDocument)
4517{
4518    registerMockedHttpURLLoad("spell.html");
4519    FrameTestHelpers::WebViewHelper webViewHelper;
4520    webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4521
4522    StubbornSpellCheckClient spellcheck;
4523    webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4524
4525    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4526    WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4527    Document* document = frame->frame()->document();
4528    Element* element = document->getElementById("data");
4529
4530    webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4531    webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4532    webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4533
4534    element->focus();
4535    document->execCommand("InsertText", false, "wellcome ");
4536
4537    spellcheck.kick();
4538    ASSERT_EQ(1U, document->markers().markers().size());
4539    ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4540    EXPECT_EQ(DocumentMarker::Spelling, document->markers().markers()[0]->type());
4541
4542    document->execCommand("InsertText", false, "wellcome ");
4543
4544    spellcheck.kickGrammar();
4545    ASSERT_EQ(1U, document->markers().markers().size());
4546    ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4547    EXPECT_EQ(DocumentMarker::Grammar, document->markers().markers()[0]->type());
4548
4549    document->execCommand("InsertText", false, "wellcome ");
4550
4551    spellcheck.kickInvisibleSpellcheck();
4552    ASSERT_EQ(1U, document->markers().markers().size());
4553    ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4554    EXPECT_EQ(DocumentMarker::InvisibleSpellcheck, document->markers().markers()[0]->type());
4555}
4556
4557class TestAccessInitialDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4558public:
4559    TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false)
4560    {
4561    }
4562
4563    virtual void didAccessInitialDocument(WebLocalFrame* frame)
4564    {
4565        EXPECT_TRUE(!m_didAccessInitialDocument);
4566        m_didAccessInitialDocument = true;
4567    }
4568
4569    bool m_didAccessInitialDocument;
4570};
4571
4572TEST_F(WebFrameTest, DidAccessInitialDocumentBody)
4573{
4574    // FIXME: Why is this local webViewClient needed instead of the default
4575    // WebViewHelper one? With out it there's some mysterious crash in the
4576    // WebViewHelper destructor.
4577    FrameTestHelpers::TestWebViewClient webViewClient;
4578    TestAccessInitialDocumentWebFrameClient webFrameClient;
4579    FrameTestHelpers::WebViewHelper webViewHelper;
4580    webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4581    runPendingTasks();
4582    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4583
4584    // Create another window that will try to access it.
4585    FrameTestHelpers::WebViewHelper newWebViewHelper;
4586    WebView* newView = newWebViewHelper.initialize(true);
4587    newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4588    runPendingTasks();
4589    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4590
4591    // Access the initial document by modifying the body.
4592    newView->mainFrame()->executeScript(
4593        WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4594    runPendingTasks();
4595    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4596
4597    // Access the initial document again, to ensure we don't notify twice.
4598    newView->mainFrame()->executeScript(
4599        WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4600    runPendingTasks();
4601    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4602}
4603
4604TEST_F(WebFrameTest, DidAccessInitialDocumentNavigator)
4605{
4606    // FIXME: Why is this local webViewClient needed instead of the default
4607    // WebViewHelper one? With out it there's some mysterious crash in the
4608    // WebViewHelper destructor.
4609    FrameTestHelpers::TestWebViewClient webViewClient;
4610    TestAccessInitialDocumentWebFrameClient webFrameClient;
4611    FrameTestHelpers::WebViewHelper webViewHelper;
4612    webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4613    runPendingTasks();
4614    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4615
4616    // Create another window that will try to access it.
4617    FrameTestHelpers::WebViewHelper newWebViewHelper;
4618    WebView* newView = newWebViewHelper.initialize(true);
4619    newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4620    runPendingTasks();
4621    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4622
4623    // Access the initial document to get to the navigator object.
4624    newView->mainFrame()->executeScript(
4625        WebScriptSource("console.log(window.opener.navigator);"));
4626    runPendingTasks();
4627    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4628}
4629
4630TEST_F(WebFrameTest, DidAccessInitialDocumentViaJavascriptUrl)
4631{
4632    TestAccessInitialDocumentWebFrameClient webFrameClient;
4633    FrameTestHelpers::WebViewHelper webViewHelper;
4634    webViewHelper.initialize(true, &webFrameClient);
4635    runPendingTasks();
4636    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4637
4638    // Access the initial document from a javascript: URL.
4639    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Modified'))");
4640    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4641}
4642
4643// Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4644#if OS(WIN)
4645TEST_F(WebFrameTest, DISABLED_DidAccessInitialDocumentBodyBeforeModalDialog)
4646#else
4647TEST_F(WebFrameTest, DidAccessInitialDocumentBodyBeforeModalDialog)
4648#endif
4649{
4650    // FIXME: Why is this local webViewClient needed instead of the default
4651    // WebViewHelper one? With out it there's some mysterious crash in the
4652    // WebViewHelper destructor.
4653    FrameTestHelpers::TestWebViewClient webViewClient;
4654    TestAccessInitialDocumentWebFrameClient webFrameClient;
4655    FrameTestHelpers::WebViewHelper webViewHelper;
4656    webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4657    runPendingTasks();
4658    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4659
4660    // Create another window that will try to access it.
4661    FrameTestHelpers::WebViewHelper newWebViewHelper;
4662    WebView* newView = newWebViewHelper.initialize(true);
4663    newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4664    runPendingTasks();
4665    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4666
4667    // Access the initial document by modifying the body. We normally set a
4668    // timer to notify the client.
4669    newView->mainFrame()->executeScript(
4670        WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4671    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4672
4673    // Make sure that a modal dialog forces us to notify right away.
4674    newView->mainFrame()->executeScript(
4675        WebScriptSource("window.opener.confirm('Modal');"));
4676    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4677
4678    // Ensure that we don't notify again later.
4679    runPendingTasks();
4680    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4681}
4682
4683// Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4684#if OS(WIN)
4685TEST_F(WebFrameTest, DISABLED_DidWriteToInitialDocumentBeforeModalDialog)
4686#else
4687TEST_F(WebFrameTest, DidWriteToInitialDocumentBeforeModalDialog)
4688#endif
4689{
4690    // FIXME: Why is this local webViewClient needed instead of the default
4691    // WebViewHelper one? With out it there's some mysterious crash in the
4692    // WebViewHelper destructor.
4693    FrameTestHelpers::TestWebViewClient webViewClient;
4694    TestAccessInitialDocumentWebFrameClient webFrameClient;
4695    FrameTestHelpers::WebViewHelper webViewHelper;
4696    webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4697    runPendingTasks();
4698    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4699
4700    // Create another window that will try to access it.
4701    FrameTestHelpers::WebViewHelper newWebViewHelper;
4702    WebView* newView = newWebViewHelper.initialize(true);
4703    newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4704    runPendingTasks();
4705    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4706
4707    // Access the initial document with document.write, which moves us past the
4708    // initial empty document state of the state machine. We normally set a
4709    // timer to notify the client.
4710    newView->mainFrame()->executeScript(
4711        WebScriptSource("window.opener.document.write('Modified');"));
4712    EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4713
4714    // Make sure that a modal dialog forces us to notify right away.
4715    newView->mainFrame()->executeScript(
4716        WebScriptSource("window.opener.confirm('Modal');"));
4717    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4718
4719    // Ensure that we don't notify again later.
4720    runPendingTasks();
4721    EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4722}
4723
4724class TestMainFrameUserOrProgrammaticScrollFrameClient : public FrameTestHelpers::TestWebFrameClient {
4725public:
4726    TestMainFrameUserOrProgrammaticScrollFrameClient() { reset(); }
4727    void reset()
4728    {
4729        m_didScrollMainFrame = false;
4730        m_wasProgrammaticScroll = false;
4731    }
4732    bool wasUserScroll() const { return m_didScrollMainFrame && !m_wasProgrammaticScroll; }
4733    bool wasProgrammaticScroll() const { return m_didScrollMainFrame && m_wasProgrammaticScroll; }
4734
4735    // WebFrameClient:
4736    virtual void didChangeScrollOffset(WebLocalFrame* frame) OVERRIDE
4737    {
4738        if (frame->parent())
4739            return;
4740        EXPECT_FALSE(m_didScrollMainFrame);
4741        WebCore::FrameView* view = toWebLocalFrameImpl(frame)->frameView();
4742        // FrameView can be scrolled in FrameView::setFixedVisibleContentRect
4743        // which is called from LocalFrame::createView (before the frame is associated
4744        // with the the view).
4745        if (view) {
4746            m_didScrollMainFrame = true;
4747            m_wasProgrammaticScroll = view->inProgrammaticScroll();
4748        }
4749    }
4750private:
4751    bool m_didScrollMainFrame;
4752    bool m_wasProgrammaticScroll;
4753};
4754
4755TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage)
4756{
4757    registerMockedHttpURLLoad("long_scroll.html");
4758    TestMainFrameUserOrProgrammaticScrollFrameClient client;
4759
4760    // Make sure we initialize to minimum scale, even if the window size
4761    // only becomes available after the load begins.
4762    FrameTestHelpers::WebViewHelper webViewHelper;
4763    webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, &client);
4764    webViewHelper.webView()->resize(WebSize(1000, 1000));
4765    webViewHelper.webView()->layout();
4766
4767    EXPECT_FALSE(client.wasUserScroll());
4768    EXPECT_FALSE(client.wasProgrammaticScroll());
4769
4770    // Do a compositor scroll, verify that this is counted as a user scroll.
4771    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(0, 1), 1.1f);
4772    EXPECT_TRUE(client.wasUserScroll());
4773    client.reset();
4774
4775    EXPECT_FALSE(client.wasUserScroll());
4776    EXPECT_FALSE(client.wasProgrammaticScroll());
4777
4778    // The page scale 1.0f and scroll.
4779    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(0, 1), 1.0f);
4780    EXPECT_TRUE(client.wasUserScroll());
4781    client.reset();
4782
4783    // No scroll event if there is no scroll delta.
4784    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(), 1.0f);
4785    EXPECT_FALSE(client.wasUserScroll());
4786    EXPECT_FALSE(client.wasProgrammaticScroll());
4787    client.reset();
4788
4789    // Non zero page scale and scroll.
4790    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(9, 13), 0.6f);
4791    EXPECT_TRUE(client.wasUserScroll());
4792    client.reset();
4793
4794    // Programmatic scroll.
4795    WebLocalFrameImpl* frameImpl = webViewHelper.webViewImpl()->mainFrameImpl();
4796    frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
4797    EXPECT_FALSE(client.wasUserScroll());
4798    EXPECT_TRUE(client.wasProgrammaticScroll());
4799    client.reset();
4800
4801    // Programmatic scroll to same offset. No scroll event should be generated.
4802    frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
4803    EXPECT_FALSE(client.wasProgrammaticScroll());
4804    EXPECT_FALSE(client.wasUserScroll());
4805    client.reset();
4806}
4807
4808TEST_F(WebFrameTest, CompositorScrollIsUserScrollShortPage)
4809{
4810    registerMockedHttpURLLoad("short_scroll.html");
4811
4812    TestMainFrameUserOrProgrammaticScrollFrameClient client;
4813
4814    // Short page tests.
4815    FrameTestHelpers::WebViewHelper webViewHelper;
4816    webViewHelper.initializeAndLoad(m_baseURL + "short_scroll.html", true, &client);
4817
4818    webViewHelper.webView()->resize(WebSize(1000, 1000));
4819    webViewHelper.webView()->layout();
4820
4821    EXPECT_FALSE(client.wasUserScroll());
4822    EXPECT_FALSE(client.wasProgrammaticScroll());
4823
4824    // Non zero page scale and scroll.
4825    webViewHelper.webViewImpl()->applyScrollAndScale(WebSize(9, 13), 2.0f);
4826    EXPECT_FALSE(client.wasProgrammaticScroll());
4827    EXPECT_TRUE(client.wasUserScroll());
4828    client.reset();
4829}
4830
4831TEST_F(WebFrameTest, FirstPartyForCookiesForRedirect)
4832{
4833    WTF::String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
4834    filePath.append("/Source/web/tests/data/first_party.html");
4835
4836    WebURL testURL(toKURL("http://www.test.com/first_party_redirect.html"));
4837    char redirect[] = "http://www.test.com/first_party.html";
4838    WebURL redirectURL(toKURL(redirect));
4839    WebURLResponse redirectResponse;
4840    redirectResponse.initialize();
4841    redirectResponse.setMIMEType("text/html");
4842    redirectResponse.setHTTPStatusCode(302);
4843    redirectResponse.setHTTPHeaderField("Location", redirect);
4844    Platform::current()->unitTestSupport()->registerMockedURL(testURL, redirectResponse, filePath);
4845
4846    WebURLResponse finalResponse;
4847    finalResponse.initialize();
4848    finalResponse.setMIMEType("text/html");
4849    Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, finalResponse, filePath);
4850
4851    FrameTestHelpers::WebViewHelper webViewHelper;
4852    webViewHelper.initializeAndLoad(m_baseURL + "first_party_redirect.html", true);
4853    EXPECT_TRUE(webViewHelper.webView()->mainFrame()->document().firstPartyForCookies() == redirectURL);
4854}
4855
4856class TestNavigationPolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4857public:
4858
4859    virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
4860    {
4861        EXPECT_TRUE(false);
4862    }
4863};
4864
4865TEST_F(WebFrameTest, SimulateFragmentAnchorMiddleClick)
4866{
4867    registerMockedHttpURLLoad("fragment_middle_click.html");
4868    TestNavigationPolicyWebFrameClient client;
4869    FrameTestHelpers::WebViewHelper webViewHelper;
4870    webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true, &client);
4871
4872    WebCore::Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
4873    WebCore::KURL destination = document->url();
4874    destination.setFragmentIdentifier("test");
4875
4876    RefPtrWillBeRawPtr<WebCore::Event> event = WebCore::MouseEvent::create(WebCore::EventTypeNames::click, false, false,
4877        document->domWindow(), 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 1, nullptr, nullptr);
4878    WebCore::FrameLoadRequest frameRequest(document, WebCore::ResourceRequest(destination));
4879    frameRequest.setTriggeringEvent(event);
4880    toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
4881}
4882
4883class TestNewWindowWebViewClient : public FrameTestHelpers::TestWebViewClient {
4884public:
4885    virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&,
4886        const WebString&, WebNavigationPolicy, bool) OVERRIDE
4887    {
4888        EXPECT_TRUE(false);
4889        return 0;
4890    }
4891};
4892
4893class TestNewWindowWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4894public:
4895    TestNewWindowWebFrameClient()
4896        : m_decidePolicyCallCount(0)
4897    {
4898    }
4899
4900    virtual WebNavigationPolicy decidePolicyForNavigation(WebLocalFrame*, WebDataSource::ExtraData*, const WebURLRequest&,
4901        WebNavigationType, WebNavigationPolicy policy, bool) OVERRIDE
4902    {
4903        m_decidePolicyCallCount++;
4904        return policy;
4905    }
4906
4907    int decidePolicyCallCount() const { return m_decidePolicyCallCount; }
4908
4909private:
4910    int m_decidePolicyCallCount;
4911};
4912
4913TEST_F(WebFrameTest, ModifiedClickNewWindow)
4914{
4915    registerMockedHttpURLLoad("ctrl_click.html");
4916    registerMockedHttpURLLoad("hello_world.html");
4917    TestNewWindowWebViewClient webViewClient;
4918    TestNewWindowWebFrameClient webFrameClient;
4919    FrameTestHelpers::WebViewHelper webViewHelper;
4920    webViewHelper.initializeAndLoad(m_baseURL + "ctrl_click.html", true, &webFrameClient, &webViewClient);
4921
4922    WebCore::Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
4923    WebCore::KURL destination = toKURL(m_baseURL + "hello_world.html");
4924
4925    // ctrl+click event
4926    RefPtrWillBeRawPtr<WebCore::Event> event = WebCore::MouseEvent::create(WebCore::EventTypeNames::click, false, false,
4927        document->domWindow(), 0, 0, 0, 0, 0, 0, 0, true, false, false, false, 0, nullptr, nullptr);
4928    WebCore::FrameLoadRequest frameRequest(document, WebCore::ResourceRequest(destination));
4929    frameRequest.setTriggeringEvent(event);
4930    WebCore::UserGestureIndicator gesture(WebCore::DefinitelyProcessingUserGesture);
4931    toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
4932    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
4933
4934    // decidePolicyForNavigation should be called both for the original request and the ctrl+click.
4935    EXPECT_EQ(2, webFrameClient.decidePolicyCallCount());
4936}
4937
4938TEST_F(WebFrameTest, BackToReload)
4939{
4940    registerMockedHttpURLLoad("fragment_middle_click.html");
4941    FrameTestHelpers::WebViewHelper webViewHelper;
4942    webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
4943    WebFrame* frame = webViewHelper.webView()->mainFrame();
4944    const WebCore::FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
4945    RefPtr<WebCore::HistoryItem> firstItem = mainFrameLoader.currentItem();
4946    EXPECT_TRUE(firstItem);
4947
4948    registerMockedHttpURLLoad("white-1x1.png");
4949    FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
4950    EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
4951
4952    FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem.get()), WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
4953    EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
4954
4955    FrameTestHelpers::reloadFrame(frame);
4956    EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
4957}
4958
4959TEST_F(WebFrameTest, BackDuringChildFrameReload)
4960{
4961    registerMockedHttpURLLoad("page_with_blank_iframe.html");
4962    FrameTestHelpers::WebViewHelper webViewHelper;
4963    webViewHelper.initializeAndLoad(m_baseURL + "page_with_blank_iframe.html", true);
4964    WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
4965    const WebCore::FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
4966    WebFrame* childFrame = mainFrame->firstChild();
4967    ASSERT_TRUE(childFrame);
4968
4969    // Start a history navigation, then have a different frame commit a navigation.
4970    // In this case, reload an about:blank frame, which will commit synchronously.
4971    // After the history navigation completes, both the appropriate document url and
4972    // the current history item should reflect the history navigation.
4973    registerMockedHttpURLLoad("white-1x1.png");
4974    WebHistoryItem item;
4975    item.initialize();
4976    WebURL historyURL(toKURL(m_baseURL + "white-1x1.png"));
4977    item.setURLString(historyURL.string());
4978    mainFrame->loadHistoryItem(item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
4979
4980    FrameTestHelpers::reloadFrame(childFrame);
4981    EXPECT_EQ(item.urlString(), mainFrame->document().url().string());
4982    EXPECT_EQ(item.urlString(), WebString(mainFrameLoader.currentItem()->urlString()));
4983}
4984
4985TEST_F(WebFrameTest, ReloadPost)
4986{
4987    registerMockedHttpURLLoad("reload_post.html");
4988    FrameTestHelpers::WebViewHelper webViewHelper;
4989    webViewHelper.initializeAndLoad(m_baseURL + "reload_post.html", true);
4990    WebFrame* frame = webViewHelper.webView()->mainFrame();
4991
4992    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.forms[0].submit()");
4993    // Pump requests one more time after the javascript URL has executed to
4994    // trigger the actual POST load request.
4995    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
4996    EXPECT_EQ(WebString::fromUTF8("POST"), frame->dataSource()->request().httpMethod());
4997
4998    FrameTestHelpers::reloadFrame(frame);
4999    EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5000    EXPECT_EQ(WebNavigationTypeFormResubmitted, frame->dataSource()->navigationType());
5001}
5002
5003TEST_F(WebFrameTest, LoadHistoryItemReload)
5004{
5005    registerMockedHttpURLLoad("fragment_middle_click.html");
5006    FrameTestHelpers::WebViewHelper webViewHelper;
5007    webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5008    WebFrame* frame = webViewHelper.webView()->mainFrame();
5009    const WebCore::FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5010    RefPtr<WebCore::HistoryItem> firstItem = mainFrameLoader.currentItem();
5011    EXPECT_TRUE(firstItem);
5012
5013    registerMockedHttpURLLoad("white-1x1.png");
5014    FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5015    EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5016
5017    // Cache policy overrides should take.
5018    FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem), WebHistoryDifferentDocumentLoad, WebURLRequest::ReloadIgnoringCacheData);
5019    EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5020    EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5021}
5022
5023
5024class TestCachePolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5025public:
5026    explicit TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient* parentClient)
5027        : m_parentClient(parentClient)
5028        , m_policy(WebURLRequest::UseProtocolCachePolicy)
5029        , m_childClient(0)
5030        , m_willSendRequestCallCount(0)
5031        , m_childFrameCreationCount(0)
5032    {
5033    }
5034
5035    void setChildWebFrameClient(TestCachePolicyWebFrameClient* client) { m_childClient = client; }
5036    WebURLRequest::CachePolicy cachePolicy() const { return m_policy; }
5037    int willSendRequestCallCount() const { return m_willSendRequestCallCount; }
5038    int childFrameCreationCount() const { return m_childFrameCreationCount; }
5039
5040    virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString&)
5041    {
5042        ASSERT(m_childClient);
5043        m_childFrameCreationCount++;
5044        WebFrame* frame = WebLocalFrame::create(m_childClient);
5045        parent->appendChild(frame);
5046        return frame;
5047    }
5048
5049    virtual void didStartLoading(bool toDifferentDocument)
5050    {
5051        if (m_parentClient) {
5052            m_parentClient->didStartLoading(toDifferentDocument);
5053            return;
5054        }
5055        TestWebFrameClient::didStartLoading(toDifferentDocument);
5056    }
5057
5058    virtual void didStopLoading()
5059    {
5060        if (m_parentClient) {
5061            m_parentClient->didStopLoading();
5062            return;
5063        }
5064        TestWebFrameClient::didStopLoading();
5065    }
5066
5067    virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) OVERRIDE
5068    {
5069        m_policy = request.cachePolicy();
5070        m_willSendRequestCallCount++;
5071    }
5072
5073private:
5074    TestCachePolicyWebFrameClient* m_parentClient;
5075
5076    WebURLRequest::CachePolicy m_policy;
5077    TestCachePolicyWebFrameClient* m_childClient;
5078    int m_willSendRequestCallCount;
5079    int m_childFrameCreationCount;
5080};
5081
5082TEST_F(WebFrameTest, ReloadIframe)
5083{
5084    registerMockedHttpURLLoad("iframe_reload.html");
5085    registerMockedHttpURLLoad("visible_iframe.html");
5086    TestCachePolicyWebFrameClient mainClient(0);
5087    TestCachePolicyWebFrameClient childClient(&mainClient);
5088    mainClient.setChildWebFrameClient(&childClient);
5089
5090    FrameTestHelpers::WebViewHelper webViewHelper;
5091    webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, &mainClient);
5092
5093    WebLocalFrameImpl* mainFrame = webViewHelper.webViewImpl()->mainFrameImpl();
5094    RefPtr<WebLocalFrameImpl> childFrame = toWebLocalFrameImpl(mainFrame->firstChild());
5095    ASSERT_EQ(childFrame->client(), &childClient);
5096    EXPECT_EQ(mainClient.childFrameCreationCount(), 1);
5097    EXPECT_EQ(childClient.willSendRequestCallCount(), 1);
5098    EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::UseProtocolCachePolicy);
5099
5100    FrameTestHelpers::reloadFrame(mainFrame);
5101
5102    // A new WebFrame should have been created, but the child WebFrameClient should be reused.
5103    ASSERT_NE(childFrame, toWebLocalFrameImpl(mainFrame->firstChild()));
5104    ASSERT_EQ(toWebLocalFrameImpl(mainFrame->firstChild())->client(), &childClient);
5105
5106    EXPECT_EQ(mainClient.childFrameCreationCount(), 2);
5107    EXPECT_EQ(childClient.willSendRequestCallCount(), 2);
5108    EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::ReloadIgnoringCacheData);
5109}
5110
5111class TestSameDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5112public:
5113    TestSameDocumentWebFrameClient()
5114        : m_frameLoadTypeSameSeen(false)
5115    {
5116    }
5117
5118    virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest&, const WebURLResponse&)
5119    {
5120        if (toWebLocalFrameImpl(frame)->frame()->loader().loadType() == WebCore::FrameLoadTypeSame)
5121            m_frameLoadTypeSameSeen = true;
5122    }
5123
5124    bool frameLoadTypeSameSeen() const { return m_frameLoadTypeSameSeen; }
5125
5126private:
5127    bool m_frameLoadTypeSameSeen;
5128};
5129
5130TEST_F(WebFrameTest, NavigateToSame)
5131{
5132    registerMockedHttpURLLoad("navigate_to_same.html");
5133    TestSameDocumentWebFrameClient client;
5134    FrameTestHelpers::WebViewHelper webViewHelper;
5135    webViewHelper.initializeAndLoad(m_baseURL + "navigate_to_same.html", true, &client);
5136    EXPECT_FALSE(client.frameLoadTypeSameSeen());
5137
5138    WebCore::FrameLoadRequest frameRequest(0, WebCore::ResourceRequest(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document()->url()));
5139    toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5140    FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5141
5142    EXPECT_TRUE(client.frameLoadTypeSameSeen());
5143}
5144
5145TEST_F(WebFrameTest, WebNodeImageContents)
5146{
5147    FrameTestHelpers::WebViewHelper webViewHelper;
5148    webViewHelper.initializeAndLoad("about:blank", true);
5149    WebFrame* frame = webViewHelper.webView()->mainFrame();
5150
5151    static const char bluePNG[] = "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYV2NkYPj/n4EIwDiqEF8oUT94AFIQE/cCn90IAAAAAElFTkSuQmCC\">";
5152
5153    // Load up the image and test that we can extract the contents.
5154    WebCore::KURL testURL = toKURL("about:blank");
5155    FrameTestHelpers::loadHTMLString(frame, bluePNG, testURL);
5156
5157    WebNode node = frame->document().body().firstChild();
5158    EXPECT_TRUE(node.isElementNode());
5159    WebElement element = node.to<WebElement>();
5160    WebImage image = element.imageContents();
5161    ASSERT_FALSE(image.isNull());
5162    EXPECT_EQ(image.size().width, 10);
5163    EXPECT_EQ(image.size().height, 10);
5164//    FIXME: The rest of this test is disabled since the ImageDecodeCache state may be inconsistent when this test runs.
5165//    crbug.com/266088
5166//    SkBitmap bitmap = image.getSkBitmap();
5167//    SkAutoLockPixels locker(bitmap);
5168//    EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorBLUE);
5169}
5170
5171class TestStartStopCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5172public:
5173    TestStartStopCallbackWebFrameClient()
5174        : m_startLoadingCount(0)
5175        , m_stopLoadingCount(0)
5176        , m_differentDocumentStartCount(0)
5177    {
5178    }
5179
5180    virtual void didStartLoading(bool toDifferentDocument) OVERRIDE
5181    {
5182        TestWebFrameClient::didStartLoading(toDifferentDocument);
5183        m_startLoadingCount++;
5184        if (toDifferentDocument)
5185            m_differentDocumentStartCount++;
5186    }
5187
5188    virtual void didStopLoading() OVERRIDE
5189    {
5190        TestWebFrameClient::didStopLoading();
5191        m_stopLoadingCount++;
5192    }
5193
5194    int startLoadingCount() const { return m_startLoadingCount; }
5195    int stopLoadingCount() const { return m_stopLoadingCount; }
5196    int differentDocumentStartCount() const { return m_differentDocumentStartCount; }
5197
5198private:
5199    int m_startLoadingCount;
5200    int m_stopLoadingCount;
5201    int m_differentDocumentStartCount;
5202};
5203
5204TEST_F(WebFrameTest, PushStateStartsAndStops)
5205{
5206    registerMockedHttpURLLoad("push_state.html");
5207    TestStartStopCallbackWebFrameClient client;
5208    FrameTestHelpers::WebViewHelper webViewHelper;
5209    webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5210
5211    EXPECT_EQ(client.startLoadingCount(), 2);
5212    EXPECT_EQ(client.stopLoadingCount(), 2);
5213    EXPECT_EQ(client.differentDocumentStartCount(), 1);
5214}
5215
5216class TestDidNavigateCommitTypeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5217public:
5218    TestDidNavigateCommitTypeWebFrameClient()
5219        : m_lastCommitType(WebHistoryInertCommit)
5220    {
5221    }
5222
5223    virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType type) OVERRIDE
5224    {
5225        m_lastCommitType = type;
5226    }
5227
5228    WebHistoryCommitType lastCommitType() const { return m_lastCommitType; }
5229
5230private:
5231    WebHistoryCommitType m_lastCommitType;
5232};
5233
5234TEST_F(WebFrameTest, SameDocumentHistoryNavigationCommitType)
5235{
5236    registerMockedHttpURLLoad("push_state.html");
5237    TestDidNavigateCommitTypeWebFrameClient client;
5238    FrameTestHelpers::WebViewHelper webViewHelper;
5239    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5240    RefPtr<WebCore::HistoryItem> item = toLocalFrame(webViewImpl->page()->mainFrame())->loader().currentItem();
5241    runPendingTasks();
5242
5243    toLocalFrame(webViewImpl->page()->mainFrame())->loader().loadHistoryItem(item.get(), WebCore::HistorySameDocumentLoad);
5244    EXPECT_EQ(WebBackForwardCommit, client.lastCommitType());
5245}
5246
5247class TestHistoryWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5248public:
5249    TestHistoryWebFrameClient()
5250    {
5251        m_replacesCurrentHistoryItem = false;
5252        m_frame = 0;
5253    }
5254    void didStartProvisionalLoad(WebLocalFrame* frame)
5255    {
5256        WebDataSource* ds = frame->provisionalDataSource();
5257        m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem();
5258        m_frame = frame;
5259    }
5260
5261    bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; }
5262    WebFrame* frame() { return m_frame; }
5263
5264private:
5265    bool m_replacesCurrentHistoryItem;
5266    WebFrame* m_frame;
5267};
5268
5269// Test which ensures that the first navigation in a subframe will always
5270// result in history entry being replaced and not a new one added.
5271TEST_F(WebFrameTest, DISABLED_FirstFrameNavigationReplacesHistory)
5272{
5273    registerMockedHttpURLLoad("history.html");
5274    registerMockedHttpURLLoad("find.html");
5275
5276    FrameTestHelpers::WebViewHelper webViewHelper;
5277    TestHistoryWebFrameClient client;
5278    webViewHelper.initializeAndLoad("about:blank", true, &client);
5279    EXPECT_TRUE(client.replacesCurrentHistoryItem());
5280
5281    WebFrame* frame = webViewHelper.webView()->mainFrame();
5282
5283    FrameTestHelpers::loadFrame(frame,
5284        "javascript:document.body.appendChild(document.createElement('iframe'))");
5285    WebFrame* iframe = frame->firstChild();
5286    EXPECT_EQ(client.frame(), iframe);
5287    EXPECT_TRUE(client.replacesCurrentHistoryItem());
5288
5289    FrameTestHelpers::loadFrame(frame,
5290        "javascript:window.frames[0].location.assign('" + m_baseURL + "history.html')");
5291    EXPECT_EQ(client.frame(), iframe);
5292    EXPECT_TRUE(client.replacesCurrentHistoryItem());
5293
5294    FrameTestHelpers::loadFrame(frame,
5295        "javascript:window.frames[0].location.assign('" + m_baseURL + "find.html')");
5296    EXPECT_EQ(client.frame(), iframe);
5297    EXPECT_FALSE(client.replacesCurrentHistoryItem());
5298
5299    // Repeat the test, but start out the iframe with initial URL, which is not
5300    // "about:blank".
5301    FrameTestHelpers::loadFrame(frame,
5302        "javascript:var f = document.createElement('iframe'); "
5303        "f.src = '" + m_baseURL + "history.html';"
5304        "document.body.appendChild(f)");
5305
5306    iframe = frame->firstChild()->nextSibling();
5307    EXPECT_EQ(client.frame(), iframe);
5308    EXPECT_TRUE(client.replacesCurrentHistoryItem());
5309
5310    FrameTestHelpers::loadFrame(frame,
5311        "javascript:window.frames[1].location.assign('" + m_baseURL + "find.html')");
5312    EXPECT_EQ(client.frame(), iframe);
5313    EXPECT_FALSE(client.replacesCurrentHistoryItem());
5314}
5315
5316// Test verifies that layout will change a layer's scrollable attibutes
5317TEST_F(WebFrameTest, overflowHiddenRewrite)
5318{
5319    registerMockedHttpURLLoad("non-scrollable.html");
5320    TestMainFrameUserOrProgrammaticScrollFrameClient client;
5321    OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
5322    FrameTestHelpers::WebViewHelper webViewHelper;
5323    webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
5324
5325    webViewHelper.webView()->resize(WebSize(100, 100));
5326    FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "non-scrollable.html");
5327
5328    WebCore::RenderLayerCompositor* compositor =  webViewHelper.webViewImpl()->compositor();
5329    ASSERT_TRUE(compositor->scrollLayer());
5330
5331    // Verify that the WebLayer is not scrollable initially.
5332    WebCore::GraphicsLayer* scrollLayer = compositor->scrollLayer();
5333    WebLayer* webScrollLayer = scrollLayer->platformLayer();
5334    ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
5335    ASSERT_FALSE(webScrollLayer->userScrollableVertical());
5336
5337    // Call javascript to make the layer scrollable, and verify it.
5338    WebLocalFrameImpl* frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
5339    frame->executeScript(WebScriptSource("allowScroll();"));
5340    webViewHelper.webView()->layout();
5341    ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
5342    ASSERT_TRUE(webScrollLayer->userScrollableVertical());
5343}
5344
5345// Test that currentHistoryItem reflects the current page, not the provisional load.
5346TEST_F(WebFrameTest, CurrentHistoryItem)
5347{
5348    registerMockedHttpURLLoad("fixed_layout.html");
5349    std::string url = m_baseURL + "fixed_layout.html";
5350
5351    FrameTestHelpers::WebViewHelper webViewHelper;
5352    webViewHelper.initialize();
5353    WebFrame* frame = webViewHelper.webView()->mainFrame();
5354    const WebCore::FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5355    WebURLRequest request;
5356    request.initialize();
5357    request.setURL(toKURL(url));
5358    frame->loadRequest(request);
5359
5360    // Before commit, there is no history item.
5361    EXPECT_FALSE(mainFrameLoader.currentItem());
5362
5363    FrameTestHelpers::pumpPendingRequestsDoNotUse(frame);
5364
5365    // After commit, there is.
5366    WebCore::HistoryItem* item = mainFrameLoader.currentItem();
5367    ASSERT_TRUE(item);
5368    EXPECT_EQ(WTF::String(url.data()), item->urlString());
5369}
5370
5371class FailCreateChildFrame : public FrameTestHelpers::TestWebFrameClient {
5372public:
5373    FailCreateChildFrame() : m_callCount(0) { }
5374
5375    virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE
5376    {
5377        ++m_callCount;
5378        return 0;
5379    }
5380
5381    int callCount() const { return m_callCount; }
5382
5383private:
5384    int m_callCount;
5385};
5386
5387// Test that we don't crash if WebFrameClient::createChildFrame() fails.
5388TEST_F(WebFrameTest, CreateChildFrameFailure)
5389{
5390    registerMockedHttpURLLoad("create_child_frame_fail.html");
5391    FailCreateChildFrame client;
5392    FrameTestHelpers::WebViewHelper webViewHelper;
5393    webViewHelper.initializeAndLoad(m_baseURL + "create_child_frame_fail.html", true, &client);
5394
5395    EXPECT_EQ(1, client.callCount());
5396}
5397
5398TEST_F(WebFrameTest, fixedPositionInFixedViewport)
5399{
5400    UseMockScrollbarSettings mockScrollbarSettings;
5401    registerMockedHttpURLLoad("fixed-position-in-fixed-viewport.html");
5402    FrameTestHelpers::WebViewHelper webViewHelper;
5403    webViewHelper.initializeAndLoad(m_baseURL + "fixed-position-in-fixed-viewport.html", true, 0, 0, enableViewportSettings);
5404
5405    WebView* webView = webViewHelper.webView();
5406    webView->resize(WebSize(100, 100));
5407    webView->layout();
5408
5409    Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5410    Element* bottomFixed = document->getElementById("bottom-fixed");
5411    Element* topBottomFixed = document->getElementById("top-bottom-fixed");
5412    Element* rightFixed = document->getElementById("right-fixed");
5413    Element* leftRightFixed = document->getElementById("left-right-fixed");
5414
5415    webView->resize(WebSize(100, 200));
5416    webView->layout();
5417    EXPECT_EQ(200, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5418    EXPECT_EQ(200, topBottomFixed->offsetHeight());
5419
5420    webView->settings()->setMainFrameResizesAreOrientationChanges(false);
5421    webView->resize(WebSize(200, 200));
5422    webView->layout();
5423    EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5424    EXPECT_EQ(200, leftRightFixed->offsetWidth());
5425
5426    webView->settings()->setMainFrameResizesAreOrientationChanges(true);
5427    // Will scale the page by 1.5.
5428    webView->resize(WebSize(300, 330));
5429    webView->layout();
5430    EXPECT_EQ(220, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5431    EXPECT_EQ(220, topBottomFixed->offsetHeight());
5432    EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5433    EXPECT_EQ(200, leftRightFixed->offsetWidth());
5434}
5435
5436TEST_F(WebFrameTest, FrameViewSetFrameRect)
5437{
5438    FrameTestHelpers::WebViewHelper webViewHelper;
5439    webViewHelper.initializeAndLoad("about:blank");
5440
5441    WebCore::FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
5442    frameView->setFrameRect(WebCore::IntRect(0, 0, 200, 200));
5443    EXPECT_EQ_RECT(WebCore::IntRect(0, 0, 200, 200), frameView->frameRect());
5444    frameView->setFrameRect(WebCore::IntRect(100, 100, 200, 200));
5445    EXPECT_EQ_RECT(WebCore::IntRect(100, 100, 200, 200), frameView->frameRect());
5446}
5447
5448TEST_F(WebFrameTest, FullscreenLayerNonScrollable)
5449{
5450    FakeCompositingWebViewClient client;
5451    registerMockedHttpURLLoad("fullscreen_div.html");
5452    FrameTestHelpers::WebViewHelper webViewHelper;
5453    int viewportWidth = 640;
5454    int viewportHeight = 480;
5455    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5456    webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5457    webViewImpl->layout();
5458
5459    Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5460    WebCore::UserGestureIndicator gesture(WebCore::DefinitelyProcessingUserGesture);
5461    Element* divFullscreen = document->getElementById("div1");
5462    divFullscreen->webkitRequestFullscreen();
5463    webViewImpl->willEnterFullScreen();
5464    webViewImpl->didEnterFullScreen();
5465    webViewImpl->layout();
5466
5467    // Verify that the main frame is not scrollable.
5468    ASSERT_TRUE(WebCore::FullscreenElementStack::isFullScreen(*document));
5469    WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5470    ASSERT_FALSE(webScrollLayer->scrollable());
5471
5472    // Verify that the main frame is scrollable upon exiting fullscreen.
5473    webViewImpl->willExitFullScreen();
5474    webViewImpl->didExitFullScreen();
5475    webViewImpl->layout();
5476    ASSERT_FALSE(WebCore::FullscreenElementStack::isFullScreen(*document));
5477    webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5478    ASSERT_TRUE(webScrollLayer->scrollable());
5479}
5480
5481TEST_F(WebFrameTest, FullscreenMainFrameScrollable)
5482{
5483    FakeCompositingWebViewClient client;
5484    registerMockedHttpURLLoad("fullscreen_div.html");
5485    FrameTestHelpers::WebViewHelper webViewHelper;
5486    int viewportWidth = 640;
5487    int viewportHeight = 480;
5488    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5489    webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5490    webViewImpl->layout();
5491
5492    Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5493    WebCore::UserGestureIndicator gesture(WebCore::DefinitelyProcessingUserGesture);
5494    document->documentElement()->webkitRequestFullscreen();
5495    webViewImpl->willEnterFullScreen();
5496    webViewImpl->didEnterFullScreen();
5497    webViewImpl->layout();
5498
5499    // Verify that the main frame is still scrollable.
5500    ASSERT_TRUE(WebCore::FullscreenElementStack::isFullScreen(*document));
5501    WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5502    ASSERT_TRUE(webScrollLayer->scrollable());
5503}
5504
5505TEST_F(WebFrameTest, RenderBlockPercentHeightDescendants)
5506{
5507    registerMockedHttpURLLoad("percent-height-descendants.html");
5508    FrameTestHelpers::WebViewHelper webViewHelper;
5509    webViewHelper.initializeAndLoad(m_baseURL + "percent-height-descendants.html");
5510
5511    WebView* webView = webViewHelper.webView();
5512    webView->resize(WebSize(800, 800));
5513    webView->layout();
5514
5515    Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5516    WebCore::RenderBlock* container = WebCore::toRenderBlock(document->getElementById("container")->renderer());
5517    WebCore::RenderBox* percentHeightInAnonymous = WebCore::toRenderBox(document->getElementById("percent-height-in-anonymous")->renderer());
5518    WebCore::RenderBox* percentHeightDirectChild = WebCore::toRenderBox(document->getElementById("percent-height-direct-child")->renderer());
5519
5520    EXPECT_TRUE(WebCore::RenderBlock::hasPercentHeightDescendant(percentHeightInAnonymous));
5521    EXPECT_TRUE(WebCore::RenderBlock::hasPercentHeightDescendant(percentHeightDirectChild));
5522
5523    ASSERT_TRUE(container->percentHeightDescendants());
5524    ASSERT_TRUE(container->hasPercentHeightDescendants());
5525    EXPECT_EQ(2U, container->percentHeightDescendants()->size());
5526    EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightInAnonymous));
5527    EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightDirectChild));
5528
5529    WebCore::RenderBlock* anonymousBlock = percentHeightInAnonymous->containingBlock();
5530    EXPECT_TRUE(anonymousBlock->isAnonymous());
5531    EXPECT_FALSE(anonymousBlock->hasPercentHeightDescendants());
5532}
5533
5534TEST_F(WebFrameTest, HasVisibleContentOnVisibleFrames)
5535{
5536    registerMockedHttpURLLoad("visible_frames.html");
5537    FrameTestHelpers::WebViewHelper webViewHelper;
5538    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "visible_frames.html");
5539    for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5540        EXPECT_TRUE(frame->hasVisibleContent());
5541    }
5542}
5543
5544TEST_F(WebFrameTest, HasVisibleContentOnHiddenFrames)
5545{
5546    registerMockedHttpURLLoad("hidden_frames.html");
5547    FrameTestHelpers::WebViewHelper webViewHelper;
5548    WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "hidden_frames.html");
5549    for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5550        EXPECT_FALSE(frame->hasVisibleContent());
5551    }
5552}
5553
5554class ManifestChangeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5555public:
5556    ManifestChangeWebFrameClient() : m_manifestChangeCount(0) { }
5557    virtual void didChangeManifest(WebLocalFrame*) OVERRIDE
5558    {
5559        ++m_manifestChangeCount;
5560    }
5561
5562    int manifestChangeCount() { return m_manifestChangeCount; }
5563
5564private:
5565    int m_manifestChangeCount;
5566};
5567
5568TEST_F(WebFrameTest, NotifyManifestChange)
5569{
5570    registerMockedHttpURLLoad("link-manifest-change.html");
5571
5572    ManifestChangeWebFrameClient webFrameClient;
5573    FrameTestHelpers::WebViewHelper webViewHelper;
5574    webViewHelper.initializeAndLoad(m_baseURL + "link-manifest-change.html", true, &webFrameClient);
5575
5576    EXPECT_EQ(14, webFrameClient.manifestChangeCount());
5577}
5578
5579TEST_F(WebFrameTest, ReloadBypassingCache)
5580{
5581    // Check that a reload ignoring cache on a frame will result in the cache
5582    // policy of the request being set to ReloadBypassingCache.
5583    registerMockedHttpURLLoad("foo.html");
5584    FrameTestHelpers::WebViewHelper webViewHelper;
5585    webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
5586    WebFrame* frame = webViewHelper.webView()->mainFrame();
5587    FrameTestHelpers::reloadFrameIgnoringCache(frame);
5588    EXPECT_EQ(WebURLRequest::ReloadBypassingCache, frame->dataSource()->request().cachePolicy());
5589}
5590
5591static void nodeImageTestValidation(const WebCore::IntSize& referenceBitmapSize, WebCore::DragImage* dragImage)
5592{
5593    // Prepare the reference bitmap.
5594    SkBitmap bitmap;
5595    ASSERT_TRUE(bitmap.allocN32Pixels(referenceBitmapSize.width(), referenceBitmapSize.height()));
5596    SkCanvas canvas(bitmap);
5597    canvas.drawColor(SK_ColorGREEN);
5598
5599    EXPECT_EQ(referenceBitmapSize.width(), dragImage->size().width());
5600    EXPECT_EQ(referenceBitmapSize.height(), dragImage->size().height());
5601    const SkBitmap& dragBitmap = dragImage->bitmap();
5602    SkAutoLockPixels lockPixel(dragBitmap);
5603    EXPECT_EQ(0, memcmp(bitmap.getPixels(), dragBitmap.getPixels(), bitmap.getSize()));
5604}
5605
5606TEST_F(WebFrameTest, NodeImageTestCSSTransform)
5607{
5608    FrameTestHelpers::WebViewHelper webViewHelper;
5609    OwnPtr<WebCore::DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-transform"));
5610    EXPECT_TRUE(dragImage);
5611
5612    nodeImageTestValidation(WebCore::IntSize(40, 40), dragImage.get());
5613}
5614
5615TEST_F(WebFrameTest, NodeImageTestCSS3DTransform)
5616{
5617    FrameTestHelpers::WebViewHelper webViewHelper;
5618    OwnPtr<WebCore::DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-3dtransform"));
5619    EXPECT_TRUE(dragImage);
5620
5621    nodeImageTestValidation(WebCore::IntSize(20, 40), dragImage.get());
5622}
5623
5624TEST_F(WebFrameTest, NodeImageTestInlineBlock)
5625{
5626    FrameTestHelpers::WebViewHelper webViewHelper;
5627    OwnPtr<WebCore::DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-inlineblock"));
5628    EXPECT_TRUE(dragImage);
5629
5630    nodeImageTestValidation(WebCore::IntSize(40, 40), dragImage.get());
5631}
5632
5633TEST_F(WebFrameTest, NodeImageTestFloatLeft)
5634{
5635    FrameTestHelpers::WebViewHelper webViewHelper;
5636    OwnPtr<WebCore::DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-float-left-overflow-hidden"));
5637    EXPECT_TRUE(dragImage);
5638
5639    nodeImageTestValidation(WebCore::IntSize(40, 40), dragImage.get());
5640}
5641
5642class ThemeColorTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5643public:
5644    ThemeColorTestWebFrameClient()
5645        : m_didNotify(false)
5646    {
5647    }
5648
5649    void reset()
5650    {
5651        m_didNotify = false;
5652    }
5653
5654    bool didNotify() const
5655    {
5656        return m_didNotify;
5657    }
5658
5659private:
5660    virtual void didChangeThemeColor()
5661    {
5662        m_didNotify = true;
5663    }
5664
5665    bool m_didNotify;
5666};
5667
5668TEST_F(WebFrameTest, ThemeColor)
5669{
5670    registerMockedHttpURLLoad("theme_color_test.html");
5671    FrameTestHelpers::WebViewHelper webViewHelper;
5672    ThemeColorTestWebFrameClient client;
5673    webViewHelper.initializeAndLoad(m_baseURL + "theme_color_test.html", true, &client);
5674    EXPECT_TRUE(client.didNotify());
5675    WebLocalFrameImpl* frame = webViewHelper.webViewImpl()->mainFrameImpl();
5676    EXPECT_EQ(0xff0000ff, frame->document().themeColor());
5677    // Change color by rgb.
5678    client.reset();
5679    frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'rgb(0, 0, 0)');"));
5680    EXPECT_TRUE(client.didNotify());
5681    EXPECT_EQ(0xff000000, frame->document().themeColor());
5682    // Change color by hsl.
5683    client.reset();
5684    frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'hsl(240,100%, 50%)');"));
5685    EXPECT_TRUE(client.didNotify());
5686    EXPECT_EQ(0xff0000ff, frame->document().themeColor());
5687    // Change of second theme-color meta tag will not change frame's theme
5688    // color.
5689    client.reset();
5690    frame->executeScript(WebScriptSource("document.getElementById('tc2').setAttribute('content', '#00FF00');"));
5691    EXPECT_TRUE(client.didNotify());
5692    EXPECT_EQ(0xff0000ff, frame->document().themeColor());
5693}
5694
5695} // namespace
5696