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