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