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