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