Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / web / tests / WebFrameTest.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "public/web/WebFrame.h"
34
35 #include "SkBitmap.h"
36 #include "SkCanvas.h"
37 #include "bindings/core/v8/V8Node.h"
38 #include "core/UserAgentStyleSheets.h"
39 #include "core/clipboard/DataTransfer.h"
40 #include "core/css/StyleSheetContents.h"
41 #include "core/css/resolver/StyleResolver.h"
42 #include "core/css/resolver/ViewportStyleResolver.h"
43 #include "core/dom/DocumentMarkerController.h"
44 #include "core/dom/Fullscreen.h"
45 #include "core/dom/NodeRenderStyle.h"
46 #include "core/dom/Range.h"
47 #include "core/editing/Editor.h"
48 #include "core/editing/FrameSelection.h"
49 #include "core/editing/SpellChecker.h"
50 #include "core/editing/VisiblePosition.h"
51 #include "core/events/MouseEvent.h"
52 #include "core/fetch/MemoryCache.h"
53 #include "core/frame/FrameHost.h"
54 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h"
56 #include "core/frame/PinchViewport.h"
57 #include "core/frame/Settings.h"
58 #include "core/html/HTMLDocument.h"
59 #include "core/html/HTMLFormElement.h"
60 #include "core/loader/DocumentThreadableLoader.h"
61 #include "core/loader/DocumentThreadableLoaderClient.h"
62 #include "core/loader/FrameLoadRequest.h"
63 #include "core/loader/ThreadableLoader.h"
64 #include "core/page/EventHandler.h"
65 #include "core/page/Page.h"
66 #include "core/rendering/HitTestResult.h"
67 #include "core/rendering/RenderView.h"
68 #include "core/rendering/compositing/RenderLayerCompositor.h"
69 #include "core/testing/URLTestHelpers.h"
70 #include "platform/DragImage.h"
71 #include "platform/RuntimeEnabledFeatures.h"
72 #include "platform/UserGestureIndicator.h"
73 #include "platform/geometry/FloatRect.h"
74 #include "platform/network/ResourceError.h"
75 #include "platform/scroll/ScrollbarTheme.h"
76 #include "platform/weborigin/SchemeRegistry.h"
77 #include "public/platform/Platform.h"
78 #include "public/platform/WebFloatRect.h"
79 #include "public/platform/WebSelectionBound.h"
80 #include "public/platform/WebThread.h"
81 #include "public/platform/WebURL.h"
82 #include "public/platform/WebURLResponse.h"
83 #include "public/platform/WebUnitTestSupport.h"
84 #include "public/web/WebCache.h"
85 #include "public/web/WebDataSource.h"
86 #include "public/web/WebDocument.h"
87 #include "public/web/WebFindOptions.h"
88 #include "public/web/WebFormElement.h"
89 #include "public/web/WebFrameClient.h"
90 #include "public/web/WebHistoryItem.h"
91 #include "public/web/WebPrintParams.h"
92 #include "public/web/WebRange.h"
93 #include "public/web/WebRemoteFrame.h"
94 #include "public/web/WebScriptSource.h"
95 #include "public/web/WebSearchableFormData.h"
96 #include "public/web/WebSecurityOrigin.h"
97 #include "public/web/WebSecurityPolicy.h"
98 #include "public/web/WebSettings.h"
99 #include "public/web/WebSpellCheckClient.h"
100 #include "public/web/WebTextCheckingCompletion.h"
101 #include "public/web/WebTextCheckingResult.h"
102 #include "public/web/WebViewClient.h"
103 #include "web/WebLocalFrameImpl.h"
104 #include "web/WebRemoteFrameImpl.h"
105 #include "web/WebViewImpl.h"
106 #include "web/tests/FrameTestHelpers.h"
107 #include "wtf/Forward.h"
108 #include "wtf/dtoa/utils.h"
109 #include <gmock/gmock.h>
110 #include <gtest/gtest.h>
111 #include <map>
112 #include <v8.h>
113
114 namespace {
115
116 using blink::URLTestHelpers::toKURL;
117 using blink::FrameTestHelpers::runPendingTasks;
118 using namespace blink;
119
120 const int touchPointPadding = 32;
121
122 #define EXPECT_RECT_EQ(a, b) \
123     do {                                   \
124         EXPECT_EQ(a.x(), b.x());           \
125         EXPECT_EQ(a.y(), b.y());           \
126         EXPECT_EQ(a.width(), b.width());   \
127         EXPECT_EQ(a.height(), b.height()); \
128     } while (false)
129
130 #define EXPECT_POINT_EQ(expected, actual) \
131     do { \
132         EXPECT_EQ((expected).x(), (actual).x()); \
133         EXPECT_EQ((expected).y(), (actual).y()); \
134     } while (false)
135
136 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \
137     do { \
138         EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \
139         EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
140     } while (false)
141
142 #define EXPECT_EQ_POINT(a, b) \
143     EXPECT_EQ(a.x(), b.x()); \
144     EXPECT_EQ(a.y(), b.y());
145
146 class FakeCompositingWebViewClient : public FrameTestHelpers::TestWebViewClient {
147 public:
148     virtual bool enterFullScreen() OVERRIDE { return true; }
149 };
150
151 class WebFrameTest : public testing::Test {
152 protected:
153     WebFrameTest()
154         : m_baseURL("http://www.test.com/")
155         , m_chromeURL("chrome://")
156     {
157     }
158
159     virtual ~WebFrameTest()
160     {
161         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
162     }
163
164     void registerMockedHttpURLLoad(const std::string& fileName)
165     {
166         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
167     }
168
169     void registerMockedChromeURLLoad(const std::string& fileName)
170     {
171         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_chromeURL.c_str()), WebString::fromUTF8(fileName.c_str()));
172     }
173
174     void applyViewportStyleOverride(FrameTestHelpers::WebViewHelper* webViewHelper)
175     {
176         RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0));
177         styleSheet->parseString(String(blink::viewportAndroidCss, sizeof(blink::viewportAndroidCss)));
178         OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
179         ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen"));
180
181         Document* document = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame())->document();
182         document->ensureStyleResolver().viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin);
183         document->ensureStyleResolver().viewportStyleResolver()->resolve();
184     }
185
186     static void configueCompositingWebView(WebSettings* settings)
187     {
188         settings->setAcceleratedCompositingEnabled(true);
189         settings->setPreferCompositingToLCDTextEnabled(true);
190     }
191
192     static void configureLoadsImagesAutomatically(WebSettings* settings)
193     {
194         settings->setLoadsImagesAutomatically(true);
195     }
196
197     void initializeTextSelectionWebView(const std::string& url, FrameTestHelpers::WebViewHelper* webViewHelper)
198     {
199         webViewHelper->initializeAndLoad(url, true);
200         webViewHelper->webView()->settings()->setDefaultFontSize(12);
201         webViewHelper->webView()->resize(WebSize(640, 480));
202     }
203
204     PassOwnPtr<DragImage> nodeImageTestSetup(FrameTestHelpers::WebViewHelper* webViewHelper, const std::string& testcase)
205     {
206         registerMockedHttpURLLoad("nodeimage.html");
207         webViewHelper->initializeAndLoad(m_baseURL + "nodeimage.html");
208         webViewHelper->webView()->resize(WebSize(640, 480));
209         webViewHelper->webView()->layout();
210         RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame());
211         ASSERT(frame);
212         Element* element = frame->document()->getElementById(testcase.c_str());
213         return frame->nodeImage(*element);
214     }
215
216     std::string m_baseURL;
217     std::string m_chromeURL;
218 };
219
220 class UseMockScrollbarSettings {
221 public:
222     UseMockScrollbarSettings()
223     {
224         Settings::setMockScrollbarsEnabled(true);
225         RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true);
226         EXPECT_TRUE(ScrollbarTheme::theme()->usesOverlayScrollbars());
227     }
228
229     ~UseMockScrollbarSettings()
230     {
231         Settings::setMockScrollbarsEnabled(false);
232         RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(false);
233     }
234 };
235
236 TEST_F(WebFrameTest, ContentText)
237 {
238     registerMockedHttpURLLoad("iframes_test.html");
239     registerMockedHttpURLLoad("visible_iframe.html");
240     registerMockedHttpURLLoad("invisible_iframe.html");
241     registerMockedHttpURLLoad("zero_sized_iframe.html");
242
243     FrameTestHelpers::WebViewHelper webViewHelper;
244     webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html");
245
246     // Now retrieve the frames text and test it only includes visible elements.
247     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
248     EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
249     EXPECT_NE(std::string::npos, content.find(" visible iframe"));
250     EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
251     EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
252     EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
253 }
254
255 TEST_F(WebFrameTest, FrameForEnteredContext)
256 {
257     registerMockedHttpURLLoad("iframes_test.html");
258     registerMockedHttpURLLoad("visible_iframe.html");
259     registerMockedHttpURLLoad("invisible_iframe.html");
260     registerMockedHttpURLLoad("zero_sized_iframe.html");
261
262     FrameTestHelpers::WebViewHelper webViewHelper;
263     webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html", true);
264
265     v8::HandleScope scope(v8::Isolate::GetCurrent());
266     EXPECT_EQ(webViewHelper.webView()->mainFrame(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->mainWorldScriptContext()));
267     EXPECT_EQ(webViewHelper.webView()->mainFrame()->firstChild(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->firstChild()->mainWorldScriptContext()));
268 }
269
270 TEST_F(WebFrameTest, FormWithNullFrame)
271 {
272     registerMockedHttpURLLoad("form.html");
273
274     FrameTestHelpers::WebViewHelper webViewHelper;
275     webViewHelper.initializeAndLoad(m_baseURL + "form.html");
276
277     WebVector<WebFormElement> forms;
278     webViewHelper.webView()->mainFrame()->document().forms(forms);
279     webViewHelper.reset();
280
281     EXPECT_EQ(forms.size(), 1U);
282
283     // This test passes if this doesn't crash.
284     WebSearchableFormData searchableDataForm(forms[0]);
285 }
286
287 TEST_F(WebFrameTest, ChromePageJavascript)
288 {
289     registerMockedChromeURLLoad("history.html");
290
291     // Pass true to enable JavaScript.
292     FrameTestHelpers::WebViewHelper webViewHelper;
293     webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
294
295     // Try to run JS against the chrome-style URL.
296     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
297
298     // Required to see any updates in contentAsText.
299     webViewHelper.webView()->layout();
300
301     // Now retrieve the frame's text and ensure it was modified by running javascript.
302     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
303     EXPECT_NE(std::string::npos, content.find("Clobbered"));
304 }
305
306 TEST_F(WebFrameTest, ChromePageNoJavascript)
307 {
308     registerMockedChromeURLLoad("history.html");
309
310     /// Pass true to enable JavaScript.
311     FrameTestHelpers::WebViewHelper webViewHelper;
312     webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
313
314     // Try to run JS against the chrome-style URL after prohibiting it.
315     WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
316     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
317
318     // Required to see any updates in contentAsText.
319     webViewHelper.webView()->layout();
320
321     // Now retrieve the frame's text and ensure it wasn't modified by running javascript.
322     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
323     EXPECT_EQ(std::string::npos, content.find("Clobbered"));
324 }
325
326 TEST_F(WebFrameTest, LocationSetHostWithMissingPort)
327 {
328     std::string fileName = "print-location-href.html";
329     registerMockedHttpURLLoad(fileName);
330     URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName));
331
332     FrameTestHelpers::WebViewHelper webViewHelper;
333
334     /// Pass true to enable JavaScript.
335     webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
336
337     // Setting host to "hostname:" should be treated as "hostname:0".
338     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.host = 'www.test.com:'; void 0;");
339
340     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
341
342     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
343     EXPECT_EQ("http://www.test.com:0/" + fileName, content);
344 }
345
346 TEST_F(WebFrameTest, LocationSetEmptyPort)
347 {
348     std::string fileName = "print-location-href.html";
349     registerMockedHttpURLLoad(fileName);
350     URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName));
351
352     FrameTestHelpers::WebViewHelper webViewHelper;
353
354     /// Pass true to enable JavaScript.
355     webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
356
357     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.port = ''; void 0;");
358
359     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;");
360
361     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
362     EXPECT_EQ("http://www.test.com:0/" + fileName, content);
363 }
364
365 class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
366 public:
367     CSSCallbackWebFrameClient() : m_updateCount(0) { }
368     virtual void didMatchCSS(WebLocalFrame*, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors) OVERRIDE;
369
370     std::map<WebLocalFrame*, std::set<std::string> > m_matchedSelectors;
371     int m_updateCount;
372 };
373
374 void CSSCallbackWebFrameClient::didMatchCSS(WebLocalFrame* frame, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors)
375 {
376     ++m_updateCount;
377     std::set<std::string>& frameSelectors = m_matchedSelectors[frame];
378     for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i) {
379         std::string selector = newlyMatchingSelectors[i].utf8();
380         EXPECT_EQ(0U, frameSelectors.count(selector)) << selector;
381         frameSelectors.insert(selector);
382     }
383     for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i) {
384         std::string selector = stoppedMatchingSelectors[i].utf8();
385         EXPECT_EQ(1U, frameSelectors.count(selector)) << selector;
386         frameSelectors.erase(selector);
387     }
388 }
389
390 class WebFrameCSSCallbackTest : public testing::Test {
391 protected:
392     WebFrameCSSCallbackTest()
393     {
394
395         m_frame = m_helper.initializeAndLoad("about:blank", true, &m_client)->mainFrame()->toWebLocalFrame();
396     }
397
398     ~WebFrameCSSCallbackTest()
399     {
400         EXPECT_EQ(1U, m_client.m_matchedSelectors.size());
401     }
402
403     WebDocument doc() const
404     {
405         return m_frame->document();
406     }
407
408     int updateCount() const
409     {
410         return m_client.m_updateCount;
411     }
412
413     const std::set<std::string>& matchedSelectors()
414     {
415         return m_client.m_matchedSelectors[m_frame];
416     }
417
418     void loadHTML(const std::string& html)
419     {
420         FrameTestHelpers::loadHTMLString(m_frame, html, toKURL("about:blank"));
421     }
422
423     void executeScript(const WebString& code)
424     {
425         m_frame->executeScript(WebScriptSource(code));
426         m_frame->view()->layout();
427         runPendingTasks();
428     }
429
430     CSSCallbackWebFrameClient m_client;
431     FrameTestHelpers::WebViewHelper m_helper;
432     WebLocalFrame* m_frame;
433 };
434
435 TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet)
436 {
437     loadHTML(
438         "<style>"
439         // This stylesheet checks that the internal property and value can't be
440         // set by a stylesheet, only WebDocument::watchCSSSelectors().
441         "div.initial_on { -internal-callback: none; }"
442         "div.initial_off { -internal-callback: -internal-presence; }"
443         "</style>"
444         "<div class=\"initial_on\"></div>"
445         "<div class=\"initial_off\"></div>");
446
447     std::vector<WebString> selectors;
448     selectors.push_back(WebString::fromUTF8("div.initial_on"));
449     m_frame->document().watchCSSSelectors(WebVector<WebString>(selectors));
450     m_frame->view()->layout();
451     runPendingTasks();
452     EXPECT_EQ(1, updateCount());
453     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_on"));
454
455     // Check that adding a watched selector calls back for already-present nodes.
456     selectors.push_back(WebString::fromUTF8("div.initial_off"));
457     doc().watchCSSSelectors(WebVector<WebString>(selectors));
458     m_frame->view()->layout();
459     runPendingTasks();
460     EXPECT_EQ(2, updateCount());
461     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_off", "div.initial_on"));
462
463     // Check that we can turn off callbacks for certain selectors.
464     doc().watchCSSSelectors(WebVector<WebString>());
465     m_frame->view()->layout();
466     runPendingTasks();
467     EXPECT_EQ(3, updateCount());
468     EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
469 }
470
471 TEST_F(WebFrameCSSCallbackTest, SharedRenderStyle)
472 {
473     // Check that adding an element calls back when it matches an existing rule.
474     std::vector<WebString> selectors;
475     selectors.push_back(WebString::fromUTF8("span"));
476     doc().watchCSSSelectors(WebVector<WebString>(selectors));
477
478     executeScript(
479         "i1 = document.createElement('span');"
480         "i1.id = 'first_span';"
481         "document.body.appendChild(i1)");
482     EXPECT_EQ(1, updateCount());
483     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
484
485     // Adding a second element that shares a RenderStyle shouldn't call back.
486     // We use <span>s to avoid default style rules that can set
487     // RenderStyle::unique().
488     executeScript(
489         "i2 = document.createElement('span');"
490         "i2.id = 'second_span';"
491         "i1 = document.getElementById('first_span');"
492         "i1.parentNode.insertBefore(i2, i1.nextSibling);");
493     EXPECT_EQ(1, updateCount());
494     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
495
496     // Removing the first element shouldn't call back.
497     executeScript(
498         "i1 = document.getElementById('first_span');"
499         "i1.parentNode.removeChild(i1);");
500     EXPECT_EQ(1, updateCount());
501     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
502
503     // But removing the second element *should* call back.
504     executeScript(
505         "i2 = document.getElementById('second_span');"
506         "i2.parentNode.removeChild(i2);");
507     EXPECT_EQ(2, updateCount());
508     EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
509 }
510
511 TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange)
512 {
513     loadHTML("<span></span>");
514
515     std::vector<WebString> selectors;
516     selectors.push_back(WebString::fromUTF8("span[attr=\"value\"]"));
517     doc().watchCSSSelectors(WebVector<WebString>(selectors));
518     runPendingTasks();
519
520     EXPECT_EQ(0, updateCount());
521     EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
522
523     executeScript(
524         "document.querySelector('span').setAttribute('attr', 'value');");
525     EXPECT_EQ(1, updateCount());
526     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span[attr=\"value\"]"));
527 }
528
529 TEST_F(WebFrameCSSCallbackTest, DisplayNone)
530 {
531     loadHTML("<div style='display:none'><span></span></div>");
532
533     std::vector<WebString> selectors;
534     selectors.push_back(WebString::fromUTF8("span"));
535     doc().watchCSSSelectors(WebVector<WebString>(selectors));
536     runPendingTasks();
537
538     EXPECT_EQ(0, updateCount()) << "Don't match elements in display:none trees.";
539
540     executeScript(
541         "d = document.querySelector('div');"
542         "d.style.display = 'block';");
543     EXPECT_EQ(1, updateCount()) << "Match elements when they become displayed.";
544     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
545
546     executeScript(
547         "d = document.querySelector('div');"
548         "d.style.display = 'none';");
549     EXPECT_EQ(2, updateCount()) << "Unmatch elements when they become undisplayed.";
550     EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
551
552     executeScript(
553         "s = document.querySelector('span');"
554         "s.style.display = 'none';");
555     EXPECT_EQ(2, updateCount()) << "No effect from no-display'ing a span that's already undisplayed.";
556
557     executeScript(
558         "d = document.querySelector('div');"
559         "d.style.display = 'block';");
560     EXPECT_EQ(2, updateCount()) << "No effect from displaying a div whose span is display:none.";
561
562     executeScript(
563         "s = document.querySelector('span');"
564         "s.style.display = 'inline';");
565     EXPECT_EQ(3, updateCount()) << "Now the span is visible and produces a callback.";
566     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
567
568     executeScript(
569         "s = document.querySelector('span');"
570         "s.style.display = 'none';");
571     EXPECT_EQ(4, updateCount()) << "Undisplaying the span directly should produce another callback.";
572     EXPECT_THAT(matchedSelectors(), testing::ElementsAre());
573 }
574
575 TEST_F(WebFrameCSSCallbackTest, Reparenting)
576 {
577     loadHTML(
578         "<div id='d1'><span></span></div>"
579         "<div id='d2'></div>");
580
581     std::vector<WebString> selectors;
582     selectors.push_back(WebString::fromUTF8("span"));
583     doc().watchCSSSelectors(WebVector<WebString>(selectors));
584     m_frame->view()->layout();
585     runPendingTasks();
586
587     EXPECT_EQ(1, updateCount());
588     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
589
590     executeScript(
591         "s = document.querySelector('span');"
592         "d2 = document.getElementById('d2');"
593         "d2.appendChild(s);");
594     EXPECT_EQ(1, updateCount()) << "Just moving an element that continues to match shouldn't send a spurious callback.";
595     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"));
596 }
597
598 TEST_F(WebFrameCSSCallbackTest, MultiSelector)
599 {
600     loadHTML("<span></span>");
601
602     // Check that selector lists match as the whole list, not as each element
603     // independently.
604     std::vector<WebString> selectors;
605     selectors.push_back(WebString::fromUTF8("span"));
606     selectors.push_back(WebString::fromUTF8("span,p"));
607     doc().watchCSSSelectors(WebVector<WebString>(selectors));
608     m_frame->view()->layout();
609     runPendingTasks();
610
611     EXPECT_EQ(1, updateCount());
612     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span", "span, p"));
613 }
614
615 TEST_F(WebFrameCSSCallbackTest, InvalidSelector)
616 {
617     loadHTML("<p><span></span></p>");
618
619     // Build a list with one valid selector and one invalid.
620     std::vector<WebString> selectors;
621     selectors.push_back(WebString::fromUTF8("span"));
622     selectors.push_back(WebString::fromUTF8("[")); // Invalid.
623     selectors.push_back(WebString::fromUTF8("p span")); // Not compound.
624     doc().watchCSSSelectors(WebVector<WebString>(selectors));
625     m_frame->view()->layout();
626     runPendingTasks();
627
628     EXPECT_EQ(1, updateCount());
629     EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span"))
630         << "An invalid selector shouldn't prevent other selectors from matching.";
631 }
632
633 TEST_F(WebFrameTest, DispatchMessageEventWithOriginCheck)
634 {
635     registerMockedHttpURLLoad("postmessage_test.html");
636
637     // Pass true to enable JavaScript.
638     FrameTestHelpers::WebViewHelper webViewHelper;
639     webViewHelper.initializeAndLoad(m_baseURL + "postmessage_test.html", true);
640
641     // Send a message with the correct origin.
642     WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL)));
643     WebDOMEvent event = webViewHelper.webView()->mainFrame()->document().createEvent("MessageEvent");
644     WebDOMMessageEvent message = event.to<WebDOMMessageEvent>();
645     WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
646     message.initMessageEvent("message", false, false, data, "http://origin.com", 0, "");
647     webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message);
648
649     // Send another message with incorrect origin.
650     WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(toKURL(m_chromeURL)));
651     webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message);
652
653     // Required to see any updates in contentAsText.
654     webViewHelper.webView()->layout();
655
656     // Verify that only the first addition is in the body of the page.
657     std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8();
658     EXPECT_NE(std::string::npos, content.find("Message 1."));
659     EXPECT_EQ(std::string::npos, content.find("Message 2."));
660 }
661
662 TEST_F(WebFrameTest, PostMessageThenDetach)
663 {
664     FrameTestHelpers::WebViewHelper webViewHelper;
665     webViewHelper.initializeAndLoad("about:blank");
666
667     RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame());
668     NonThrowableExceptionState exceptionState;
669     frame->domWindow()->postMessage(SerializedScriptValue::create("message"), 0, "*", frame->domWindow(), exceptionState);
670     webViewHelper.reset();
671     EXPECT_FALSE(exceptionState.hadException());
672
673     // Success is not crashing.
674     runPendingTasks();
675 }
676
677 class FixedLayoutTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
678  public:
679     virtual WebScreenInfo screenInfo() OVERRIDE { return m_screenInfo; }
680
681     WebScreenInfo m_screenInfo;
682 };
683
684 // Viewport settings need to be set before the page gets loaded
685 static void enableViewportSettings(WebSettings* settings)
686 {
687     settings->setViewportMetaEnabled(true);
688     settings->setViewportEnabled(true);
689     settings->setMainFrameResizesAreOrientationChanges(true);
690     settings->setShrinksViewportContentToFit(true);
691 }
692
693 // Helper function to check or set text autosizing multipliers on a document.
694 static bool checkOrSetTextAutosizingMultiplier(Document* document, float multiplier, bool setMultiplier)
695 {
696     bool multiplierCheckedOrSetAtLeastOnce = false;
697     for (RenderObject* renderer = document->renderView(); renderer; renderer = renderer->nextInPreOrder()) {
698         if (renderer->style()) {
699             if (setMultiplier)
700                 renderer->style()->setTextAutosizingMultiplier(multiplier);
701             EXPECT_EQ(multiplier, renderer->style()->textAutosizingMultiplier());
702             multiplierCheckedOrSetAtLeastOnce = true;
703         }
704     }
705     return multiplierCheckedOrSetAtLeastOnce;
706
707 }
708
709 static bool setTextAutosizingMultiplier(Document* document, float multiplier)
710 {
711     return checkOrSetTextAutosizingMultiplier(document, multiplier, true);
712 }
713
714 static bool checkTextAutosizingMultiplier(Document* document, float multiplier)
715 {
716     return checkOrSetTextAutosizingMultiplier(document, multiplier, false);
717 }
718
719 TEST_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
748 TEST_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
790 TEST_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
807 TEST_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
836 TEST_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
873 TEST_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
910 TEST_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
934 TEST_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
954 TEST_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
975 TEST_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
996 TEST_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
1018 TEST_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
1039 TEST_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
1058 TEST_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
1079 TEST_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
1098 TEST_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
1130 TEST_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
1150 TEST_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
1169 TEST_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
1205 TEST_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
1227 TEST_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
1261 TEST_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
1285 TEST_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
1307 TEST_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
1333 TEST_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
1357 TEST_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
1409 TEST_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
1436 TEST_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
1454 TEST_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
1473 TEST_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
1500 TEST_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
1522 TEST_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
1545 TEST_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
1564 TEST_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
1584 TEST_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
1619 TEST_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
1640 TEST_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
1672 TEST_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
1698 TEST_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
1725 TEST_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
1748 TEST_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
1772 TEST_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
1795 TEST_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
1815 TEST_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
1839 TEST_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
1860 TEST_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
1880 class WebFrameResizeTest : public WebFrameTest {
1881 protected:
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
1958 TEST_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
1972 TEST_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
1988 TEST_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
2001 TEST_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
2014 TEST_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
2063 TEST_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
2088 TEST_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
2119 TEST_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
2146 void 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
2153 TEST_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
2212 void 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
2220 void simulateMultiTargetZoom(WebViewImpl* webViewImpl, const WebRect& rect, float& scale)
2221 {
2222     if (webViewImpl->zoomToMultipleTargetsRect(rect))
2223         simulatePageScale(webViewImpl, scale);
2224 }
2225
2226 void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale)
2227 {
2228     webViewImpl->animateDoubleTapZoom(point);
2229     EXPECT_TRUE(webViewImpl->fakeDoubleTapAnimationPendingForTesting());
2230     simulatePageScale(webViewImpl, scale);
2231 }
2232
2233 TEST_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
2264 TEST_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
2293 TEST_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
2342 TEST_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
2403 TEST_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
2481 TEST_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
2516 TEST_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
2594 TEST_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
2650 class TestReloadDoesntRedirectWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2651 public:
2652     virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE
2653     {
2654         EXPECT_FALSE(info.isRedirect);
2655         return WebNavigationPolicyCurrentTab;
2656     }
2657 };
2658
2659 TEST_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
2674 class ReloadWithOverrideURLTask : public WebThread::Task {
2675 public:
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
2686 private:
2687     WebFrame* const m_frame;
2688     const KURL m_url;
2689     const bool m_ignoreCache;
2690 };
2691
2692 TEST_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
2729 TEST_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
2749 TEST_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
2768 TEST_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
2789 TEST_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.
2806 class ContextLifetimeTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
2807 public:
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.
2865 TEST_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
2905 TEST_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
2942 TEST_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
2986 TEST_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
3043 TEST_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
3085 TEST_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
3119 class TestExecuteScriptDuringDidCreateScriptContext : public FrameTestHelpers::TestWebFrameClient {
3120 public:
3121     virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
3122     {
3123         frame->executeScript(WebScriptSource("window.history = 'replaced';"));
3124     }
3125 };
3126
3127 TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext)
3128 {
3129     registerMockedHttpURLLoad("hello_world.html");
3130
3131     TestExecuteScriptDuringDidCreateScriptContext webFrameClient;
3132     FrameTestHelpers::WebViewHelper webViewHelper;
3133     webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient);
3134
3135     FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame());
3136 }
3137
3138 class FindUpdateWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
3139 public:
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
3156 private:
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)
3164 TEST_F(WebFrameTest, DISABLED_FindInPageMatchRects)
3165 #else
3166 TEST_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
3286 TEST_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
3316 TEST_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
3355 TEST_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
3394 TEST_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
3433 TEST_F(WebFrameTest, ResetMatchCount)
3434 {
3435     registerMockedHttpURLLoad("find_in_generated_frame.html");
3436
3437     FindUpdateWebFrameClient client;
3438     FrameTestHelpers::WebViewHelper webViewHelper;
3439     webViewHelper.initializeAndLoad(m_baseURL + "find_in_generated_frame.html", true, &client);
3440     webViewHelper.webView()->resize(WebSize(640, 480));
3441     webViewHelper.webView()->layout();
3442     runPendingTasks();
3443
3444     static const char* kFindString = "result";
3445     static const int kFindIdentifier = 12345;
3446
3447     WebFindOptions options;
3448     WebString searchText = WebString::fromUTF8(kFindString);
3449     WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3450
3451     // Check that child frame exists.
3452     EXPECT_TRUE(!!mainFrame->traverseNext(false));
3453
3454     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) {
3455         EXPECT_FALSE(frame->find(kFindIdentifier, searchText, options, false, 0));
3456     }
3457
3458     runPendingTasks();
3459     EXPECT_FALSE(client.findResultsAreReady());
3460
3461     mainFrame->resetMatchCount();
3462 }
3463
3464 TEST_F(WebFrameTest, SetTickmarks)
3465 {
3466     registerMockedHttpURLLoad("find.html");
3467
3468     FindUpdateWebFrameClient client;
3469     FrameTestHelpers::WebViewHelper webViewHelper;
3470     webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client);
3471     webViewHelper.webView()->resize(WebSize(640, 480));
3472     webViewHelper.webView()->layout();
3473     runPendingTasks();
3474
3475     static const char* kFindString = "foo";
3476     static const int kFindIdentifier = 12345;
3477
3478     WebFindOptions options;
3479     WebString searchText = WebString::fromUTF8(kFindString);
3480     WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3481     EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
3482
3483     mainFrame->resetMatchCount();
3484     mainFrame->scopeStringMatches(kFindIdentifier, searchText, options, true);
3485
3486     runPendingTasks();
3487     EXPECT_TRUE(client.findResultsAreReady());
3488
3489     // Get the tickmarks for the original find request.
3490     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
3518 static WebPoint topLeft(const WebRect& rect)
3519 {
3520     return WebPoint(rect.x, rect.y);
3521 }
3522
3523 static WebPoint bottomRightMinusOne(const WebRect& rect)
3524 {
3525     // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
3526     // selection bounds, selectRange() will select the *next* element. That's
3527     // strictly correct, as hit-testing checks the pixel to the lower-right of
3528     // the input coordinate, but it's a wart on the API.
3529     return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1);
3530 }
3531
3532 static WebRect elementBounds(WebFrame* frame, const WebString& id)
3533 {
3534     return frame->document().getElementById(id).boundsInViewportSpace();
3535 }
3536
3537 static std::string selectionAsString(WebFrame* frame)
3538 {
3539     return frame->selectionAsText().utf8();
3540 }
3541
3542 TEST_F(WebFrameTest, SelectRange)
3543 {
3544     WebFrame* frame;
3545     WebRect startWebRect;
3546     WebRect endWebRect;
3547
3548     registerMockedHttpURLLoad("select_range_basic.html");
3549     registerMockedHttpURLLoad("select_range_scroll.html");
3550
3551     FrameTestHelpers::WebViewHelper webViewHelper;
3552     initializeTextSelectionWebView(m_baseURL + "select_range_basic.html", &webViewHelper);
3553     frame = webViewHelper.webView()->mainFrame();
3554     EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3555     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3556     frame->executeCommand(WebString::fromUTF8("Unselect"));
3557     EXPECT_EQ("", selectionAsString(frame));
3558     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3559     EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
3560
3561     initializeTextSelectionWebView(m_baseURL + "select_range_scroll.html", &webViewHelper);
3562     frame = webViewHelper.webView()->mainFrame();
3563     EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3564     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3565     frame->executeCommand(WebString::fromUTF8("Unselect"));
3566     EXPECT_EQ("", selectionAsString(frame));
3567     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3568     EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
3569 }
3570
3571 TEST_F(WebFrameTest, SelectRangeInIframe)
3572 {
3573     WebFrame* frame;
3574     WebRect startWebRect;
3575     WebRect endWebRect;
3576
3577     registerMockedHttpURLLoad("select_range_iframe.html");
3578     registerMockedHttpURLLoad("select_range_basic.html");
3579
3580     FrameTestHelpers::WebViewHelper webViewHelper;
3581     initializeTextSelectionWebView(m_baseURL + "select_range_iframe.html", &webViewHelper);
3582     frame = webViewHelper.webView()->mainFrame();
3583     WebFrame* subframe = frame->firstChild();
3584     EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3585     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3586     subframe->executeCommand(WebString::fromUTF8("Unselect"));
3587     EXPECT_EQ("", selectionAsString(subframe));
3588     subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3589     EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
3590 }
3591
3592 TEST_F(WebFrameTest, SelectRangeDivContentEditable)
3593 {
3594     WebFrame* frame;
3595     WebRect startWebRect;
3596     WebRect endWebRect;
3597
3598     registerMockedHttpURLLoad("select_range_div_editable.html");
3599
3600     // Select the middle of an editable element, then try to extend the selection to the top of the document.
3601     // The selection range should be clipped to the bounds of the editable element.
3602     FrameTestHelpers::WebViewHelper webViewHelper;
3603     initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3604     frame = webViewHelper.webView()->mainFrame();
3605     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3606     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3607
3608     frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3609     EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3610
3611     // As above, but extending the selection to the bottom of the document.
3612     initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3613     frame = webViewHelper.webView()->mainFrame();
3614
3615     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3616     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3617     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3618     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3619
3620     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3621     frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3622     EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3623 }
3624
3625 // positionForPoint returns the wrong values for contenteditable spans. See
3626 // http://crbug.com/238334.
3627 TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable)
3628 {
3629     WebFrame* frame;
3630     WebRect startWebRect;
3631     WebRect endWebRect;
3632
3633     registerMockedHttpURLLoad("select_range_span_editable.html");
3634
3635     // Select the middle of an editable element, then try to extend the selection to the top of the document.
3636     // The selection range should be clipped to the bounds of the editable element.
3637     FrameTestHelpers::WebViewHelper webViewHelper;
3638     initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3639     frame = webViewHelper.webView()->mainFrame();
3640     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3641     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3642
3643     frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
3644     EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
3645
3646     // As above, but extending the selection to the bottom of the document.
3647     initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3648     frame = webViewHelper.webView()->mainFrame();
3649
3650     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3651     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
3652     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3653     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3654
3655     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
3656     webViewHelper.webView()->selectionBounds(startWebRect, endWebRect);
3657     frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
3658     EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
3659 }
3660
3661 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart)
3662 {
3663     registerMockedHttpURLLoad("text_selection.html");
3664     FrameTestHelpers::WebViewHelper webViewHelper;
3665     initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3666     WebFrame* frame = webViewHelper.webView()->mainFrame();
3667
3668     // Select second span. We can move the start to include the first span.
3669     frame->executeScript(WebScriptSource("selectElement('header_2');"));
3670     EXPECT_EQ("Header 2.", selectionAsString(frame));
3671     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3672     EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3673
3674     // We can move the start and end together.
3675     frame->executeScript(WebScriptSource("selectElement('header_1');"));
3676     EXPECT_EQ("Header 1.", selectionAsString(frame));
3677     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1")));
3678     EXPECT_EQ("", selectionAsString(frame));
3679     // Selection is a caret, not empty.
3680     EXPECT_FALSE(frame->selectionRange().isNull());
3681
3682     // We can move the start across the end.
3683     frame->executeScript(WebScriptSource("selectElement('header_1');"));
3684     EXPECT_EQ("Header 1.", selectionAsString(frame));
3685     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3686     EXPECT_EQ(" Header 2.", selectionAsString(frame));
3687
3688     // Can't extend the selection part-way into an editable element.
3689     frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3690     EXPECT_EQ("Footer 2.", selectionAsString(frame));
3691     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2")));
3692     EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame));
3693
3694     // Can extend the selection completely across editable elements.
3695     frame->executeScript(WebScriptSource("selectElement('footer_2');"));
3696     EXPECT_EQ("Footer 2.", selectionAsString(frame));
3697     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2")));
3698     EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame));
3699
3700     // If the selection is editable text, we can't extend it into non-editable text.
3701     frame->executeScript(WebScriptSource("selectElement('editable_2');"));
3702     EXPECT_EQ("Editable 2.", selectionAsString(frame));
3703     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2")));
3704     // positionForPoint returns the wrong values for contenteditable spans. See
3705     // http://crbug.com/238334.
3706     // EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame));
3707 }
3708
3709 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd)
3710 {
3711     registerMockedHttpURLLoad("text_selection.html");
3712     FrameTestHelpers::WebViewHelper webViewHelper;
3713     initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper);
3714     WebFrame* frame = webViewHelper.webView()->mainFrame();
3715
3716     // Select first span. We can move the end to include the second span.
3717     frame->executeScript(WebScriptSource("selectElement('header_1');"));
3718     EXPECT_EQ("Header 1.", selectionAsString(frame));
3719     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
3720     EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
3721
3722     // We can move the start and end together.
3723     frame->executeScript(WebScriptSource("selectElement('header_2');"));
3724     EXPECT_EQ("Header 2.", selectionAsString(frame));
3725     frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2")));
3726     EXPECT_EQ("", selectionAsString(frame));
3727     // Selection is a caret, not empty.
3728     EXPECT_FALSE(frame->selectionRange().isNull());
3729
3730     // We can move the end across the start.
3731     frame->executeScript(WebScriptSource("selectElement('header_2');"));
3732     EXPECT_EQ("Header 2.", selectionAsString(frame));
3733     frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
3734     EXPECT_EQ("Header 1. ", selectionAsString(frame));
3735
3736     // Can't extend the selection part-way into an editable element.
3737     frame->executeScript(WebScriptSource("selectElement('header_1');"));
3738     EXPECT_EQ("Header 1.", selectionAsString(frame));
3739     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1")));
3740     EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame));
3741
3742     // Can extend the selection completely across editable elements.
3743     frame->executeScript(WebScriptSource("selectElement('header_1');"));
3744     EXPECT_EQ("Header 1.", selectionAsString(frame));
3745     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3746     EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame));
3747
3748     // If the selection is editable text, we can't extend it into non-editable text.
3749     frame->executeScript(WebScriptSource("selectElement('editable_1');"));
3750     EXPECT_EQ("Editable 1.", selectionAsString(frame));
3751     frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
3752     // positionForPoint returns the wrong values for contenteditable spans. See
3753     // http://crbug.com/238334.
3754     // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
3755 }
3756
3757 static int computeOffset(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.
3764 TEST_F(WebFrameTest, DISABLED_PositionForPointTest)
3765 {
3766     registerMockedHttpURLLoad("select_range_span_editable.html");
3767     FrameTestHelpers::WebViewHelper webViewHelper;
3768     initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper);
3769     WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3770     RenderObject* renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3771     EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3772     EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3773
3774     registerMockedHttpURLLoad("select_range_div_editable.html");
3775     initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper);
3776     mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3777     renderer = mainFrame->frame()->selection().rootEditableElement()->renderer();
3778     EXPECT_EQ(0, computeOffset(renderer, -1, -1));
3779     EXPECT_EQ(64, computeOffset(renderer, 1000, 1000));
3780 }
3781
3782 #if !OS(MACOSX) && !OS(LINUX)
3783 TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved)
3784 {
3785     registerMockedHttpURLLoad("move_caret.html");
3786
3787     FrameTestHelpers::WebViewHelper webViewHelper;
3788     initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3789     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
3790
3791     WebRect initialStartRect;
3792     WebRect initialEndRect;
3793     WebRect startRect;
3794     WebRect endRect;
3795
3796     frame->executeScript(WebScriptSource("selectRange();"));
3797     webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3798     WebPoint movedStart(topLeft(initialStartRect));
3799
3800     movedStart.y += 40;
3801     frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3802     webViewHelper.webView()->selectionBounds(startRect, endRect);
3803     EXPECT_EQ(startRect, initialStartRect);
3804     EXPECT_EQ(endRect, initialEndRect);
3805
3806     movedStart.y -= 80;
3807     frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect));
3808     webViewHelper.webView()->selectionBounds(startRect, endRect);
3809     EXPECT_EQ(startRect, initialStartRect);
3810     EXPECT_EQ(endRect, initialEndRect);
3811
3812     WebPoint movedEnd(bottomRightMinusOne(initialEndRect));
3813
3814     movedEnd.y += 40;
3815     frame->selectRange(topLeft(initialStartRect), movedEnd);
3816     webViewHelper.webView()->selectionBounds(startRect, endRect);
3817     EXPECT_EQ(startRect, initialStartRect);
3818     EXPECT_EQ(endRect, initialEndRect);
3819
3820     movedEnd.y -= 80;
3821     frame->selectRange(topLeft(initialStartRect), movedEnd);
3822     webViewHelper.webView()->selectionBounds(startRect, endRect);
3823     EXPECT_EQ(startRect, initialStartRect);
3824     EXPECT_EQ(endRect, initialEndRect);
3825 }
3826
3827 TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved)
3828 {
3829     WebLocalFrameImpl* frame;
3830     registerMockedHttpURLLoad("move_caret.html");
3831
3832     FrameTestHelpers::WebViewHelper webViewHelper;
3833     initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper);
3834     frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
3835
3836     WebRect initialStartRect;
3837     WebRect initialEndRect;
3838     WebRect startRect;
3839     WebRect endRect;
3840
3841     frame->executeScript(WebScriptSource("selectCaret();"));
3842     webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect);
3843     WebPoint moveTo(topLeft(initialStartRect));
3844
3845     moveTo.y += 40;
3846     frame->moveCaretSelection(moveTo);
3847     webViewHelper.webView()->selectionBounds(startRect, endRect);
3848     EXPECT_EQ(startRect, initialStartRect);
3849     EXPECT_EQ(endRect, initialEndRect);
3850
3851     moveTo.y -= 80;
3852     frame->moveCaretSelection(moveTo);
3853     webViewHelper.webView()->selectionBounds(startRect, endRect);
3854     EXPECT_EQ(startRect, initialStartRect);
3855     EXPECT_EQ(endRect, initialEndRect);
3856 }
3857 #endif
3858
3859 class CompositedSelectionBoundsTestLayerTreeView : public WebLayerTreeView {
3860 public:
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
3901 private:
3902     bool m_selectionCleared;
3903     OwnPtr<WebSelectionBound> m_start;
3904     OwnPtr<WebSelectionBound> m_end;
3905 };
3906
3907 class CompositedSelectionBoundsTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
3908 public:
3909     virtual ~CompositedSelectionBoundsTestWebViewClient() { }
3910     virtual WebLayerTreeView* layerTreeView() OVERRIDE { return &m_testLayerTreeView; }
3911
3912     CompositedSelectionBoundsTestLayerTreeView& selectionLayerTreeView() { return m_testLayerTreeView; }
3913
3914 private:
3915     CompositedSelectionBoundsTestLayerTreeView m_testLayerTreeView;
3916 };
3917
3918 class CompositedSelectionBoundsTest : public WebFrameTest {
3919 protected:
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
3989 TEST_F(CompositedSelectionBoundsTest, None) { runTest("composited_selection_bounds_none.html"); }
3990 TEST_F(CompositedSelectionBoundsTest, Basic) { runTest("composited_selection_bounds_basic.html"); }
3991 TEST_F(CompositedSelectionBoundsTest, Transformed) { runTest("composited_selection_bounds_transformed.html"); }
3992 TEST_F(CompositedSelectionBoundsTest, SplitLayer) { runTest("composited_selection_bounds_split_layer.html"); }
3993 TEST_F(CompositedSelectionBoundsTest, Iframe) { runTestWithMultipleFiles("composited_selection_bounds_iframe.html", "composited_selection_bounds_basic.html", nullptr); }
3994
3995 TEST_F(WebFrameTest, CompositedSelectionBoundsCleared)
3996 {
3997     RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
3998
3999     registerMockedHttpURLLoad("select_range_basic.html");
4000     registerMockedHttpURLLoad("select_range_scroll.html");
4001
4002     int viewWidth = 500;
4003     int viewHeight = 500;
4004
4005     CompositedSelectionBoundsTestWebViewClient fakeSelectionWebViewClient;
4006     CompositedSelectionBoundsTestLayerTreeView& fakeSelectionLayerTreeView = fakeSelectionWebViewClient.selectionLayerTreeView();
4007
4008     FrameTestHelpers::WebViewHelper webViewHelper;
4009     webViewHelper.initialize(true, 0, &fakeSelectionWebViewClient);
4010     webViewHelper.webView()->settings()->setDefaultFontSize(12);
4011     webViewHelper.webView()->setPageScaleFactorLimits(1, 1);
4012     webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight));
4013     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_basic.html");
4014
4015     // The frame starts with a non-empty selection.
4016     WebFrame* frame = webViewHelper.webView()->mainFrame();
4017     ASSERT_TRUE(frame->hasSelection());
4018     EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4019
4020     // The selection cleared notification should be triggered upon layout.
4021     frame->executeCommand(WebString::fromUTF8("Unselect"));
4022     ASSERT_FALSE(frame->hasSelection());
4023     EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4024     webViewHelper.webView()->layout();
4025     EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4026
4027     frame->executeCommand(WebString::fromUTF8("SelectAll"));
4028     webViewHelper.webView()->layout();
4029     ASSERT_TRUE(frame->hasSelection());
4030     EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4031
4032     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "select_range_scroll.html");
4033     ASSERT_TRUE(frame->hasSelection());
4034     EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4035
4036     // Transitions between non-empty selections should not trigger a clearing.
4037     WebRect startWebRect;
4038     WebRect endWebRect;
4039     webViewHelper.webViewImpl()->selectionBounds(startWebRect, endWebRect);
4040     WebPoint movedEnd(bottomRightMinusOne(endWebRect));
4041     endWebRect.x -= 20;
4042     frame->selectRange(topLeft(startWebRect), movedEnd);
4043     webViewHelper.webView()->layout();
4044     ASSERT_TRUE(frame->hasSelection());
4045     EXPECT_FALSE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4046
4047     frame = webViewHelper.webView()->mainFrame();
4048     frame->executeCommand(WebString::fromUTF8("Unselect"));
4049     webViewHelper.webView()->layout();
4050     ASSERT_FALSE(frame->hasSelection());
4051     EXPECT_TRUE(fakeSelectionLayerTreeView.getAndResetSelectionCleared());
4052 }
4053
4054 class DisambiguationPopupTestWebViewClient : public FrameTestHelpers::TestWebViewClient {
4055 public:
4056     virtual bool didTapMultipleTargets(const WebSize&, const WebRect&, const WebVector<WebRect>& targetRects) OVERRIDE
4057     {
4058         EXPECT_GE(targetRects.size(), 2u);
4059         m_triggered = true;
4060         return true;
4061     }
4062
4063     bool triggered() const { return m_triggered; }
4064     void resetTriggered() { m_triggered = false; }
4065     bool m_triggered;
4066 };
4067
4068 static WebGestureEvent fatTap(int x, int y)
4069 {
4070     WebGestureEvent event;
4071     event.type = WebInputEvent::GestureTap;
4072     event.x = x;
4073     event.y = y;
4074     event.data.tap.width = 50;
4075     event.data.tap.height = 50;
4076     return event;
4077 }
4078
4079 TEST_F(WebFrameTest, DisambiguationPopup)
4080 {
4081     const std::string htmlFile = "disambiguation_popup.html";
4082     registerMockedHttpURLLoad(htmlFile);
4083
4084     DisambiguationPopupTestWebViewClient client;
4085
4086     // Make sure we initialize to minimum scale, even if the window size
4087     // only becomes available after the load begins.
4088     FrameTestHelpers::WebViewHelper webViewHelper;
4089     webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4090     webViewHelper.webView()->resize(WebSize(1000, 1000));
4091     webViewHelper.webView()->layout();
4092
4093     client.resetTriggered();
4094     webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4095     EXPECT_FALSE(client.triggered());
4096
4097     client.resetTriggered();
4098     webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4099     EXPECT_FALSE(client.triggered());
4100
4101     for (int i = 0; i <= 46; i++) {
4102         client.resetTriggered();
4103         webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4104
4105         int j = i % 10;
4106         if (j >= 7 && j <= 9)
4107             EXPECT_TRUE(client.triggered());
4108         else
4109             EXPECT_FALSE(client.triggered());
4110     }
4111
4112     for (int i = 0; i <= 46; i++) {
4113         client.resetTriggered();
4114         webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4115
4116         int j = i % 10;
4117         if (j >= 7 && j <= 9)
4118             EXPECT_TRUE(client.triggered());
4119         else
4120             EXPECT_FALSE(client.triggered());
4121     }
4122 }
4123
4124 TEST_F(WebFrameTest, DisambiguationPopupNoContainer)
4125 {
4126     registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
4127
4128     DisambiguationPopupTestWebViewClient client;
4129
4130     // Make sure we initialize to minimum scale, even if the window size
4131     // only becomes available after the load begins.
4132     FrameTestHelpers::WebViewHelper webViewHelper;
4133     webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_no_container.html", true, 0, &client);
4134     webViewHelper.webView()->resize(WebSize(1000, 1000));
4135     webViewHelper.webView()->layout();
4136
4137     client.resetTriggered();
4138     webViewHelper.webView()->handleInputEvent(fatTap(50, 50));
4139     EXPECT_FALSE(client.triggered());
4140 }
4141
4142 TEST_F(WebFrameTest, DisambiguationPopupMobileSite)
4143 {
4144     UseMockScrollbarSettings mockScrollbarSettings;
4145     const std::string htmlFile = "disambiguation_popup_mobile_site.html";
4146     registerMockedHttpURLLoad(htmlFile);
4147
4148     DisambiguationPopupTestWebViewClient client;
4149
4150     // Make sure we initialize to minimum scale, even if the window size
4151     // only becomes available after the load begins.
4152     FrameTestHelpers::WebViewHelper webViewHelper;
4153     webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4154     webViewHelper.webView()->resize(WebSize(1000, 1000));
4155     webViewHelper.webView()->layout();
4156
4157     client.resetTriggered();
4158     webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4159     EXPECT_FALSE(client.triggered());
4160
4161     client.resetTriggered();
4162     webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4163     EXPECT_FALSE(client.triggered());
4164
4165     for (int i = 0; i <= 46; i++) {
4166         client.resetTriggered();
4167         webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4168         EXPECT_FALSE(client.triggered());
4169     }
4170
4171     for (int i = 0; i <= 46; i++) {
4172         client.resetTriggered();
4173         webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4174         EXPECT_FALSE(client.triggered());
4175     }
4176 }
4177
4178 TEST_F(WebFrameTest, DisambiguationPopupViewportSite)
4179 {
4180     UseMockScrollbarSettings mockScrollbarSettings;
4181     const std::string htmlFile = "disambiguation_popup_viewport_site.html";
4182     registerMockedHttpURLLoad(htmlFile);
4183
4184     DisambiguationPopupTestWebViewClient client;
4185
4186     // Make sure we initialize to minimum scale, even if the window size
4187     // only becomes available after the load begins.
4188     FrameTestHelpers::WebViewHelper webViewHelper;
4189     webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableViewportSettings);
4190     webViewHelper.webView()->resize(WebSize(1000, 1000));
4191     webViewHelper.webView()->layout();
4192
4193     client.resetTriggered();
4194     webViewHelper.webView()->handleInputEvent(fatTap(0, 0));
4195     EXPECT_FALSE(client.triggered());
4196
4197     client.resetTriggered();
4198     webViewHelper.webView()->handleInputEvent(fatTap(200, 115));
4199     EXPECT_FALSE(client.triggered());
4200
4201     for (int i = 0; i <= 46; i++) {
4202         client.resetTriggered();
4203         webViewHelper.webView()->handleInputEvent(fatTap(120, 230 + i * 5));
4204         EXPECT_FALSE(client.triggered());
4205     }
4206
4207     for (int i = 0; i <= 46; i++) {
4208         client.resetTriggered();
4209         webViewHelper.webView()->handleInputEvent(fatTap(10 + i * 5, 590));
4210         EXPECT_FALSE(client.triggered());
4211     }
4212 }
4213
4214 static void enableVirtualViewport(WebSettings* settings)
4215 {
4216     settings->setPinchVirtualViewportEnabled(true);
4217     settings->setViewportEnabled(true);
4218     settings->setViewportMetaEnabled(true);
4219     settings->setShrinksViewportContentToFit(true);
4220 }
4221
4222 TEST_F(WebFrameTest, DisambiguationPopupPinchViewport)
4223 {
4224     UseMockScrollbarSettings mockScrollbarSettings;
4225     const std::string htmlFile = "disambiguation_popup_200_by_800.html";
4226     registerMockedHttpURLLoad(htmlFile);
4227
4228     DisambiguationPopupTestWebViewClient client;
4229
4230     FrameTestHelpers::WebViewHelper webViewHelper;
4231     webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client, enableVirtualViewport);
4232
4233     WebViewImpl* webViewImpl = webViewHelper.webViewImpl();
4234     ASSERT_TRUE(webViewImpl);
4235     LocalFrame* frame = webViewImpl->mainFrameImpl()->frame();
4236     ASSERT_TRUE(frame);
4237
4238     webViewHelper.webView()->resize(WebSize(100, 200));
4239
4240     // Scroll main frame to the bottom of the document
4241     webViewImpl->setMainFrameScrollOffset(WebPoint(0, 400));
4242     EXPECT_POINT_EQ(IntPoint(0, 400), frame->view()->scrollPosition());
4243
4244     webViewImpl->setPageScaleFactor(2.0);
4245
4246     // Scroll pinch viewport to the top of the main frame.
4247     PinchViewport& pinchViewport = frame->page()->frameHost().pinchViewport();
4248     pinchViewport.setLocation(FloatPoint(0, 0));
4249     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 0), pinchViewport.location());
4250
4251     // Tap at the top: there is nothing there.
4252     client.resetTriggered();
4253     webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4254     EXPECT_FALSE(client.triggered());
4255
4256     // Scroll pinch viewport to the bottom of the main frame.
4257     pinchViewport.setLocation(FloatPoint(0, 200));
4258     EXPECT_FLOAT_POINT_EQ(FloatPoint(0, 200), pinchViewport.location());
4259
4260     // Now the tap with the same coordinates should hit two elements.
4261     client.resetTriggered();
4262     webViewHelper.webView()->handleInputEvent(fatTap(10, 60));
4263     EXPECT_TRUE(client.triggered());
4264 }
4265
4266 TEST_F(WebFrameTest, DisambiguationPopupBlacklist)
4267 {
4268     const unsigned viewportWidth = 500;
4269     const unsigned viewportHeight = 1000;
4270     const unsigned divHeight = 100;
4271     const std::string htmlFile = "disambiguation_popup_blacklist.html";
4272     registerMockedHttpURLLoad(htmlFile);
4273
4274     DisambiguationPopupTestWebViewClient client;
4275
4276     // Make sure we initialize to minimum scale, even if the window size
4277     // only becomes available after the load begins.
4278     FrameTestHelpers::WebViewHelper webViewHelper;
4279     webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, 0, &client);
4280     webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight));
4281     webViewHelper.webView()->layout();
4282
4283     // Click somewhere where the popup shouldn't appear.
4284     client.resetTriggered();
4285     webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, 0));
4286     EXPECT_FALSE(client.triggered());
4287
4288     // Click directly in between two container divs with click handlers, with children that don't handle clicks.
4289     client.resetTriggered();
4290     webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight));
4291     EXPECT_TRUE(client.triggered());
4292
4293     // The third div container should be blacklisted if you click on the link it contains.
4294     client.resetTriggered();
4295     webViewHelper.webView()->handleInputEvent(fatTap(viewportWidth / 2, divHeight * 3.25));
4296     EXPECT_FALSE(client.triggered());
4297 }
4298
4299 TEST_F(WebFrameTest, DisambiguationPopupPageScale)
4300 {
4301     registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
4302
4303     DisambiguationPopupTestWebViewClient client;
4304
4305     // Make sure we initialize to minimum scale, even if the window size
4306     // only becomes available after the load begins.
4307     FrameTestHelpers::WebViewHelper webViewHelper;
4308     webViewHelper.initializeAndLoad(m_baseURL + "disambiguation_popup_page_scale.html", true, 0, &client);
4309     webViewHelper.webView()->resize(WebSize(1000, 1000));
4310     webViewHelper.webView()->layout();
4311
4312     client.resetTriggered();
4313     webViewHelper.webView()->handleInputEvent(fatTap(80, 80));
4314     EXPECT_TRUE(client.triggered());
4315
4316     client.resetTriggered();
4317     webViewHelper.webView()->handleInputEvent(fatTap(230, 190));
4318     EXPECT_TRUE(client.triggered());
4319
4320     webViewHelper.webView()->setPageScaleFactor(3.0f);
4321     webViewHelper.webView()->layout();
4322
4323     client.resetTriggered();
4324     webViewHelper.webView()->handleInputEvent(fatTap(240, 240));
4325     EXPECT_TRUE(client.triggered());
4326
4327     client.resetTriggered();
4328     webViewHelper.webView()->handleInputEvent(fatTap(690, 570));
4329     EXPECT_FALSE(client.triggered());
4330 }
4331
4332 class TestSubstituteDataWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4333 public:
4334     TestSubstituteDataWebFrameClient()
4335         : m_commitCalled(false)
4336     {
4337     }
4338
4339     virtual void didFailProvisionalLoad(WebLocalFrame* frame, const WebURLError& error)
4340     {
4341         frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true);
4342     }
4343
4344     virtual void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType)
4345     {
4346         if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank")))
4347             m_commitCalled = true;
4348     }
4349
4350     bool commitCalled() const { return m_commitCalled; }
4351
4352 private:
4353     bool m_commitCalled;
4354 };
4355
4356 TEST_F(WebFrameTest, ReplaceNavigationAfterHistoryNavigation)
4357 {
4358     TestSubstituteDataWebFrameClient webFrameClient;
4359
4360     FrameTestHelpers::WebViewHelper webViewHelper;
4361     webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
4362     WebFrame* frame = webViewHelper.webView()->mainFrame();
4363
4364     // Load a url as a history navigation that will return an error. TestSubstituteDataWebFrameClient
4365     // will start a SubstituteData load in response to the load failure, which should get fully committed.
4366     // Due to https://bugs.webkit.org/show_bug.cgi?id=91685, FrameLoader::didReceiveData() wasn't getting
4367     // called in this case, which resulted in the SubstituteData document not getting displayed.
4368     WebURLError error;
4369     error.reason = 1337;
4370     error.domain = "WebFrameTest";
4371     std::string errorURL = "http://0.0.0.0";
4372     WebURLResponse response;
4373     response.initialize();
4374     response.setURL(URLTestHelpers::toKURL(errorURL));
4375     response.setMIMEType("text/html");
4376     response.setHTTPStatusCode(500);
4377     WebHistoryItem errorHistoryItem;
4378     errorHistoryItem.initialize();
4379     errorHistoryItem.setURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
4380     Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
4381     FrameTestHelpers::loadHistoryItem(frame, errorHistoryItem, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
4382
4383     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
4384     EXPECT_EQ("This should appear", text.utf8());
4385     EXPECT_TRUE(webFrameClient.commitCalled());
4386 }
4387
4388 class TestWillInsertBodyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4389 public:
4390     TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false)
4391     {
4392     }
4393
4394     virtual void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
4395     {
4396         m_numBodies = 0;
4397         m_didLoad = true;
4398     }
4399
4400     virtual void didCreateDocumentElement(WebLocalFrame*) OVERRIDE
4401     {
4402         EXPECT_EQ(0, m_numBodies);
4403     }
4404
4405     virtual void willInsertBody(WebLocalFrame*) OVERRIDE
4406     {
4407         m_numBodies++;
4408     }
4409
4410     int m_numBodies;
4411     bool m_didLoad;
4412 };
4413
4414 TEST_F(WebFrameTest, HTMLDocument)
4415 {
4416     registerMockedHttpURLLoad("clipped-body.html");
4417
4418     TestWillInsertBodyWebFrameClient webFrameClient;
4419     FrameTestHelpers::WebViewHelper webViewHelper;
4420     webViewHelper.initializeAndLoad(m_baseURL + "clipped-body.html", false, &webFrameClient);
4421
4422     EXPECT_TRUE(webFrameClient.m_didLoad);
4423     EXPECT_EQ(1, webFrameClient.m_numBodies);
4424 }
4425
4426 TEST_F(WebFrameTest, EmptyDocument)
4427 {
4428     registerMockedHttpURLLoad("pageserializer/green_rectangle.svg");
4429
4430     TestWillInsertBodyWebFrameClient webFrameClient;
4431     FrameTestHelpers::WebViewHelper webViewHelper;
4432     webViewHelper.initialize(false, &webFrameClient);
4433
4434     EXPECT_FALSE(webFrameClient.m_didLoad);
4435     EXPECT_EQ(1, webFrameClient.m_numBodies); // The empty document that a new frame starts with triggers this.
4436 }
4437
4438 TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection)
4439 {
4440     FrameTestHelpers::WebViewHelper webViewHelper;
4441     webViewHelper.initializeAndLoad("about:blank", true);
4442     WebFrame* frame = webViewHelper.webView()->mainFrame();
4443
4444     // This test passes if this doesn't crash.
4445     frame->moveCaretSelection(WebPoint(0, 0));
4446 }
4447
4448 TEST_F(WebFrameTest, NavigateToSandboxedMarkup)
4449 {
4450     FrameTestHelpers::WebViewHelper webViewHelper;
4451     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad("about:blank", true);
4452     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4453
4454     frame->document().setIsTransitionDocument();
4455
4456     std::string markup("<div id='foo'></div><script>document.getElementById('foo').setAttribute('dir', 'rtl')</script>");
4457     frame->navigateToSandboxedMarkup(WebData(markup.data(), markup.length()));
4458     FrameTestHelpers::runPendingTasks();
4459
4460     WebDocument document = webViewImpl->mainFrame()->document();
4461     WebElement transitionElement = document.getElementById("foo");
4462     // Check that the markup got navigated to successfully.
4463     EXPECT_FALSE(transitionElement.isNull());
4464
4465     // Check that the inline script was not executed.
4466     EXPECT_FALSE(transitionElement.hasAttribute("dir"));
4467 }
4468
4469 class SpellCheckClient : public WebSpellCheckClient {
4470 public:
4471     explicit SpellCheckClient(uint32_t hash = 0) : m_numberOfTimesChecked(0), m_hash(hash) { }
4472     virtual ~SpellCheckClient() { }
4473     virtual void requestCheckingOfText(const WebString&, const WebVector<uint32_t>&, const WebVector<unsigned>&, WebTextCheckingCompletion* completion) OVERRIDE
4474     {
4475         ++m_numberOfTimesChecked;
4476         Vector<WebTextCheckingResult> results;
4477         const int misspellingStartOffset = 1;
4478         const int misspellingLength = 8;
4479         results.append(WebTextCheckingResult(WebTextDecorationTypeSpelling, misspellingStartOffset, misspellingLength, WebString(), m_hash));
4480         completion->didFinishCheckingText(results);
4481     }
4482     int numberOfTimesChecked() const { return m_numberOfTimesChecked; }
4483 private:
4484     int m_numberOfTimesChecked;
4485     uint32_t m_hash;
4486 };
4487
4488 TEST_F(WebFrameTest, ReplaceMisspelledRange)
4489 {
4490     registerMockedHttpURLLoad("spell.html");
4491     FrameTestHelpers::WebViewHelper webViewHelper;
4492     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4493     SpellCheckClient spellcheck;
4494     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4495
4496     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4497     Document* document = frame->frame()->document();
4498     Element* element = document->getElementById("data");
4499
4500     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4501     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4502     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4503
4504     element->focus();
4505     document->execCommand("InsertText", false, "_wellcome_.");
4506
4507     const int allTextBeginOffset = 0;
4508     const int allTextLength = 11;
4509     frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4510     RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4511
4512     EXPECT_EQ(1, spellcheck.numberOfTimesChecked());
4513     EXPECT_EQ(1U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4514
4515     frame->replaceMisspelledRange("welcome");
4516     EXPECT_EQ("_welcome_.", frame->contentAsText(std::numeric_limits<size_t>::max()).utf8());
4517 }
4518
4519 TEST_F(WebFrameTest, RemoveSpellingMarkers)
4520 {
4521     registerMockedHttpURLLoad("spell.html");
4522     FrameTestHelpers::WebViewHelper webViewHelper;
4523     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4524     SpellCheckClient spellcheck;
4525     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4526
4527     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4528     Document* document = frame->frame()->document();
4529     Element* element = document->getElementById("data");
4530
4531     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4532     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4533     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4534
4535     element->focus();
4536     document->execCommand("InsertText", false, "_wellcome_.");
4537
4538     frame->removeSpellingMarkers();
4539
4540     const int allTextBeginOffset = 0;
4541     const int allTextLength = 11;
4542     frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength));
4543     RefPtrWillBeRawPtr<Range> selectionRange = frame->frame()->selection().toNormalizedRange();
4544
4545     EXPECT_EQ(0U, document->markers().markersInRange(selectionRange.get(), DocumentMarker::Spelling).size());
4546 }
4547
4548 TEST_F(WebFrameTest, RemoveSpellingMarkersUnderWords)
4549 {
4550     registerMockedHttpURLLoad("spell.html");
4551     FrameTestHelpers::WebViewHelper webViewHelper;
4552     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4553     SpellCheckClient spellcheck;
4554     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4555
4556     LocalFrame* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame())->frame();
4557     Document* document = frame->document();
4558     Element* element = document->getElementById("data");
4559
4560     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4561     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4562     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4563
4564     element->focus();
4565     document->execCommand("InsertText", false, " wellcome ");
4566
4567     WebVector<uint32_t> documentMarkers1;
4568     webViewHelper.webView()->spellingMarkers(&documentMarkers1);
4569     EXPECT_EQ(1U, documentMarkers1.size());
4570
4571     Vector<String> words;
4572     words.append("wellcome");
4573     frame->removeSpellingMarkersUnderWords(words);
4574
4575     WebVector<uint32_t> documentMarkers2;
4576     webViewHelper.webView()->spellingMarkers(&documentMarkers2);
4577     EXPECT_EQ(0U, documentMarkers2.size());
4578 }
4579
4580 TEST_F(WebFrameTest, MarkerHashIdentifiers) {
4581     registerMockedHttpURLLoad("spell.html");
4582     FrameTestHelpers::WebViewHelper webViewHelper;
4583     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4584
4585     static const uint32_t kHash = 42;
4586     SpellCheckClient spellcheck(kHash);
4587     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4588
4589     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4590     Document* document = frame->frame()->document();
4591     Element* element = document->getElementById("data");
4592
4593     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4594     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4595     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4596
4597     element->focus();
4598     document->execCommand("InsertText", false, "wellcome.");
4599
4600     WebVector<uint32_t> documentMarkers;
4601     webViewHelper.webView()->spellingMarkers(&documentMarkers);
4602     EXPECT_EQ(1U, documentMarkers.size());
4603     EXPECT_EQ(kHash, documentMarkers[0]);
4604 }
4605
4606 class StubbornSpellCheckClient : public WebSpellCheckClient {
4607 public:
4608     StubbornSpellCheckClient() : m_completion(0) { }
4609     virtual ~StubbornSpellCheckClient() { }
4610
4611     virtual void requestCheckingOfText(
4612         const WebString&,
4613         const WebVector<uint32_t>&,
4614         const WebVector<unsigned>&,
4615         WebTextCheckingCompletion* completion) OVERRIDE
4616     {
4617         m_completion = completion;
4618     }
4619
4620     void kickNoResults()
4621     {
4622         kick(-1, -1, WebTextDecorationTypeSpelling);
4623     }
4624
4625     void kick()
4626     {
4627         kick(1, 8, WebTextDecorationTypeSpelling);
4628     }
4629
4630     void kickGrammar()
4631     {
4632         kick(1, 8, WebTextDecorationTypeGrammar);
4633     }
4634
4635     void kickInvisibleSpellcheck()
4636     {
4637         kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck);
4638     }
4639
4640 private:
4641     void kick(int misspellingStartOffset, int misspellingLength, WebTextDecorationType type)
4642     {
4643         if (!m_completion)
4644             return;
4645         Vector<WebTextCheckingResult> results;
4646         if (misspellingStartOffset >= 0 && misspellingLength > 0)
4647             results.append(WebTextCheckingResult(type, misspellingStartOffset, misspellingLength));
4648         m_completion->didFinishCheckingText(results);
4649         m_completion = 0;
4650     }
4651
4652     WebTextCheckingCompletion* m_completion;
4653 };
4654
4655 TEST_F(WebFrameTest, SlowSpellcheckMarkerPosition)
4656 {
4657     registerMockedHttpURLLoad("spell.html");
4658     FrameTestHelpers::WebViewHelper webViewHelper;
4659     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4660
4661     StubbornSpellCheckClient spellcheck;
4662     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4663
4664     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4665     WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4666     Document* document = frame->frame()->document();
4667     Element* element = document->getElementById("data");
4668
4669     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4670     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4671     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4672
4673     element->focus();
4674     document->execCommand("InsertText", false, "wellcome ");
4675     webInputElement.setSelectionRange(0, 0);
4676     document->execCommand("InsertText", false, "he");
4677
4678     spellcheck.kick();
4679
4680     WebVector<uint32_t> documentMarkers;
4681     webViewHelper.webView()->spellingMarkers(&documentMarkers);
4682     EXPECT_EQ(0U, documentMarkers.size());
4683 }
4684
4685 // This test verifies that cancelling spelling request does not cause a
4686 // write-after-free when there's no spellcheck client set.
4687 TEST_F(WebFrameTest, CancelSpellingRequestCrash)
4688 {
4689     registerMockedHttpURLLoad("spell.html");
4690     FrameTestHelpers::WebViewHelper webViewHelper;
4691     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4692     webViewHelper.webView()->setSpellCheckClient(0);
4693
4694     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4695     Document* document = frame->frame()->document();
4696     Element* element = document->getElementById("data");
4697
4698     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4699     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4700     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4701
4702     element->focus();
4703     frame->frame()->editor().replaceSelectionWithText("A", false, false);
4704     frame->frame()->spellChecker().cancelCheck();
4705 }
4706
4707 TEST_F(WebFrameTest, SpellcheckResultErasesMarkers)
4708 {
4709     registerMockedHttpURLLoad("spell.html");
4710     FrameTestHelpers::WebViewHelper webViewHelper;
4711     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4712
4713     StubbornSpellCheckClient spellcheck;
4714     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4715
4716     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4717     WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4718     Document* document = frame->frame()->document();
4719     Element* element = document->getElementById("data");
4720
4721     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4722     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4723     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4724
4725     element->focus();
4726     document->execCommand("InsertText", false, "welcome ");
4727     document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Spelling);
4728     document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::Grammar);
4729     document->markers().addMarker(rangeOfContents(element->toNode()).get(), DocumentMarker::InvisibleSpellcheck);
4730     EXPECT_EQ(3U, document->markers().markers().size());
4731
4732     spellcheck.kickNoResults();
4733     EXPECT_EQ(0U, document->markers().markers().size());
4734 }
4735
4736 TEST_F(WebFrameTest, SpellcheckResultsSavedInDocument)
4737 {
4738     registerMockedHttpURLLoad("spell.html");
4739     FrameTestHelpers::WebViewHelper webViewHelper;
4740     webViewHelper.initializeAndLoad(m_baseURL + "spell.html");
4741
4742     StubbornSpellCheckClient spellcheck;
4743     webViewHelper.webView()->setSpellCheckClient(&spellcheck);
4744
4745     WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame());
4746     WebInputElement webInputElement = frame->document().getElementById("data").to<WebInputElement>();
4747     Document* document = frame->frame()->document();
4748     Element* element = document->getElementById("data");
4749
4750     webViewHelper.webView()->settings()->setAsynchronousSpellCheckingEnabled(true);
4751     webViewHelper.webView()->settings()->setUnifiedTextCheckerEnabled(true);
4752     webViewHelper.webView()->settings()->setEditingBehavior(WebSettings::EditingBehaviorWin);
4753
4754     element->focus();
4755     document->execCommand("InsertText", false, "wellcome ");
4756
4757     spellcheck.kick();
4758     ASSERT_EQ(1U, document->markers().markers().size());
4759     ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4760     EXPECT_EQ(DocumentMarker::Spelling, document->markers().markers()[0]->type());
4761
4762     document->execCommand("InsertText", false, "wellcome ");
4763
4764     spellcheck.kickGrammar();
4765     ASSERT_EQ(1U, document->markers().markers().size());
4766     ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4767     EXPECT_EQ(DocumentMarker::Grammar, document->markers().markers()[0]->type());
4768
4769     document->execCommand("InsertText", false, "wellcome ");
4770
4771     spellcheck.kickInvisibleSpellcheck();
4772     ASSERT_EQ(1U, document->markers().markers().size());
4773     ASSERT_NE(static_cast<DocumentMarker*>(0), document->markers().markers()[0]);
4774     EXPECT_EQ(DocumentMarker::InvisibleSpellcheck, document->markers().markers()[0]->type());
4775 }
4776
4777 class TestAccessInitialDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
4778 public:
4779     TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false)
4780     {
4781     }
4782
4783     virtual void didAccessInitialDocument(WebLocalFrame* frame)
4784     {
4785         EXPECT_TRUE(!m_didAccessInitialDocument);
4786         m_didAccessInitialDocument = true;
4787     }
4788
4789     bool m_didAccessInitialDocument;
4790 };
4791
4792 TEST_F(WebFrameTest, DidAccessInitialDocumentBody)
4793 {
4794     // FIXME: Why is this local webViewClient needed instead of the default
4795     // WebViewHelper one? With out it there's some mysterious crash in the
4796     // WebViewHelper destructor.
4797     FrameTestHelpers::TestWebViewClient webViewClient;
4798     TestAccessInitialDocumentWebFrameClient webFrameClient;
4799     FrameTestHelpers::WebViewHelper webViewHelper;
4800     webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4801     runPendingTasks();
4802     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4803
4804     // Create another window that will try to access it.
4805     FrameTestHelpers::WebViewHelper newWebViewHelper;
4806     WebView* newView = newWebViewHelper.initialize(true);
4807     newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4808     runPendingTasks();
4809     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4810
4811     // Access the initial document by modifying the body.
4812     newView->mainFrame()->executeScript(
4813         WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4814     runPendingTasks();
4815     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4816
4817     // Access the initial document again, to ensure we don't notify twice.
4818     newView->mainFrame()->executeScript(
4819         WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4820     runPendingTasks();
4821     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4822 }
4823
4824 TEST_F(WebFrameTest, DidAccessInitialDocumentNavigator)
4825 {
4826     // FIXME: Why is this local webViewClient needed instead of the default
4827     // WebViewHelper one? With out it there's some mysterious crash in the
4828     // WebViewHelper destructor.
4829     FrameTestHelpers::TestWebViewClient webViewClient;
4830     TestAccessInitialDocumentWebFrameClient webFrameClient;
4831     FrameTestHelpers::WebViewHelper webViewHelper;
4832     webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4833     runPendingTasks();
4834     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4835
4836     // Create another window that will try to access it.
4837     FrameTestHelpers::WebViewHelper newWebViewHelper;
4838     WebView* newView = newWebViewHelper.initialize(true);
4839     newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4840     runPendingTasks();
4841     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4842
4843     // Access the initial document to get to the navigator object.
4844     newView->mainFrame()->executeScript(
4845         WebScriptSource("console.log(window.opener.navigator);"));
4846     runPendingTasks();
4847     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4848 }
4849
4850 TEST_F(WebFrameTest, DidAccessInitialDocumentViaJavascriptUrl)
4851 {
4852     TestAccessInitialDocumentWebFrameClient webFrameClient;
4853     FrameTestHelpers::WebViewHelper webViewHelper;
4854     webViewHelper.initialize(true, &webFrameClient);
4855     runPendingTasks();
4856     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4857
4858     // Access the initial document from a javascript: URL.
4859     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Modified'))");
4860     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4861 }
4862
4863 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4864 #if OS(WIN)
4865 TEST_F(WebFrameTest, DISABLED_DidAccessInitialDocumentBodyBeforeModalDialog)
4866 #else
4867 TEST_F(WebFrameTest, DidAccessInitialDocumentBodyBeforeModalDialog)
4868 #endif
4869 {
4870     // FIXME: Why is this local webViewClient needed instead of the default
4871     // WebViewHelper one? With out it there's some mysterious crash in the
4872     // WebViewHelper destructor.
4873     FrameTestHelpers::TestWebViewClient webViewClient;
4874     TestAccessInitialDocumentWebFrameClient webFrameClient;
4875     FrameTestHelpers::WebViewHelper webViewHelper;
4876     webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4877     runPendingTasks();
4878     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4879
4880     // Create another window that will try to access it.
4881     FrameTestHelpers::WebViewHelper newWebViewHelper;
4882     WebView* newView = newWebViewHelper.initialize(true);
4883     newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4884     runPendingTasks();
4885     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4886
4887     // Access the initial document by modifying the body. We normally set a
4888     // timer to notify the client.
4889     newView->mainFrame()->executeScript(
4890         WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
4891     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4892
4893     // Make sure that a modal dialog forces us to notify right away.
4894     newView->mainFrame()->executeScript(
4895         WebScriptSource("window.opener.confirm('Modal');"));
4896     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4897
4898     // Ensure that we don't notify again later.
4899     runPendingTasks();
4900     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4901 }
4902
4903 // Fails on the WebKit XP (deps) bot. http://crbug.com/312192
4904 #if OS(WIN)
4905 TEST_F(WebFrameTest, DISABLED_DidWriteToInitialDocumentBeforeModalDialog)
4906 #else
4907 TEST_F(WebFrameTest, DidWriteToInitialDocumentBeforeModalDialog)
4908 #endif
4909 {
4910     // FIXME: Why is this local webViewClient needed instead of the default
4911     // WebViewHelper one? With out it there's some mysterious crash in the
4912     // WebViewHelper destructor.
4913     FrameTestHelpers::TestWebViewClient webViewClient;
4914     TestAccessInitialDocumentWebFrameClient webFrameClient;
4915     FrameTestHelpers::WebViewHelper webViewHelper;
4916     webViewHelper.initialize(true, &webFrameClient, &webViewClient);
4917     runPendingTasks();
4918     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4919
4920     // Create another window that will try to access it.
4921     FrameTestHelpers::WebViewHelper newWebViewHelper;
4922     WebView* newView = newWebViewHelper.initialize(true);
4923     newView->mainFrame()->setOpener(webViewHelper.webView()->mainFrame());
4924     runPendingTasks();
4925     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4926
4927     // Access the initial document with document.write, which moves us past the
4928     // initial empty document state of the state machine. We normally set a
4929     // timer to notify the client.
4930     newView->mainFrame()->executeScript(
4931         WebScriptSource("window.opener.document.write('Modified');"));
4932     EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
4933
4934     // Make sure that a modal dialog forces us to notify right away.
4935     newView->mainFrame()->executeScript(
4936         WebScriptSource("window.opener.confirm('Modal');"));
4937     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4938
4939     // Ensure that we don't notify again later.
4940     runPendingTasks();
4941     EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
4942 }
4943
4944 class TestMainFrameUserOrProgrammaticScrollFrameClient : public FrameTestHelpers::TestWebFrameClient {
4945 public:
4946     TestMainFrameUserOrProgrammaticScrollFrameClient() { reset(); }
4947     void reset()
4948     {
4949         m_didScrollMainFrame = false;
4950         m_wasProgrammaticScroll = false;
4951     }
4952     bool wasUserScroll() const { return m_didScrollMainFrame && !m_wasProgrammaticScroll; }
4953     bool wasProgrammaticScroll() const { return m_didScrollMainFrame && m_wasProgrammaticScroll; }
4954
4955     // WebFrameClient:
4956     virtual void didChangeScrollOffset(WebLocalFrame* frame) OVERRIDE
4957     {
4958         if (frame->parent())
4959             return;
4960         EXPECT_FALSE(m_didScrollMainFrame);
4961         FrameView* view = toWebLocalFrameImpl(frame)->frameView();
4962         // FrameView can be scrolled in FrameView::setFixedVisibleContentRect
4963         // which is called from LocalFrame::createView (before the frame is associated
4964         // with the the view).
4965         if (view) {
4966             m_didScrollMainFrame = true;
4967             m_wasProgrammaticScroll = view->inProgrammaticScroll();
4968         }
4969     }
4970 private:
4971     bool m_didScrollMainFrame;
4972     bool m_wasProgrammaticScroll;
4973 };
4974
4975 TEST_F(WebFrameTest, CompositorScrollIsUserScrollLongPage)
4976 {
4977     registerMockedHttpURLLoad("long_scroll.html");
4978     TestMainFrameUserOrProgrammaticScrollFrameClient client;
4979
4980     // Make sure we initialize to minimum scale, even if the window size
4981     // only becomes available after the load begins.
4982     FrameTestHelpers::WebViewHelper webViewHelper;
4983     webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, &client);
4984     webViewHelper.webView()->resize(WebSize(1000, 1000));
4985     webViewHelper.webView()->layout();
4986
4987     EXPECT_FALSE(client.wasUserScroll());
4988     EXPECT_FALSE(client.wasProgrammaticScroll());
4989
4990     // Do a compositor scroll, verify that this is counted as a user scroll.
4991     webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(0, 1), 1.1f, 0);
4992     EXPECT_TRUE(client.wasUserScroll());
4993     client.reset();
4994
4995     EXPECT_FALSE(client.wasUserScroll());
4996     EXPECT_FALSE(client.wasProgrammaticScroll());
4997
4998     // The page scale 1.0f and scroll.
4999     webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(0, 1), 1.0f, 0);
5000     EXPECT_TRUE(client.wasUserScroll());
5001     client.reset();
5002
5003     // No scroll event if there is no scroll delta.
5004     webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.0f, 0);
5005     EXPECT_FALSE(client.wasUserScroll());
5006     EXPECT_FALSE(client.wasProgrammaticScroll());
5007     client.reset();
5008
5009     // Non zero page scale and scroll.
5010     webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(9, 13), 0.6f, 0);
5011     EXPECT_TRUE(client.wasUserScroll());
5012     client.reset();
5013
5014     // Programmatic scroll.
5015     WebLocalFrameImpl* frameImpl = webViewHelper.webViewImpl()->mainFrameImpl();
5016     frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5017     EXPECT_FALSE(client.wasUserScroll());
5018     EXPECT_TRUE(client.wasProgrammaticScroll());
5019     client.reset();
5020
5021     // Programmatic scroll to same offset. No scroll event should be generated.
5022     frameImpl->executeScript(WebScriptSource("window.scrollTo(0, 20);"));
5023     EXPECT_FALSE(client.wasProgrammaticScroll());
5024     EXPECT_FALSE(client.wasUserScroll());
5025     client.reset();
5026 }
5027
5028 TEST_F(WebFrameTest, CompositorScrollIsUserScrollShortPage)
5029 {
5030     registerMockedHttpURLLoad("short_scroll.html");
5031
5032     TestMainFrameUserOrProgrammaticScrollFrameClient client;
5033
5034     // Short page tests.
5035     FrameTestHelpers::WebViewHelper webViewHelper;
5036     webViewHelper.initializeAndLoad(m_baseURL + "short_scroll.html", true, &client);
5037
5038     webViewHelper.webView()->resize(WebSize(1000, 1000));
5039     webViewHelper.webView()->layout();
5040
5041     EXPECT_FALSE(client.wasUserScroll());
5042     EXPECT_FALSE(client.wasProgrammaticScroll());
5043
5044     // Non zero page scale and scroll.
5045     webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(9, 13), 2.0f, 0);
5046     EXPECT_FALSE(client.wasProgrammaticScroll());
5047     EXPECT_TRUE(client.wasUserScroll());
5048     client.reset();
5049 }
5050
5051 TEST_F(WebFrameTest, FirstPartyForCookiesForRedirect)
5052 {
5053     WTF::String filePath = Platform::current()->unitTestSupport()->webKitRootDir();
5054     filePath.append("/Source/web/tests/data/first_party.html");
5055
5056     WebURL testURL(toKURL("http://www.test.com/first_party_redirect.html"));
5057     char redirect[] = "http://www.test.com/first_party.html";
5058     WebURL redirectURL(toKURL(redirect));
5059     WebURLResponse redirectResponse;
5060     redirectResponse.initialize();
5061     redirectResponse.setMIMEType("text/html");
5062     redirectResponse.setHTTPStatusCode(302);
5063     redirectResponse.setHTTPHeaderField("Location", redirect);
5064     Platform::current()->unitTestSupport()->registerMockedURL(testURL, redirectResponse, filePath);
5065
5066     WebURLResponse finalResponse;
5067     finalResponse.initialize();
5068     finalResponse.setMIMEType("text/html");
5069     Platform::current()->unitTestSupport()->registerMockedURL(redirectURL, finalResponse, filePath);
5070
5071     FrameTestHelpers::WebViewHelper webViewHelper;
5072     webViewHelper.initializeAndLoad(m_baseURL + "first_party_redirect.html", true);
5073     EXPECT_TRUE(webViewHelper.webView()->mainFrame()->document().firstPartyForCookies() == redirectURL);
5074 }
5075
5076 class TestNavigationPolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5077 public:
5078
5079     virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE
5080     {
5081         EXPECT_TRUE(false);
5082     }
5083 };
5084
5085 TEST_F(WebFrameTest, SimulateFragmentAnchorMiddleClick)
5086 {
5087     registerMockedHttpURLLoad("fragment_middle_click.html");
5088     TestNavigationPolicyWebFrameClient client;
5089     FrameTestHelpers::WebViewHelper webViewHelper;
5090     webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true, &client);
5091
5092     Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5093     KURL destination = document->url();
5094     destination.setFragmentIdentifier("test");
5095
5096     RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5097         document->domWindow(), 0, 0, 0, 0, 0, 0, 0, false, false, false, false, 1, nullptr, nullptr);
5098     FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5099     frameRequest.setTriggeringEvent(event);
5100     toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5101 }
5102
5103 class TestNewWindowWebViewClient : public FrameTestHelpers::TestWebViewClient {
5104 public:
5105     virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&,
5106         const WebString&, WebNavigationPolicy, bool) OVERRIDE
5107     {
5108         EXPECT_TRUE(false);
5109         return 0;
5110     }
5111 };
5112
5113 class TestNewWindowWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5114 public:
5115     TestNewWindowWebFrameClient()
5116         : m_decidePolicyCallCount(0)
5117     {
5118     }
5119
5120     virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE
5121     {
5122         m_decidePolicyCallCount++;
5123         return info.defaultPolicy;
5124     }
5125
5126     int decidePolicyCallCount() const { return m_decidePolicyCallCount; }
5127
5128 private:
5129     int m_decidePolicyCallCount;
5130 };
5131
5132 TEST_F(WebFrameTest, ModifiedClickNewWindow)
5133 {
5134     registerMockedHttpURLLoad("ctrl_click.html");
5135     registerMockedHttpURLLoad("hello_world.html");
5136     TestNewWindowWebViewClient webViewClient;
5137     TestNewWindowWebFrameClient webFrameClient;
5138     FrameTestHelpers::WebViewHelper webViewHelper;
5139     webViewHelper.initializeAndLoad(m_baseURL + "ctrl_click.html", true, &webFrameClient, &webViewClient);
5140
5141     Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document();
5142     KURL destination = toKURL(m_baseURL + "hello_world.html");
5143
5144     // ctrl+click event
5145     RefPtrWillBeRawPtr<Event> event = MouseEvent::create(EventTypeNames::click, false, false,
5146         document->domWindow(), 0, 0, 0, 0, 0, 0, 0, true, false, false, false, 0, nullptr, nullptr);
5147     FrameLoadRequest frameRequest(document, ResourceRequest(destination));
5148     frameRequest.setTriggeringEvent(event);
5149     UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5150     toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5151     FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5152
5153     // decidePolicyForNavigation should be called both for the original request and the ctrl+click.
5154     EXPECT_EQ(2, webFrameClient.decidePolicyCallCount());
5155 }
5156
5157 TEST_F(WebFrameTest, BackToReload)
5158 {
5159     registerMockedHttpURLLoad("fragment_middle_click.html");
5160     FrameTestHelpers::WebViewHelper webViewHelper;
5161     webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5162     WebFrame* frame = webViewHelper.webView()->mainFrame();
5163     const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5164     RefPtr<HistoryItem> firstItem = mainFrameLoader.currentItem();
5165     EXPECT_TRUE(firstItem);
5166
5167     registerMockedHttpURLLoad("white-1x1.png");
5168     FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5169     EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5170
5171     FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem.get()), WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5172     EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5173
5174     FrameTestHelpers::reloadFrame(frame);
5175     EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5176 }
5177
5178 TEST_F(WebFrameTest, BackDuringChildFrameReload)
5179 {
5180     registerMockedHttpURLLoad("page_with_blank_iframe.html");
5181     FrameTestHelpers::WebViewHelper webViewHelper;
5182     webViewHelper.initializeAndLoad(m_baseURL + "page_with_blank_iframe.html", true);
5183     WebFrame* mainFrame = webViewHelper.webView()->mainFrame();
5184     const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5185     WebFrame* childFrame = mainFrame->firstChild();
5186     ASSERT_TRUE(childFrame);
5187
5188     // Start a history navigation, then have a different frame commit a navigation.
5189     // In this case, reload an about:blank frame, which will commit synchronously.
5190     // After the history navigation completes, both the appropriate document url and
5191     // the current history item should reflect the history navigation.
5192     registerMockedHttpURLLoad("white-1x1.png");
5193     WebHistoryItem item;
5194     item.initialize();
5195     WebURL historyURL(toKURL(m_baseURL + "white-1x1.png"));
5196     item.setURLString(historyURL.string());
5197     mainFrame->loadHistoryItem(item, WebHistoryDifferentDocumentLoad, WebURLRequest::UseProtocolCachePolicy);
5198
5199     FrameTestHelpers::reloadFrame(childFrame);
5200     EXPECT_EQ(item.urlString(), mainFrame->document().url().string());
5201     EXPECT_EQ(item.urlString(), WebString(mainFrameLoader.currentItem()->urlString()));
5202 }
5203
5204 TEST_F(WebFrameTest, ReloadPost)
5205 {
5206     registerMockedHttpURLLoad("reload_post.html");
5207     FrameTestHelpers::WebViewHelper webViewHelper;
5208     webViewHelper.initializeAndLoad(m_baseURL + "reload_post.html", true);
5209     WebFrame* frame = webViewHelper.webView()->mainFrame();
5210
5211     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.forms[0].submit()");
5212     // Pump requests one more time after the javascript URL has executed to
5213     // trigger the actual POST load request.
5214     FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5215     EXPECT_EQ(WebString::fromUTF8("POST"), frame->dataSource()->request().httpMethod());
5216
5217     FrameTestHelpers::reloadFrame(frame);
5218     EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5219     EXPECT_EQ(WebNavigationTypeFormResubmitted, frame->dataSource()->navigationType());
5220 }
5221
5222 TEST_F(WebFrameTest, LoadHistoryItemReload)
5223 {
5224     registerMockedHttpURLLoad("fragment_middle_click.html");
5225     FrameTestHelpers::WebViewHelper webViewHelper;
5226     webViewHelper.initializeAndLoad(m_baseURL + "fragment_middle_click.html", true);
5227     WebFrame* frame = webViewHelper.webView()->mainFrame();
5228     const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5229     RefPtr<HistoryItem> firstItem = mainFrameLoader.currentItem();
5230     EXPECT_TRUE(firstItem);
5231
5232     registerMockedHttpURLLoad("white-1x1.png");
5233     FrameTestHelpers::loadFrame(frame, m_baseURL + "white-1x1.png");
5234     EXPECT_NE(firstItem.get(), mainFrameLoader.currentItem());
5235
5236     // Cache policy overrides should take.
5237     FrameTestHelpers::loadHistoryItem(frame, WebHistoryItem(firstItem), WebHistoryDifferentDocumentLoad, WebURLRequest::ReloadIgnoringCacheData);
5238     EXPECT_EQ(firstItem.get(), mainFrameLoader.currentItem());
5239     EXPECT_EQ(WebURLRequest::ReloadIgnoringCacheData, frame->dataSource()->request().cachePolicy());
5240 }
5241
5242
5243 class TestCachePolicyWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5244 public:
5245     explicit TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient* parentClient)
5246         : m_parentClient(parentClient)
5247         , m_policy(WebURLRequest::UseProtocolCachePolicy)
5248         , m_childClient(0)
5249         , m_willSendRequestCallCount(0)
5250         , m_childFrameCreationCount(0)
5251     {
5252     }
5253
5254     void setChildWebFrameClient(TestCachePolicyWebFrameClient* client) { m_childClient = client; }
5255     WebURLRequest::CachePolicy cachePolicy() const { return m_policy; }
5256     int willSendRequestCallCount() const { return m_willSendRequestCallCount; }
5257     int childFrameCreationCount() const { return m_childFrameCreationCount; }
5258
5259     virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString&)
5260     {
5261         ASSERT(m_childClient);
5262         m_childFrameCreationCount++;
5263         WebFrame* frame = WebLocalFrame::create(m_childClient);
5264         parent->appendChild(frame);
5265         return frame;
5266     }
5267
5268     virtual void didStartLoading(bool toDifferentDocument)
5269     {
5270         if (m_parentClient) {
5271             m_parentClient->didStartLoading(toDifferentDocument);
5272             return;
5273         }
5274         TestWebFrameClient::didStartLoading(toDifferentDocument);
5275     }
5276
5277     virtual void didStopLoading()
5278     {
5279         if (m_parentClient) {
5280             m_parentClient->didStopLoading();
5281             return;
5282         }
5283         TestWebFrameClient::didStopLoading();
5284     }
5285
5286     virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) OVERRIDE
5287     {
5288         m_policy = request.cachePolicy();
5289         m_willSendRequestCallCount++;
5290     }
5291
5292 private:
5293     TestCachePolicyWebFrameClient* m_parentClient;
5294
5295     WebURLRequest::CachePolicy m_policy;
5296     TestCachePolicyWebFrameClient* m_childClient;
5297     int m_willSendRequestCallCount;
5298     int m_childFrameCreationCount;
5299 };
5300
5301 TEST_F(WebFrameTest, ReloadIframe)
5302 {
5303     registerMockedHttpURLLoad("iframe_reload.html");
5304     registerMockedHttpURLLoad("visible_iframe.html");
5305     TestCachePolicyWebFrameClient mainClient(0);
5306     TestCachePolicyWebFrameClient childClient(&mainClient);
5307     mainClient.setChildWebFrameClient(&childClient);
5308
5309     FrameTestHelpers::WebViewHelper webViewHelper;
5310     webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, &mainClient);
5311
5312     WebLocalFrameImpl* mainFrame = webViewHelper.webViewImpl()->mainFrameImpl();
5313     RefPtrWillBeRawPtr<WebLocalFrameImpl> childFrame = toWebLocalFrameImpl(mainFrame->firstChild());
5314     ASSERT_EQ(childFrame->client(), &childClient);
5315     EXPECT_EQ(mainClient.childFrameCreationCount(), 1);
5316     EXPECT_EQ(childClient.willSendRequestCallCount(), 1);
5317     EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::UseProtocolCachePolicy);
5318
5319     FrameTestHelpers::reloadFrame(mainFrame);
5320
5321     // A new WebFrame should have been created, but the child WebFrameClient should be reused.
5322     ASSERT_NE(childFrame, toWebLocalFrameImpl(mainFrame->firstChild()));
5323     ASSERT_EQ(toWebLocalFrameImpl(mainFrame->firstChild())->client(), &childClient);
5324
5325     EXPECT_EQ(mainClient.childFrameCreationCount(), 2);
5326     EXPECT_EQ(childClient.willSendRequestCallCount(), 2);
5327     EXPECT_EQ(childClient.cachePolicy(), WebURLRequest::ReloadIgnoringCacheData);
5328 }
5329
5330 class TestSameDocumentWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5331 public:
5332     TestSameDocumentWebFrameClient()
5333         : m_frameLoadTypeSameSeen(false)
5334     {
5335     }
5336
5337     virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest&, const WebURLResponse&)
5338     {
5339         if (toWebLocalFrameImpl(frame)->frame()->loader().loadType() == FrameLoadTypeSame)
5340             m_frameLoadTypeSameSeen = true;
5341     }
5342
5343     bool frameLoadTypeSameSeen() const { return m_frameLoadTypeSameSeen; }
5344
5345 private:
5346     bool m_frameLoadTypeSameSeen;
5347 };
5348
5349 TEST_F(WebFrameTest, NavigateToSame)
5350 {
5351     registerMockedHttpURLLoad("navigate_to_same.html");
5352     TestSameDocumentWebFrameClient client;
5353     FrameTestHelpers::WebViewHelper webViewHelper;
5354     webViewHelper.initializeAndLoad(m_baseURL + "navigate_to_same.html", true, &client);
5355     EXPECT_FALSE(client.frameLoadTypeSameSeen());
5356
5357     FrameLoadRequest frameRequest(0, ResourceRequest(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document()->url()));
5358     toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().load(frameRequest);
5359     FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame());
5360
5361     EXPECT_TRUE(client.frameLoadTypeSameSeen());
5362 }
5363
5364 class TestSameDocumentWithImageWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5365 public:
5366     TestSameDocumentWithImageWebFrameClient()
5367         : m_numOfImageRequests(0)
5368     {
5369     }
5370
5371     virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&)
5372     {
5373         if (request.requestContext() == WebURLRequest::RequestContextImage) {
5374             m_numOfImageRequests++;
5375             EXPECT_EQ(WebURLRequest::UseProtocolCachePolicy, request.cachePolicy());
5376         }
5377     }
5378
5379     int numOfImageRequests() const { return m_numOfImageRequests; }
5380
5381 private:
5382     int m_numOfImageRequests;
5383 };
5384
5385 TEST_F(WebFrameTest, NavigateToSameNoConditionalRequestForSubresource)
5386 {
5387     registerMockedHttpURLLoad("foo_with_image.html");
5388     registerMockedHttpURLLoad("white-1x1.png");
5389     TestSameDocumentWithImageWebFrameClient client;
5390     FrameTestHelpers::WebViewHelper webViewHelper;
5391     webViewHelper.initializeAndLoad(m_baseURL + "foo_with_image.html", true, &client, 0, &configureLoadsImagesAutomatically);
5392
5393     WebCache::clear();
5394     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "foo_with_image.html");
5395
5396     EXPECT_EQ(client.numOfImageRequests(), 2);
5397 }
5398
5399 TEST_F(WebFrameTest, WebNodeImageContents)
5400 {
5401     FrameTestHelpers::WebViewHelper webViewHelper;
5402     webViewHelper.initializeAndLoad("about:blank", true);
5403     WebFrame* frame = webViewHelper.webView()->mainFrame();
5404
5405     static const char bluePNG[] = "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYV2NkYPj/n4EIwDiqEF8oUT94AFIQE/cCn90IAAAAAElFTkSuQmCC\">";
5406
5407     // Load up the image and test that we can extract the contents.
5408     KURL testURL = toKURL("about:blank");
5409     FrameTestHelpers::loadHTMLString(frame, bluePNG, testURL);
5410
5411     WebNode node = frame->document().body().firstChild();
5412     EXPECT_TRUE(node.isElementNode());
5413     WebElement element = node.to<WebElement>();
5414     WebImage image = element.imageContents();
5415     ASSERT_FALSE(image.isNull());
5416     EXPECT_EQ(image.size().width, 10);
5417     EXPECT_EQ(image.size().height, 10);
5418 //    FIXME: The rest of this test is disabled since the ImageDecodeCache state may be inconsistent when this test runs.
5419 //    crbug.com/266088
5420 //    SkBitmap bitmap = image.getSkBitmap();
5421 //    SkAutoLockPixels locker(bitmap);
5422 //    EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorBLUE);
5423 }
5424
5425 class TestStartStopCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5426 public:
5427     TestStartStopCallbackWebFrameClient()
5428         : m_startLoadingCount(0)
5429         , m_stopLoadingCount(0)
5430         , m_differentDocumentStartCount(0)
5431     {
5432     }
5433
5434     virtual void didStartLoading(bool toDifferentDocument) OVERRIDE
5435     {
5436         TestWebFrameClient::didStartLoading(toDifferentDocument);
5437         m_startLoadingCount++;
5438         if (toDifferentDocument)
5439             m_differentDocumentStartCount++;
5440     }
5441
5442     virtual void didStopLoading() OVERRIDE
5443     {
5444         TestWebFrameClient::didStopLoading();
5445         m_stopLoadingCount++;
5446     }
5447
5448     int startLoadingCount() const { return m_startLoadingCount; }
5449     int stopLoadingCount() const { return m_stopLoadingCount; }
5450     int differentDocumentStartCount() const { return m_differentDocumentStartCount; }
5451
5452 private:
5453     int m_startLoadingCount;
5454     int m_stopLoadingCount;
5455     int m_differentDocumentStartCount;
5456 };
5457
5458 TEST_F(WebFrameTest, PushStateStartsAndStops)
5459 {
5460     registerMockedHttpURLLoad("push_state.html");
5461     TestStartStopCallbackWebFrameClient client;
5462     FrameTestHelpers::WebViewHelper webViewHelper;
5463     webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5464
5465     EXPECT_EQ(client.startLoadingCount(), 2);
5466     EXPECT_EQ(client.stopLoadingCount(), 2);
5467     EXPECT_EQ(client.differentDocumentStartCount(), 1);
5468 }
5469
5470 class TestDidNavigateCommitTypeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5471 public:
5472     TestDidNavigateCommitTypeWebFrameClient()
5473         : m_lastCommitType(WebHistoryInertCommit)
5474     {
5475     }
5476
5477     virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType type) OVERRIDE
5478     {
5479         m_lastCommitType = type;
5480     }
5481
5482     WebHistoryCommitType lastCommitType() const { return m_lastCommitType; }
5483
5484 private:
5485     WebHistoryCommitType m_lastCommitType;
5486 };
5487
5488 TEST_F(WebFrameTest, SameDocumentHistoryNavigationCommitType)
5489 {
5490     registerMockedHttpURLLoad("push_state.html");
5491     TestDidNavigateCommitTypeWebFrameClient client;
5492     FrameTestHelpers::WebViewHelper webViewHelper;
5493     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "push_state.html", true, &client);
5494     RefPtr<HistoryItem> item = toLocalFrame(webViewImpl->page()->mainFrame())->loader().currentItem();
5495     runPendingTasks();
5496
5497     toLocalFrame(webViewImpl->page()->mainFrame())->loader().loadHistoryItem(item.get(), HistorySameDocumentLoad);
5498     EXPECT_EQ(WebBackForwardCommit, client.lastCommitType());
5499 }
5500
5501 class TestHistoryWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5502 public:
5503     TestHistoryWebFrameClient()
5504     {
5505         m_replacesCurrentHistoryItem = false;
5506         m_frame = 0;
5507     }
5508
5509     void didStartProvisionalLoad(WebLocalFrame* frame, bool isTransitionNavigation)
5510     {
5511         WebDataSource* ds = frame->provisionalDataSource();
5512         m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem();
5513         m_frame = frame;
5514     }
5515
5516     bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; }
5517     WebFrame* frame() { return m_frame; }
5518
5519 private:
5520     bool m_replacesCurrentHistoryItem;
5521     WebFrame* m_frame;
5522 };
5523
5524 // Test which ensures that the first navigation in a subframe will always
5525 // result in history entry being replaced and not a new one added.
5526 TEST_F(WebFrameTest, DISABLED_FirstFrameNavigationReplacesHistory)
5527 {
5528     registerMockedHttpURLLoad("history.html");
5529     registerMockedHttpURLLoad("find.html");
5530
5531     FrameTestHelpers::WebViewHelper webViewHelper;
5532     TestHistoryWebFrameClient client;
5533     webViewHelper.initializeAndLoad("about:blank", true, &client);
5534     EXPECT_TRUE(client.replacesCurrentHistoryItem());
5535
5536     WebFrame* frame = webViewHelper.webView()->mainFrame();
5537
5538     FrameTestHelpers::loadFrame(frame,
5539         "javascript:document.body.appendChild(document.createElement('iframe'))");
5540     WebFrame* iframe = frame->firstChild();
5541     EXPECT_EQ(client.frame(), iframe);
5542     EXPECT_TRUE(client.replacesCurrentHistoryItem());
5543
5544     FrameTestHelpers::loadFrame(frame,
5545         "javascript:window.frames[0].location.assign('" + m_baseURL + "history.html')");
5546     EXPECT_EQ(client.frame(), iframe);
5547     EXPECT_TRUE(client.replacesCurrentHistoryItem());
5548
5549     FrameTestHelpers::loadFrame(frame,
5550         "javascript:window.frames[0].location.assign('" + m_baseURL + "find.html')");
5551     EXPECT_EQ(client.frame(), iframe);
5552     EXPECT_FALSE(client.replacesCurrentHistoryItem());
5553
5554     // Repeat the test, but start out the iframe with initial URL, which is not
5555     // "about:blank".
5556     FrameTestHelpers::loadFrame(frame,
5557         "javascript:var f = document.createElement('iframe'); "
5558         "f.src = '" + m_baseURL + "history.html';"
5559         "document.body.appendChild(f)");
5560
5561     iframe = frame->firstChild()->nextSibling();
5562     EXPECT_EQ(client.frame(), iframe);
5563     EXPECT_TRUE(client.replacesCurrentHistoryItem());
5564
5565     FrameTestHelpers::loadFrame(frame,
5566         "javascript:window.frames[1].location.assign('" + m_baseURL + "find.html')");
5567     EXPECT_EQ(client.frame(), iframe);
5568     EXPECT_FALSE(client.replacesCurrentHistoryItem());
5569 }
5570
5571 // Test verifies that layout will change a layer's scrollable attibutes
5572 TEST_F(WebFrameTest, overflowHiddenRewrite)
5573 {
5574     registerMockedHttpURLLoad("non-scrollable.html");
5575     TestMainFrameUserOrProgrammaticScrollFrameClient client;
5576     OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient());
5577     FrameTestHelpers::WebViewHelper webViewHelper;
5578     webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
5579
5580     webViewHelper.webView()->resize(WebSize(100, 100));
5581     FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "non-scrollable.html");
5582
5583     RenderLayerCompositor* compositor =  webViewHelper.webViewImpl()->compositor();
5584     ASSERT_TRUE(compositor->scrollLayer());
5585
5586     // Verify that the WebLayer is not scrollable initially.
5587     GraphicsLayer* scrollLayer = compositor->scrollLayer();
5588     WebLayer* webScrollLayer = scrollLayer->platformLayer();
5589     ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
5590     ASSERT_FALSE(webScrollLayer->userScrollableVertical());
5591
5592     // Call javascript to make the layer scrollable, and verify it.
5593     WebLocalFrameImpl* frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame();
5594     frame->executeScript(WebScriptSource("allowScroll();"));
5595     webViewHelper.webView()->layout();
5596     ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
5597     ASSERT_TRUE(webScrollLayer->userScrollableVertical());
5598 }
5599
5600 // Test that currentHistoryItem reflects the current page, not the provisional load.
5601 TEST_F(WebFrameTest, CurrentHistoryItem)
5602 {
5603     registerMockedHttpURLLoad("fixed_layout.html");
5604     std::string url = m_baseURL + "fixed_layout.html";
5605
5606     FrameTestHelpers::WebViewHelper webViewHelper;
5607     webViewHelper.initialize();
5608     WebFrame* frame = webViewHelper.webView()->mainFrame();
5609     const FrameLoader& mainFrameLoader = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->loader();
5610     WebURLRequest request;
5611     request.initialize();
5612     request.setURL(toKURL(url));
5613     frame->loadRequest(request);
5614
5615     // Before commit, there is no history item.
5616     EXPECT_FALSE(mainFrameLoader.currentItem());
5617
5618     FrameTestHelpers::pumpPendingRequestsDoNotUse(frame);
5619
5620     // After commit, there is.
5621     HistoryItem* item = mainFrameLoader.currentItem();
5622     ASSERT_TRUE(item);
5623     EXPECT_EQ(WTF::String(url.data()), item->urlString());
5624 }
5625
5626 class FailCreateChildFrame : public FrameTestHelpers::TestWebFrameClient {
5627 public:
5628     FailCreateChildFrame() : m_callCount(0) { }
5629
5630     virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE
5631     {
5632         ++m_callCount;
5633         return 0;
5634     }
5635
5636     int callCount() const { return m_callCount; }
5637
5638 private:
5639     int m_callCount;
5640 };
5641
5642 // Test that we don't crash if WebFrameClient::createChildFrame() fails.
5643 TEST_F(WebFrameTest, CreateChildFrameFailure)
5644 {
5645     registerMockedHttpURLLoad("create_child_frame_fail.html");
5646     FailCreateChildFrame client;
5647     FrameTestHelpers::WebViewHelper webViewHelper;
5648     webViewHelper.initializeAndLoad(m_baseURL + "create_child_frame_fail.html", true, &client);
5649
5650     EXPECT_EQ(1, client.callCount());
5651 }
5652
5653 TEST_F(WebFrameTest, fixedPositionInFixedViewport)
5654 {
5655     UseMockScrollbarSettings mockScrollbarSettings;
5656     registerMockedHttpURLLoad("fixed-position-in-fixed-viewport.html");
5657     FrameTestHelpers::WebViewHelper webViewHelper;
5658     webViewHelper.initializeAndLoad(m_baseURL + "fixed-position-in-fixed-viewport.html", true, 0, 0, enableViewportSettings);
5659
5660     WebView* webView = webViewHelper.webView();
5661     webView->resize(WebSize(100, 100));
5662     webView->layout();
5663
5664     Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5665     Element* bottomFixed = document->getElementById("bottom-fixed");
5666     Element* topBottomFixed = document->getElementById("top-bottom-fixed");
5667     Element* rightFixed = document->getElementById("right-fixed");
5668     Element* leftRightFixed = document->getElementById("left-right-fixed");
5669
5670     webView->resize(WebSize(100, 200));
5671     webView->layout();
5672     EXPECT_EQ(200, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5673     EXPECT_EQ(200, topBottomFixed->offsetHeight());
5674
5675     webView->settings()->setMainFrameResizesAreOrientationChanges(false);
5676     webView->resize(WebSize(200, 200));
5677     webView->layout();
5678     EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5679     EXPECT_EQ(200, leftRightFixed->offsetWidth());
5680
5681     webView->settings()->setMainFrameResizesAreOrientationChanges(true);
5682     // Will scale the page by 1.5.
5683     webView->resize(WebSize(300, 330));
5684     webView->layout();
5685     EXPECT_EQ(220, bottomFixed->offsetTop() + bottomFixed->offsetHeight());
5686     EXPECT_EQ(220, topBottomFixed->offsetHeight());
5687     EXPECT_EQ(200, rightFixed->offsetLeft() + rightFixed->offsetWidth());
5688     EXPECT_EQ(200, leftRightFixed->offsetWidth());
5689 }
5690
5691 TEST_F(WebFrameTest, FrameViewSetFrameRect)
5692 {
5693     FrameTestHelpers::WebViewHelper webViewHelper;
5694     webViewHelper.initializeAndLoad("about:blank");
5695
5696     FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
5697     frameView->setFrameRect(IntRect(0, 0, 200, 200));
5698     EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), frameView->frameRect());
5699     frameView->setFrameRect(IntRect(100, 100, 200, 200));
5700     EXPECT_RECT_EQ(IntRect(100, 100, 200, 200), frameView->frameRect());
5701 }
5702
5703 // FIXME(bokan) Renable once Chromium-side of patch lands
5704 TEST_F(WebFrameTest, DISABLED_FrameViewScrollAccountsForTopControls)
5705 {
5706     FrameTestHelpers::WebViewHelper webViewHelper;
5707     webViewHelper.initializeAndLoad("about:blank");
5708
5709     WebViewImpl* webView = webViewHelper.webViewImpl();
5710     FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
5711
5712     webView->setTopControlsLayoutHeight(0);
5713     webView->resize(WebSize(100, 100));
5714     webView->setPageScaleFactor(2.0f);
5715     webView->layout();
5716
5717     webView->setMainFrameScrollOffset(WebPoint(20, 100));
5718     EXPECT_EQ_POINT(IntPoint(20, 50), IntPoint(frameView->scrollOffset()));
5719
5720     // Simulate the top controls showing by 20px, thus shrinking the viewport
5721     // and allowing it to scroll an additional 10px (since we're 2X zoomed).
5722     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 20.0f);
5723     EXPECT_EQ_POINT(IntPoint(50, 60), frameView->maximumScrollPosition());
5724
5725     // Show more, make sure the scroll actually gets clamped. Horizontal
5726     // direction shouldn't be affected.
5727     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 20.0f);
5728     webView->setMainFrameScrollOffset(WebPoint(100, 100));
5729     EXPECT_EQ_POINT(IntPoint(50, 70), IntPoint(frameView->scrollOffset()));
5730
5731     // Hide until there's 10px showing.
5732     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, -30.0f);
5733     EXPECT_EQ_POINT(IntPoint(50, 55), frameView->maximumScrollPosition());
5734
5735     // Simulate a RenderWidget::resize. The frame is resized to accomodate
5736     // the top controls and Blink's view of the top controls matches that of
5737     // the CC
5738     webView->setTopControlsLayoutHeight(10.0f);
5739     webView->resize(WebSize(100, 90));
5740     webView->layout();
5741     EXPECT_EQ_POINT(IntPoint(50, 45), frameView->maximumScrollPosition());
5742
5743     // Now simulate hiding.
5744     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, -10.0f);
5745     EXPECT_EQ_POINT(IntPoint(50, 40), frameView->maximumScrollPosition());
5746
5747     // Reset to original state: 100px widget height, top controls fully hidden.
5748     webView->setTopControlsLayoutHeight(0.0f);
5749     webView->resize(WebSize(100, 100));
5750     webView->layout();
5751     EXPECT_EQ_POINT(IntPoint(50, 50), frameView->maximumScrollPosition());
5752
5753     // Show the top controls by just 1px, since we're zoomed in to 2X, that
5754     // should allow an extra 0.5px of scrolling, but since we quantize to ints
5755     // it should clamp such that we don't show anything outside bounds.
5756     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 1.0f);
5757     EXPECT_EQ_POINT(IntPoint(50, 50), frameView->maximumScrollPosition());
5758
5759     webView->applyViewportDeltas(WebSize(0, 0), 1.0f, 2.0f);
5760     EXPECT_EQ_POINT(IntPoint(50, 51), frameView->maximumScrollPosition());
5761
5762
5763 }
5764
5765 TEST_F(WebFrameTest, FullscreenLayerNonScrollable)
5766 {
5767     FakeCompositingWebViewClient client;
5768     registerMockedHttpURLLoad("fullscreen_div.html");
5769     FrameTestHelpers::WebViewHelper webViewHelper;
5770     int viewportWidth = 640;
5771     int viewportHeight = 480;
5772     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5773     webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5774     webViewImpl->layout();
5775
5776     Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5777     UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5778     Element* divFullscreen = document->getElementById("div1");
5779     Fullscreen::from(*document).requestFullscreen(*divFullscreen, Fullscreen::PrefixedRequest);
5780     webViewImpl->didEnterFullScreen();
5781     webViewImpl->layout();
5782
5783     // Verify that the main frame bounds are empty.
5784     ASSERT_TRUE(Fullscreen::isFullScreen(*document));
5785     WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5786     ASSERT_EQ(WebSize(), webScrollLayer->bounds());
5787
5788     // Verify that the main frame is scrollable upon exiting fullscreen.
5789     webViewImpl->didExitFullScreen();
5790     webViewImpl->layout();
5791     ASSERT_FALSE(Fullscreen::isFullScreen(*document));
5792     webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5793     ASSERT_NE(WebSize(), webScrollLayer->bounds());
5794 }
5795
5796 TEST_F(WebFrameTest, FullscreenMainFrameScrollable)
5797 {
5798     FakeCompositingWebViewClient client;
5799     registerMockedHttpURLLoad("fullscreen_div.html");
5800     FrameTestHelpers::WebViewHelper webViewHelper;
5801     int viewportWidth = 640;
5802     int viewportHeight = 480;
5803     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "fullscreen_div.html", true, 0, &client, &configueCompositingWebView);
5804     webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
5805     webViewImpl->layout();
5806
5807     Document* document = toWebLocalFrameImpl(webViewImpl->mainFrame())->frame()->document();
5808     UserGestureIndicator gesture(DefinitelyProcessingUserGesture);
5809     Fullscreen::from(*document).requestFullscreen(*document->documentElement(), Fullscreen::PrefixedRequest);
5810     webViewImpl->didEnterFullScreen();
5811     webViewImpl->layout();
5812
5813     // Verify that the main frame is still scrollable.
5814     ASSERT_TRUE(Fullscreen::isFullScreen(*document));
5815     WebLayer* webScrollLayer = webViewImpl->compositor()->scrollLayer()->platformLayer();
5816     ASSERT_TRUE(webScrollLayer->scrollable());
5817 }
5818
5819 TEST_F(WebFrameTest, RenderBlockPercentHeightDescendants)
5820 {
5821     registerMockedHttpURLLoad("percent-height-descendants.html");
5822     FrameTestHelpers::WebViewHelper webViewHelper;
5823     webViewHelper.initializeAndLoad(m_baseURL + "percent-height-descendants.html");
5824
5825     WebView* webView = webViewHelper.webView();
5826     webView->resize(WebSize(800, 800));
5827     webView->layout();
5828
5829     Document* document = toWebLocalFrameImpl(webView->mainFrame())->frame()->document();
5830     RenderBlock* container = toRenderBlock(document->getElementById("container")->renderer());
5831     RenderBox* percentHeightInAnonymous = toRenderBox(document->getElementById("percent-height-in-anonymous")->renderer());
5832     RenderBox* percentHeightDirectChild = toRenderBox(document->getElementById("percent-height-direct-child")->renderer());
5833
5834     EXPECT_TRUE(RenderBlock::hasPercentHeightDescendant(percentHeightInAnonymous));
5835     EXPECT_TRUE(RenderBlock::hasPercentHeightDescendant(percentHeightDirectChild));
5836
5837     ASSERT_TRUE(container->percentHeightDescendants());
5838     ASSERT_TRUE(container->hasPercentHeightDescendants());
5839     EXPECT_EQ(2U, container->percentHeightDescendants()->size());
5840     EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightInAnonymous));
5841     EXPECT_TRUE(container->percentHeightDescendants()->contains(percentHeightDirectChild));
5842
5843     RenderBlock* anonymousBlock = percentHeightInAnonymous->containingBlock();
5844     EXPECT_TRUE(anonymousBlock->isAnonymous());
5845     EXPECT_FALSE(anonymousBlock->hasPercentHeightDescendants());
5846 }
5847
5848 TEST_F(WebFrameTest, HasVisibleContentOnVisibleFrames)
5849 {
5850     registerMockedHttpURLLoad("visible_frames.html");
5851     FrameTestHelpers::WebViewHelper webViewHelper;
5852     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "visible_frames.html");
5853     for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5854         EXPECT_TRUE(frame->hasVisibleContent());
5855     }
5856 }
5857
5858 TEST_F(WebFrameTest, HasVisibleContentOnHiddenFrames)
5859 {
5860     registerMockedHttpURLLoad("hidden_frames.html");
5861     FrameTestHelpers::WebViewHelper webViewHelper;
5862     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "hidden_frames.html");
5863     for (WebFrame* frame = webViewImpl->mainFrameImpl()->traverseNext(false); frame; frame = frame->traverseNext(false)) {
5864         EXPECT_FALSE(frame->hasVisibleContent());
5865     }
5866 }
5867
5868 class ManifestChangeWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5869 public:
5870     ManifestChangeWebFrameClient() : m_manifestChangeCount(0) { }
5871     virtual void didChangeManifest(WebLocalFrame*) OVERRIDE
5872     {
5873         ++m_manifestChangeCount;
5874     }
5875
5876     int manifestChangeCount() { return m_manifestChangeCount; }
5877
5878 private:
5879     int m_manifestChangeCount;
5880 };
5881
5882 TEST_F(WebFrameTest, NotifyManifestChange)
5883 {
5884     registerMockedHttpURLLoad("link-manifest-change.html");
5885
5886     ManifestChangeWebFrameClient webFrameClient;
5887     FrameTestHelpers::WebViewHelper webViewHelper;
5888     webViewHelper.initializeAndLoad(m_baseURL + "link-manifest-change.html", true, &webFrameClient);
5889
5890     EXPECT_EQ(14, webFrameClient.manifestChangeCount());
5891 }
5892
5893 TEST_F(WebFrameTest, ReloadBypassingCache)
5894 {
5895     // Check that a reload ignoring cache on a frame will result in the cache
5896     // policy of the request being set to ReloadBypassingCache.
5897     registerMockedHttpURLLoad("foo.html");
5898     FrameTestHelpers::WebViewHelper webViewHelper;
5899     webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
5900     WebFrame* frame = webViewHelper.webView()->mainFrame();
5901     FrameTestHelpers::reloadFrameIgnoringCache(frame);
5902     EXPECT_EQ(WebURLRequest::ReloadBypassingCache, frame->dataSource()->request().cachePolicy());
5903 }
5904
5905 static void nodeImageTestValidation(const IntSize& referenceBitmapSize, DragImage* dragImage)
5906 {
5907     // Prepare the reference bitmap.
5908     SkBitmap bitmap;
5909     bitmap.allocN32Pixels(referenceBitmapSize.width(), referenceBitmapSize.height());
5910     SkCanvas canvas(bitmap);
5911     canvas.drawColor(SK_ColorGREEN);
5912
5913     EXPECT_EQ(referenceBitmapSize.width(), dragImage->size().width());
5914     EXPECT_EQ(referenceBitmapSize.height(), dragImage->size().height());
5915     const SkBitmap& dragBitmap = dragImage->bitmap();
5916     SkAutoLockPixels lockPixel(dragBitmap);
5917     EXPECT_EQ(0, memcmp(bitmap.getPixels(), dragBitmap.getPixels(), bitmap.getSize()));
5918 }
5919
5920 TEST_F(WebFrameTest, NodeImageTestCSSTransform)
5921 {
5922     FrameTestHelpers::WebViewHelper webViewHelper;
5923     OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-transform"));
5924     EXPECT_TRUE(dragImage);
5925
5926     nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5927 }
5928
5929 TEST_F(WebFrameTest, NodeImageTestCSS3DTransform)
5930 {
5931     FrameTestHelpers::WebViewHelper webViewHelper;
5932     OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-css-3dtransform"));
5933     EXPECT_TRUE(dragImage);
5934
5935     nodeImageTestValidation(IntSize(20, 40), dragImage.get());
5936 }
5937
5938 TEST_F(WebFrameTest, NodeImageTestInlineBlock)
5939 {
5940     FrameTestHelpers::WebViewHelper webViewHelper;
5941     OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-inlineblock"));
5942     EXPECT_TRUE(dragImage);
5943
5944     nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5945 }
5946
5947 TEST_F(WebFrameTest, NodeImageTestFloatLeft)
5948 {
5949     FrameTestHelpers::WebViewHelper webViewHelper;
5950     OwnPtr<DragImage> dragImage = nodeImageTestSetup(&webViewHelper, std::string("case-float-left-overflow-hidden"));
5951     EXPECT_TRUE(dragImage);
5952
5953     nodeImageTestValidation(IntSize(40, 40), dragImage.get());
5954 }
5955
5956 // Crashes on Android: http://crbug.com/403804
5957 #if OS(ANDROID)
5958 TEST_F(WebFrameTest, DISABLED_PrintingBasic)
5959 #else
5960 TEST_F(WebFrameTest, PrintingBasic)
5961 #endif
5962 {
5963     FrameTestHelpers::WebViewHelper webViewHelper;
5964     webViewHelper.initializeAndLoad("data:text/html,Hello, world.");
5965
5966     WebFrame* frame = webViewHelper.webView()->mainFrame();
5967
5968     WebPrintParams printParams;
5969     printParams.printContentArea.width = 500;
5970     printParams.printContentArea.height = 500;
5971
5972     int pageCount = frame->printBegin(printParams);
5973     EXPECT_EQ(1, pageCount);
5974     frame->printEnd();
5975 }
5976
5977 class ThemeColorTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
5978 public:
5979     ThemeColorTestWebFrameClient()
5980         : m_didNotify(false)
5981     {
5982     }
5983
5984     void reset()
5985     {
5986         m_didNotify = false;
5987     }
5988
5989     bool didNotify() const
5990     {
5991         return m_didNotify;
5992     }
5993
5994 private:
5995     virtual void didChangeThemeColor()
5996     {
5997         m_didNotify = true;
5998     }
5999
6000     bool m_didNotify;
6001 };
6002
6003 TEST_F(WebFrameTest, ThemeColor)
6004 {
6005     registerMockedHttpURLLoad("theme_color_test.html");
6006     FrameTestHelpers::WebViewHelper webViewHelper;
6007     ThemeColorTestWebFrameClient client;
6008     webViewHelper.initializeAndLoad(m_baseURL + "theme_color_test.html", true, &client);
6009     EXPECT_TRUE(client.didNotify());
6010     WebLocalFrameImpl* frame = webViewHelper.webViewImpl()->mainFrameImpl();
6011     EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6012     // Change color by rgb.
6013     client.reset();
6014     frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'rgb(0, 0, 0)');"));
6015     EXPECT_TRUE(client.didNotify());
6016     EXPECT_EQ(0xff000000, frame->document().themeColor());
6017     // Change color by hsl.
6018     client.reset();
6019     frame->executeScript(WebScriptSource("document.getElementById('tc1').setAttribute('content', 'hsl(240,100%, 50%)');"));
6020     EXPECT_TRUE(client.didNotify());
6021     EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6022     // Change of second theme-color meta tag will not change frame's theme
6023     // color.
6024     client.reset();
6025     frame->executeScript(WebScriptSource("document.getElementById('tc2').setAttribute('content', '#00FF00');"));
6026     EXPECT_TRUE(client.didNotify());
6027     EXPECT_EQ(0xff0000ff, frame->document().themeColor());
6028 }
6029
6030 class WebFrameSwapTest : public WebFrameTest {
6031 protected:
6032     WebFrameSwapTest()
6033     {
6034         registerMockedHttpURLLoad("frame-a-b-c.html");
6035         registerMockedHttpURLLoad("subframe-a.html");
6036         registerMockedHttpURLLoad("subframe-b.html");
6037         registerMockedHttpURLLoad("subframe-c.html");
6038         registerMockedHttpURLLoad("subframe-hello.html");
6039
6040         m_webViewHelper.initializeAndLoad(m_baseURL + "frame-a-b-c.html");
6041     }
6042
6043     void reset() { m_webViewHelper.reset(); }
6044     WebFrame* mainFrame() const { return m_webViewHelper.webView()->mainFrame(); }
6045
6046 private:
6047     FrameTestHelpers::WebViewHelper m_webViewHelper;
6048 };
6049
6050 // FIXME: We should have tests for main frame swaps, but it interacts poorly
6051 // with the geolocation inspector agent, since the lifetime of the inspector
6052 // agent is tied to the Page, but the inspector agent is created by the
6053 // instantiation of the main frame.
6054
6055 void swapAndVerifyFirstChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6056 {
6057     SCOPED_TRACE(message);
6058     parent->firstChild()->swap(newChild);
6059
6060     EXPECT_EQ(newChild, parent->firstChild());
6061     EXPECT_EQ(newChild->parent(), parent);
6062     EXPECT_EQ(newChild, parent->lastChild()->previousSibling()->previousSibling());
6063     EXPECT_EQ(newChild->nextSibling(), parent->lastChild()->previousSibling());
6064 }
6065
6066 TEST_F(WebFrameSwapTest, SwapFirstChild)
6067 {
6068     WebFrame* remoteFrame = WebRemoteFrame::create(0);
6069     swapAndVerifyFirstChildConsistency("local->remote", mainFrame(), remoteFrame);
6070
6071     FrameTestHelpers::TestWebFrameClient client;
6072     WebFrame* localFrame = WebLocalFrame::create(&client);
6073     swapAndVerifyFirstChildConsistency("remote->local", mainFrame(), localFrame);
6074
6075     // FIXME: This almost certainly fires more load events on the iframe element
6076     // than it should.
6077     // Finally, make sure an embedder triggered load in the local frame swapped
6078     // back in works.
6079     FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6080     std::string content = localFrame->contentAsText(1024).utf8();
6081     EXPECT_EQ("hello", content);
6082
6083     // Manually reset to break WebViewHelper's dependency on the stack allocated
6084     // TestWebFrameClient.
6085     reset();
6086     remoteFrame->close();
6087 }
6088
6089 void swapAndVerifyMiddleChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6090 {
6091     SCOPED_TRACE(message);
6092     parent->firstChild()->nextSibling()->swap(newChild);
6093
6094     EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
6095     EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
6096     EXPECT_EQ(newChild->parent(), parent);
6097     EXPECT_EQ(newChild, parent->firstChild()->nextSibling());
6098     EXPECT_EQ(newChild->previousSibling(), parent->firstChild());
6099     EXPECT_EQ(newChild, parent->lastChild()->previousSibling());
6100     EXPECT_EQ(newChild->nextSibling(), parent->lastChild());
6101 }
6102
6103 TEST_F(WebFrameSwapTest, SwapMiddleChild)
6104 {
6105     WebFrame* remoteFrame = WebRemoteFrame::create(0);
6106     swapAndVerifyMiddleChildConsistency("local->remote", mainFrame(), remoteFrame);
6107
6108     FrameTestHelpers::TestWebFrameClient client;
6109     WebFrame* localFrame = WebLocalFrame::create(&client);
6110     swapAndVerifyMiddleChildConsistency("remote->local", mainFrame(), localFrame);
6111
6112     // FIXME: This almost certainly fires more load events on the iframe element
6113     // than it should.
6114     // Finally, make sure an embedder triggered load in the local frame swapped
6115     // back in works.
6116     FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6117     std::string content = localFrame->contentAsText(1024).utf8();
6118     EXPECT_EQ("hello", content);
6119
6120     // Manually reset to break WebViewHelper's dependency on the stack allocated
6121     // TestWebFrameClient.
6122     reset();
6123     remoteFrame->close();
6124 }
6125
6126 void swapAndVerifyLastChildConsistency(const char* const message, WebFrame* parent, WebFrame* newChild)
6127 {
6128     SCOPED_TRACE(message);
6129     parent->lastChild()->swap(newChild);
6130
6131     EXPECT_EQ(newChild, parent->lastChild());
6132     EXPECT_EQ(newChild->parent(), parent);
6133     EXPECT_EQ(newChild, parent->firstChild()->nextSibling()->nextSibling());
6134     EXPECT_EQ(newChild->previousSibling(), parent->firstChild()->nextSibling());
6135 }
6136
6137 TEST_F(WebFrameSwapTest, SwapLastChild)
6138 {
6139     WebFrame* remoteFrame = WebRemoteFrame::create(0);
6140     swapAndVerifyLastChildConsistency("local->remote", mainFrame(), remoteFrame);
6141
6142     FrameTestHelpers::TestWebFrameClient client;
6143     WebFrame* localFrame = WebLocalFrame::create(&client);
6144     swapAndVerifyLastChildConsistency("remote->local", mainFrame(), localFrame);
6145
6146     // FIXME: This almost certainly fires more load events on the iframe element
6147     // than it should.
6148     // Finally, make sure an embedder triggered load in the local frame swapped
6149     // back in works.
6150     FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6151     std::string content = localFrame->contentAsText(1024).utf8();
6152     EXPECT_EQ("hello", content);
6153
6154     // Manually reset to break WebViewHelper's dependency on the stack allocated
6155     // TestWebFrameClient.
6156     reset();
6157     remoteFrame->close();
6158 }
6159
6160 void swapAndVerifySubframeConsistency(const char* const message, WebFrame* oldFrame, WebFrame* newFrame)
6161 {
6162     SCOPED_TRACE(message);
6163
6164     EXPECT_TRUE(oldFrame->firstChild());
6165     oldFrame->swap(newFrame);
6166
6167     EXPECT_FALSE(newFrame->firstChild());
6168     EXPECT_FALSE(newFrame->lastChild());
6169 }
6170
6171 TEST_F(WebFrameSwapTest, SwapParentShouldDetachChildren)
6172 {
6173     WebRemoteFrame* remoteFrame = WebRemoteFrame::create(0);
6174     WebFrame* targetFrame = mainFrame()->firstChild()->nextSibling();
6175     EXPECT_TRUE(targetFrame);
6176     swapAndVerifySubframeConsistency("local->remote", targetFrame, remoteFrame);
6177
6178     targetFrame = mainFrame()->firstChild()->nextSibling();
6179     EXPECT_TRUE(targetFrame);
6180
6181     // Create child frames in the target frame before testing the swap.
6182     FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient;
6183     remoteFrame->createRemoteChild("", &remoteFrameClient);
6184
6185     FrameTestHelpers::TestWebFrameClient client;
6186     WebFrame* localFrame = WebLocalFrame::create(&client);
6187     swapAndVerifySubframeConsistency("remote->local", targetFrame, localFrame);
6188
6189     // FIXME: This almost certainly fires more load events on the iframe element
6190     // than it should.
6191     // Finally, make sure an embedder triggered load in the local frame swapped
6192     // back in works.
6193     FrameTestHelpers::loadFrame(localFrame, m_baseURL + "subframe-hello.html");
6194     std::string content = localFrame->contentAsText(1024).utf8();
6195     EXPECT_EQ("hello", content);
6196
6197     // Manually reset to break WebViewHelper's dependency on the stack allocated
6198     // TestWebFrameClient.
6199     reset();
6200     remoteFrame->close();
6201 }
6202
6203 class MockDocumentThreadableLoaderClient : public DocumentThreadableLoaderClient {
6204 public:
6205     MockDocumentThreadableLoaderClient() : m_failed(false) { }
6206     virtual void didFail(const ResourceError&) OVERRIDE { m_failed = true;}
6207
6208     void reset() { m_failed = false; }
6209     bool failed() { return m_failed; }
6210
6211     bool m_failed;
6212 };
6213
6214 // FIXME: This would be better as a unittest on DocumentThreadableLoader but it
6215 // requires spin-up of a frame. It may be possible to remove that requirement
6216 // and convert it to a unittest.
6217 TEST_F(WebFrameTest, LoaderOriginAccess)
6218 {
6219     FrameTestHelpers::WebViewHelper webViewHelper;
6220     webViewHelper.initializeAndLoad("about:blank");
6221
6222     SchemeRegistry::registerURLSchemeAsDisplayIsolated("chrome");
6223
6224     // Cross-origin request.
6225     KURL resourceUrl(ParsedURLString, "chrome://test.pdf");
6226     registerMockedChromeURLLoad("test.pdf");
6227
6228     RefPtrWillBeRawPtr<LocalFrame> frame(toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame()));
6229
6230     MockDocumentThreadableLoaderClient client;
6231     ThreadableLoaderOptions options;
6232
6233     // First try to load the request with regular access. Should fail.
6234     options.crossOriginRequestPolicy = UseAccessControl;
6235     ResourceLoaderOptions resourceLoaderOptions;
6236     DocumentThreadableLoader::loadResourceSynchronously(
6237         *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
6238     EXPECT_TRUE(client.failed());
6239
6240     client.reset();
6241     // Try to load the request with cross origin access. Should succeed.
6242     options.crossOriginRequestPolicy = AllowCrossOriginRequests;
6243     DocumentThreadableLoader::loadResourceSynchronously(
6244         *frame->document(), ResourceRequest(resourceUrl), client, options, resourceLoaderOptions);
6245     EXPECT_FALSE(client.failed());
6246 }
6247
6248 class NavigationTransitionCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
6249 public:
6250     NavigationTransitionCallbackWebFrameClient()
6251         : m_navigationalDataReceivedCount(0)
6252         , m_provisionalLoadCount(0)
6253         , m_wasLastProvisionalLoadATransition(false) { }
6254
6255     virtual void addNavigationTransitionData(const WebString& allowedDestinationOrigin, const WebString& selector, const WebString& markup) OVERRIDE
6256     {
6257         m_navigationalDataReceivedCount++;
6258     }
6259
6260     virtual void didStartProvisionalLoad(WebLocalFrame* localFrame, bool isTransitionNavigation) OVERRIDE
6261     {
6262         m_provisionalLoadCount++;
6263         m_wasLastProvisionalLoadATransition = isTransitionNavigation;
6264     }
6265
6266     unsigned navigationalDataReceivedCount() const { return m_navigationalDataReceivedCount; }
6267     unsigned provisionalLoadCount() const { return m_provisionalLoadCount; }
6268     bool wasLastProvisionalLoadATransition() const { return m_wasLastProvisionalLoadATransition; }
6269
6270 private:
6271     unsigned m_navigationalDataReceivedCount;
6272     unsigned m_provisionalLoadCount;
6273     bool m_wasLastProvisionalLoadATransition;
6274 };
6275
6276 TEST_F(WebFrameTest, NavigationTransitionCallbacks)
6277 {
6278     RuntimeEnabledFeatures::setNavigationTransitionsEnabled(true);
6279     FrameTestHelpers::WebViewHelper viewHelper;
6280     NavigationTransitionCallbackWebFrameClient frameClient;
6281     WebLocalFrame* localFrame = viewHelper.initialize(true, &frameClient)->mainFrame()->toWebLocalFrame();
6282
6283     const char* transitionHTMLString =
6284         "<!DOCTYPE html>"
6285         "<meta name='transition-elements' content='#foo;*'>"
6286         "<div id='foo'>";
6287
6288     // Initial document load should not be a transition.
6289     FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("http://www.test.com"));
6290     EXPECT_EQ(1u, frameClient.provisionalLoadCount());
6291     EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6292     EXPECT_EQ(0u, frameClient.navigationalDataReceivedCount());
6293
6294     // Going from www.test.com containing transition elements to about:blank, should be a transition.
6295     FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("about:blank"));
6296     EXPECT_EQ(2u, frameClient.provisionalLoadCount());
6297     EXPECT_TRUE(frameClient.wasLastProvisionalLoadATransition());
6298     EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6299
6300     // Navigating to the URL of the current page shouldn't be a transition.
6301     FrameTestHelpers::loadHTMLString(localFrame, transitionHTMLString, toKURL("about:blank"));
6302     EXPECT_EQ(3u, frameClient.provisionalLoadCount());
6303     EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6304     EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6305
6306     // Neither should a page reload.
6307     localFrame->reload();
6308     EXPECT_EQ(4u, frameClient.provisionalLoadCount());
6309     EXPECT_FALSE(frameClient.wasLastProvisionalLoadATransition());
6310     EXPECT_EQ(1u, frameClient.navigationalDataReceivedCount());
6311 }
6312
6313 } // namespace