1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include "public/web/WebFrame.h" 34 35 #include "SkBitmap.h" 36 #include "SkCanvas.h" 37 #include "bindings/core/v8/V8Node.h" 38 #include "core/UserAgentStyleSheets.h" 39 #include "core/clipboard/DataTransfer.h" 40 #include "core/css/StyleSheetContents.h" 41 #include "core/css/resolver/StyleResolver.h" 42 #include "core/css/resolver/ViewportStyleResolver.h" 43 #include "core/dom/DocumentMarkerController.h" 44 #include "core/dom/Fullscreen.h" 45 #include "core/dom/NodeRenderStyle.h" 46 #include "core/dom/Range.h" 47 #include "core/editing/Editor.h" 48 #include "core/editing/FrameSelection.h" 49 #include "core/editing/SpellChecker.h" 50 #include "core/editing/VisiblePosition.h" 51 #include "core/events/MouseEvent.h" 52 #include "core/fetch/MemoryCache.h" 53 #include "core/frame/FrameHost.h" 54 #include "core/frame/FrameView.h" 55 #include "core/frame/LocalFrame.h" 56 #include "core/frame/PinchViewport.h" 57 #include "core/frame/Settings.h" 58 #include "core/html/HTMLDocument.h" 59 #include "core/html/HTMLFormElement.h" 60 #include "core/loader/DocumentThreadableLoader.h" 61 #include "core/loader/DocumentThreadableLoaderClient.h" 62 #include "core/loader/FrameLoadRequest.h" 63 #include "core/loader/ThreadableLoader.h" 64 #include "core/page/EventHandler.h" 65 #include "core/page/Page.h" 66 #include "core/rendering/HitTestResult.h" 67 #include "core/rendering/RenderView.h" 68 #include "core/rendering/compositing/RenderLayerCompositor.h" 69 #include "core/testing/URLTestHelpers.h" 70 #include "platform/DragImage.h" 71 #include "platform/RuntimeEnabledFeatures.h" 72 #include "platform/UserGestureIndicator.h" 73 #include "platform/geometry/FloatRect.h" 74 #include "platform/network/ResourceError.h" 75 #include "platform/scroll/ScrollbarTheme.h" 76 #include "platform/weborigin/SchemeRegistry.h" 77 #include "public/platform/Platform.h" 78 #include "public/platform/WebFloatRect.h" 79 #include "public/platform/WebSelectionBound.h" 80 #include "public/platform/WebThread.h" 81 #include "public/platform/WebURL.h" 82 #include "public/platform/WebURLResponse.h" 83 #include "public/platform/WebUnitTestSupport.h" 84 #include "public/web/WebCache.h" 85 #include "public/web/WebDataSource.h" 86 #include "public/web/WebDocument.h" 87 #include "public/web/WebFindOptions.h" 88 #include "public/web/WebFormElement.h" 89 #include "public/web/WebFrameClient.h" 90 #include "public/web/WebHistoryItem.h" 91 #include "public/web/WebPrintParams.h" 92 #include "public/web/WebRange.h" 93 #include "public/web/WebRemoteFrame.h" 94 #include "public/web/WebScriptSource.h" 95 #include "public/web/WebSearchableFormData.h" 96 #include "public/web/WebSecurityOrigin.h" 97 #include "public/web/WebSecurityPolicy.h" 98 #include "public/web/WebSettings.h" 99 #include "public/web/WebSpellCheckClient.h" 100 #include "public/web/WebTextCheckingCompletion.h" 101 #include "public/web/WebTextCheckingResult.h" 102 #include "public/web/WebViewClient.h" 103 #include "web/WebLocalFrameImpl.h" 104 #include "web/WebRemoteFrameImpl.h" 105 #include "web/WebViewImpl.h" 106 #include "web/tests/FrameTestHelpers.h" 107 #include "wtf/Forward.h" 108 #include "wtf/dtoa/utils.h" 109 #include <gmock/gmock.h> 110 #include <gtest/gtest.h> 111 #include <map> 112 #include <v8.h> 113 114 namespace { 115 116 using blink::URLTestHelpers::toKURL; 117 using blink::FrameTestHelpers::runPendingTasks; 118 using namespace blink; 119 120 const int touchPointPadding = 32; 121 122 #define EXPECT_RECT_EQ(a, b) \ 123 do { \ 124 EXPECT_EQ(a.x(), b.x()); \ 125 EXPECT_EQ(a.y(), b.y()); \ 126 EXPECT_EQ(a.width(), b.width()); \ 127 EXPECT_EQ(a.height(), b.height()); \ 128 } while (false) 129 130 #define EXPECT_POINT_EQ(expected, actual) \ 131 do { \ 132 EXPECT_EQ((expected).x(), (actual).x()); \ 133 EXPECT_EQ((expected).y(), (actual).y()); \ 134 } while (false) 135 136 #define EXPECT_FLOAT_POINT_EQ(expected, actual) \ 137 do { \ 138 EXPECT_FLOAT_EQ((expected).x(), (actual).x()); \ 139 EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \ 140 } while (false) 141 142 #define EXPECT_EQ_POINT(a, b) \ 143 EXPECT_EQ(a.x(), b.x()); \ 144 EXPECT_EQ(a.y(), b.y()); 145 146 class FakeCompositingWebViewClient : public FrameTestHelpers::TestWebViewClient { 147 public: 148 virtual bool enterFullScreen() OVERRIDE { return true; } 149 }; 150 151 class WebFrameTest : public testing::Test { 152 protected: 153 WebFrameTest() 154 : m_baseURL("http://www.test.com/") 155 , m_chromeURL("chrome://") 156 { 157 } 158 159 virtual ~WebFrameTest() 160 { 161 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); 162 } 163 164 void registerMockedHttpURLLoad(const std::string& fileName) 165 { 166 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str())); 167 } 168 169 void registerMockedChromeURLLoad(const std::string& fileName) 170 { 171 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_chromeURL.c_str()), WebString::fromUTF8(fileName.c_str())); 172 } 173 174 void applyViewportStyleOverride(FrameTestHelpers::WebViewHelper* webViewHelper) 175 { 176 RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0)); 177 styleSheet->parseString(String(blink::viewportAndroidCss, sizeof(blink::viewportAndroidCss))); 178 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create(); 179 ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen")); 180 181 Document* document = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame())->document(); 182 document->ensureStyleResolver().viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin); 183 document->ensureStyleResolver().viewportStyleResolver()->resolve(); 184 } 185 186 static void configueCompositingWebView(WebSettings* settings) 187 { 188 settings->setAcceleratedCompositingEnabled(true); 189 settings->setPreferCompositingToLCDTextEnabled(true); 190 } 191 192 static void configureLoadsImagesAutomatically(WebSettings* settings) 193 { 194 settings->setLoadsImagesAutomatically(true); 195 } 196 197 void initializeTextSelectionWebView(const std::string& url, FrameTestHelpers::WebViewHelper* webViewHelper) 198 { 199 webViewHelper->initializeAndLoad(url, true); 200 webViewHelper->webView()->settings()->setDefaultFontSize(12); 201 webViewHelper->webView()->resize(WebSize(640, 480)); 202 } 203 204 PassOwnPtr<DragImage> nodeImageTestSetup(FrameTestHelpers::WebViewHelper* webViewHelper, const std::string& testcase) 205 { 206 registerMockedHttpURLLoad("nodeimage.html"); 207 webViewHelper->initializeAndLoad(m_baseURL + "nodeimage.html"); 208 webViewHelper->webView()->resize(WebSize(640, 480)); 209 webViewHelper->webView()->layout(); 210 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper->webViewImpl()->page()->mainFrame()); 211 ASSERT(frame); 212 Element* element = frame->document()->getElementById(testcase.c_str()); 213 return frame->nodeImage(*element); 214 } 215 216 std::string m_baseURL; 217 std::string m_chromeURL; 218 }; 219 220 class UseMockScrollbarSettings { 221 public: 222 UseMockScrollbarSettings() 223 { 224 Settings::setMockScrollbarsEnabled(true); 225 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true); 226 EXPECT_TRUE(ScrollbarTheme::theme()->usesOverlayScrollbars()); 227 } 228 229 ~UseMockScrollbarSettings() 230 { 231 Settings::setMockScrollbarsEnabled(false); 232 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(false); 233 } 234 }; 235 236 TEST_F(WebFrameTest, ContentText) 237 { 238 registerMockedHttpURLLoad("iframes_test.html"); 239 registerMockedHttpURLLoad("visible_iframe.html"); 240 registerMockedHttpURLLoad("invisible_iframe.html"); 241 registerMockedHttpURLLoad("zero_sized_iframe.html"); 242 243 FrameTestHelpers::WebViewHelper webViewHelper; 244 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html"); 245 246 // Now retrieve the frames text and test it only includes visible elements. 247 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 248 EXPECT_NE(std::string::npos, content.find(" visible paragraph")); 249 EXPECT_NE(std::string::npos, content.find(" visible iframe")); 250 EXPECT_EQ(std::string::npos, content.find(" invisible pararaph")); 251 EXPECT_EQ(std::string::npos, content.find(" invisible iframe")); 252 EXPECT_EQ(std::string::npos, content.find("iframe with zero size")); 253 } 254 255 TEST_F(WebFrameTest, FrameForEnteredContext) 256 { 257 registerMockedHttpURLLoad("iframes_test.html"); 258 registerMockedHttpURLLoad("visible_iframe.html"); 259 registerMockedHttpURLLoad("invisible_iframe.html"); 260 registerMockedHttpURLLoad("zero_sized_iframe.html"); 261 262 FrameTestHelpers::WebViewHelper webViewHelper; 263 webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html", true); 264 265 v8::HandleScope scope(v8::Isolate::GetCurrent()); 266 EXPECT_EQ(webViewHelper.webView()->mainFrame(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->mainWorldScriptContext())); 267 EXPECT_EQ(webViewHelper.webView()->mainFrame()->firstChild(), WebLocalFrame::frameForContext(webViewHelper.webView()->mainFrame()->firstChild()->mainWorldScriptContext())); 268 } 269 270 TEST_F(WebFrameTest, FormWithNullFrame) 271 { 272 registerMockedHttpURLLoad("form.html"); 273 274 FrameTestHelpers::WebViewHelper webViewHelper; 275 webViewHelper.initializeAndLoad(m_baseURL + "form.html"); 276 277 WebVector<WebFormElement> forms; 278 webViewHelper.webView()->mainFrame()->document().forms(forms); 279 webViewHelper.reset(); 280 281 EXPECT_EQ(forms.size(), 1U); 282 283 // This test passes if this doesn't crash. 284 WebSearchableFormData searchableDataForm(forms[0]); 285 } 286 287 TEST_F(WebFrameTest, ChromePageJavascript) 288 { 289 registerMockedChromeURLLoad("history.html"); 290 291 // Pass true to enable JavaScript. 292 FrameTestHelpers::WebViewHelper webViewHelper; 293 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true); 294 295 // Try to run JS against the chrome-style URL. 296 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))"); 297 298 // Required to see any updates in contentAsText. 299 webViewHelper.webView()->layout(); 300 301 // Now retrieve the frame's text and ensure it was modified by running javascript. 302 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 303 EXPECT_NE(std::string::npos, content.find("Clobbered")); 304 } 305 306 TEST_F(WebFrameTest, ChromePageNoJavascript) 307 { 308 registerMockedChromeURLLoad("history.html"); 309 310 /// Pass true to enable JavaScript. 311 FrameTestHelpers::WebViewHelper webViewHelper; 312 webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true); 313 314 // Try to run JS against the chrome-style URL after prohibiting it. 315 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome"); 316 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))"); 317 318 // Required to see any updates in contentAsText. 319 webViewHelper.webView()->layout(); 320 321 // Now retrieve the frame's text and ensure it wasn't modified by running javascript. 322 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 323 EXPECT_EQ(std::string::npos, content.find("Clobbered")); 324 } 325 326 TEST_F(WebFrameTest, LocationSetHostWithMissingPort) 327 { 328 std::string fileName = "print-location-href.html"; 329 registerMockedHttpURLLoad(fileName); 330 URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName)); 331 332 FrameTestHelpers::WebViewHelper webViewHelper; 333 334 /// Pass true to enable JavaScript. 335 webViewHelper.initializeAndLoad(m_baseURL + fileName, true); 336 337 // Setting host to "hostname:" should be treated as "hostname:0". 338 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.host = 'www.test.com:'; void 0;"); 339 340 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;"); 341 342 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 343 EXPECT_EQ("http://www.test.com:0/" + fileName, content); 344 } 345 346 TEST_F(WebFrameTest, LocationSetEmptyPort) 347 { 348 std::string fileName = "print-location-href.html"; 349 registerMockedHttpURLLoad(fileName); 350 URLTestHelpers::registerMockedURLLoad(toKURL("http://www.test.com:0/" + fileName), WebString::fromUTF8(fileName)); 351 352 FrameTestHelpers::WebViewHelper webViewHelper; 353 354 /// Pass true to enable JavaScript. 355 webViewHelper.initializeAndLoad(m_baseURL + fileName, true); 356 357 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:location.port = ''; void 0;"); 358 359 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), "javascript:document.body.textContent = location.href; void 0;"); 360 361 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 362 EXPECT_EQ("http://www.test.com:0/" + fileName, content); 363 } 364 365 class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient { 366 public: 367 CSSCallbackWebFrameClient() : m_updateCount(0) { } 368 virtual void didMatchCSS(WebLocalFrame*, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors) OVERRIDE; 369 370 std::map<WebLocalFrame*, std::set<std::string> > m_matchedSelectors; 371 int m_updateCount; 372 }; 373 374 void CSSCallbackWebFrameClient::didMatchCSS(WebLocalFrame* frame, const WebVector<WebString>& newlyMatchingSelectors, const WebVector<WebString>& stoppedMatchingSelectors) 375 { 376 ++m_updateCount; 377 std::set<std::string>& frameSelectors = m_matchedSelectors[frame]; 378 for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i) { 379 std::string selector = newlyMatchingSelectors[i].utf8(); 380 EXPECT_EQ(0U, frameSelectors.count(selector)) << selector; 381 frameSelectors.insert(selector); 382 } 383 for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i) { 384 std::string selector = stoppedMatchingSelectors[i].utf8(); 385 EXPECT_EQ(1U, frameSelectors.count(selector)) << selector; 386 frameSelectors.erase(selector); 387 } 388 } 389 390 class WebFrameCSSCallbackTest : public testing::Test { 391 protected: 392 WebFrameCSSCallbackTest() 393 { 394 395 m_frame = m_helper.initializeAndLoad("about:blank", true, &m_client)->mainFrame()->toWebLocalFrame(); 396 } 397 398 ~WebFrameCSSCallbackTest() 399 { 400 EXPECT_EQ(1U, m_client.m_matchedSelectors.size()); 401 } 402 403 WebDocument doc() const 404 { 405 return m_frame->document(); 406 } 407 408 int updateCount() const 409 { 410 return m_client.m_updateCount; 411 } 412 413 const std::set<std::string>& matchedSelectors() 414 { 415 return m_client.m_matchedSelectors[m_frame]; 416 } 417 418 void loadHTML(const std::string& html) 419 { 420 FrameTestHelpers::loadHTMLString(m_frame, html, toKURL("about:blank")); 421 } 422 423 void executeScript(const WebString& code) 424 { 425 m_frame->executeScript(WebScriptSource(code)); 426 m_frame->view()->layout(); 427 runPendingTasks(); 428 } 429 430 CSSCallbackWebFrameClient m_client; 431 FrameTestHelpers::WebViewHelper m_helper; 432 WebLocalFrame* m_frame; 433 }; 434 435 TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet) 436 { 437 loadHTML( 438 "<style>" 439 // This stylesheet checks that the internal property and value can't be 440 // set by a stylesheet, only WebDocument::watchCSSSelectors(). 441 "div.initial_on { -internal-callback: none; }" 442 "div.initial_off { -internal-callback: -internal-presence; }" 443 "</style>" 444 "<div class=\"initial_on\"></div>" 445 "<div class=\"initial_off\"></div>"); 446 447 std::vector<WebString> selectors; 448 selectors.push_back(WebString::fromUTF8("div.initial_on")); 449 m_frame->document().watchCSSSelectors(WebVector<WebString>(selectors)); 450 m_frame->view()->layout(); 451 runPendingTasks(); 452 EXPECT_EQ(1, updateCount()); 453 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_on")); 454 455 // Check that adding a watched selector calls back for already-present nodes. 456 selectors.push_back(WebString::fromUTF8("div.initial_off")); 457 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 458 m_frame->view()->layout(); 459 runPendingTasks(); 460 EXPECT_EQ(2, updateCount()); 461 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("div.initial_off", "div.initial_on")); 462 463 // Check that we can turn off callbacks for certain selectors. 464 doc().watchCSSSelectors(WebVector<WebString>()); 465 m_frame->view()->layout(); 466 runPendingTasks(); 467 EXPECT_EQ(3, updateCount()); 468 EXPECT_THAT(matchedSelectors(), testing::ElementsAre()); 469 } 470 471 TEST_F(WebFrameCSSCallbackTest, SharedRenderStyle) 472 { 473 // Check that adding an element calls back when it matches an existing rule. 474 std::vector<WebString> selectors; 475 selectors.push_back(WebString::fromUTF8("span")); 476 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 477 478 executeScript( 479 "i1 = document.createElement('span');" 480 "i1.id = 'first_span';" 481 "document.body.appendChild(i1)"); 482 EXPECT_EQ(1, updateCount()); 483 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 484 485 // Adding a second element that shares a RenderStyle shouldn't call back. 486 // We use <span>s to avoid default style rules that can set 487 // RenderStyle::unique(). 488 executeScript( 489 "i2 = document.createElement('span');" 490 "i2.id = 'second_span';" 491 "i1 = document.getElementById('first_span');" 492 "i1.parentNode.insertBefore(i2, i1.nextSibling);"); 493 EXPECT_EQ(1, updateCount()); 494 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 495 496 // Removing the first element shouldn't call back. 497 executeScript( 498 "i1 = document.getElementById('first_span');" 499 "i1.parentNode.removeChild(i1);"); 500 EXPECT_EQ(1, updateCount()); 501 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 502 503 // But removing the second element *should* call back. 504 executeScript( 505 "i2 = document.getElementById('second_span');" 506 "i2.parentNode.removeChild(i2);"); 507 EXPECT_EQ(2, updateCount()); 508 EXPECT_THAT(matchedSelectors(), testing::ElementsAre()); 509 } 510 511 TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange) 512 { 513 loadHTML("<span></span>"); 514 515 std::vector<WebString> selectors; 516 selectors.push_back(WebString::fromUTF8("span[attr=\"value\"]")); 517 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 518 runPendingTasks(); 519 520 EXPECT_EQ(0, updateCount()); 521 EXPECT_THAT(matchedSelectors(), testing::ElementsAre()); 522 523 executeScript( 524 "document.querySelector('span').setAttribute('attr', 'value');"); 525 EXPECT_EQ(1, updateCount()); 526 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span[attr=\"value\"]")); 527 } 528 529 TEST_F(WebFrameCSSCallbackTest, DisplayNone) 530 { 531 loadHTML("<div style='display:none'><span></span></div>"); 532 533 std::vector<WebString> selectors; 534 selectors.push_back(WebString::fromUTF8("span")); 535 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 536 runPendingTasks(); 537 538 EXPECT_EQ(0, updateCount()) << "Don't match elements in display:none trees."; 539 540 executeScript( 541 "d = document.querySelector('div');" 542 "d.style.display = 'block';"); 543 EXPECT_EQ(1, updateCount()) << "Match elements when they become displayed."; 544 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 545 546 executeScript( 547 "d = document.querySelector('div');" 548 "d.style.display = 'none';"); 549 EXPECT_EQ(2, updateCount()) << "Unmatch elements when they become undisplayed."; 550 EXPECT_THAT(matchedSelectors(), testing::ElementsAre()); 551 552 executeScript( 553 "s = document.querySelector('span');" 554 "s.style.display = 'none';"); 555 EXPECT_EQ(2, updateCount()) << "No effect from no-display'ing a span that's already undisplayed."; 556 557 executeScript( 558 "d = document.querySelector('div');" 559 "d.style.display = 'block';"); 560 EXPECT_EQ(2, updateCount()) << "No effect from displaying a div whose span is display:none."; 561 562 executeScript( 563 "s = document.querySelector('span');" 564 "s.style.display = 'inline';"); 565 EXPECT_EQ(3, updateCount()) << "Now the span is visible and produces a callback."; 566 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 567 568 executeScript( 569 "s = document.querySelector('span');" 570 "s.style.display = 'none';"); 571 EXPECT_EQ(4, updateCount()) << "Undisplaying the span directly should produce another callback."; 572 EXPECT_THAT(matchedSelectors(), testing::ElementsAre()); 573 } 574 575 TEST_F(WebFrameCSSCallbackTest, Reparenting) 576 { 577 loadHTML( 578 "<div id='d1'><span></span></div>" 579 "<div id='d2'></div>"); 580 581 std::vector<WebString> selectors; 582 selectors.push_back(WebString::fromUTF8("span")); 583 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 584 m_frame->view()->layout(); 585 runPendingTasks(); 586 587 EXPECT_EQ(1, updateCount()); 588 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 589 590 executeScript( 591 "s = document.querySelector('span');" 592 "d2 = document.getElementById('d2');" 593 "d2.appendChild(s);"); 594 EXPECT_EQ(1, updateCount()) << "Just moving an element that continues to match shouldn't send a spurious callback."; 595 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")); 596 } 597 598 TEST_F(WebFrameCSSCallbackTest, MultiSelector) 599 { 600 loadHTML("<span></span>"); 601 602 // Check that selector lists match as the whole list, not as each element 603 // independently. 604 std::vector<WebString> selectors; 605 selectors.push_back(WebString::fromUTF8("span")); 606 selectors.push_back(WebString::fromUTF8("span,p")); 607 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 608 m_frame->view()->layout(); 609 runPendingTasks(); 610 611 EXPECT_EQ(1, updateCount()); 612 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span", "span, p")); 613 } 614 615 TEST_F(WebFrameCSSCallbackTest, InvalidSelector) 616 { 617 loadHTML("<p><span></span></p>"); 618 619 // Build a list with one valid selector and one invalid. 620 std::vector<WebString> selectors; 621 selectors.push_back(WebString::fromUTF8("span")); 622 selectors.push_back(WebString::fromUTF8("[")); // Invalid. 623 selectors.push_back(WebString::fromUTF8("p span")); // Not compound. 624 doc().watchCSSSelectors(WebVector<WebString>(selectors)); 625 m_frame->view()->layout(); 626 runPendingTasks(); 627 628 EXPECT_EQ(1, updateCount()); 629 EXPECT_THAT(matchedSelectors(), testing::ElementsAre("span")) 630 << "An invalid selector shouldn't prevent other selectors from matching."; 631 } 632 633 TEST_F(WebFrameTest, DispatchMessageEventWithOriginCheck) 634 { 635 registerMockedHttpURLLoad("postmessage_test.html"); 636 637 // Pass true to enable JavaScript. 638 FrameTestHelpers::WebViewHelper webViewHelper; 639 webViewHelper.initializeAndLoad(m_baseURL + "postmessage_test.html", true); 640 641 // Send a message with the correct origin. 642 WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL))); 643 WebDOMEvent event = webViewHelper.webView()->mainFrame()->document().createEvent("MessageEvent"); 644 WebDOMMessageEvent message = event.to<WebDOMMessageEvent>(); 645 WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo")); 646 message.initMessageEvent("message", false, false, data, "http://origin.com", 0, ""); 647 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message); 648 649 // Send another message with incorrect origin. 650 WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(toKURL(m_chromeURL))); 651 webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message); 652 653 // Required to see any updates in contentAsText. 654 webViewHelper.webView()->layout(); 655 656 // Verify that only the first addition is in the body of the page. 657 std::string content = webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 658 EXPECT_NE(std::string::npos, content.find("Message 1.")); 659 EXPECT_EQ(std::string::npos, content.find("Message 2.")); 660 } 661 662 TEST_F(WebFrameTest, PostMessageThenDetach) 663 { 664 FrameTestHelpers::WebViewHelper webViewHelper; 665 webViewHelper.initializeAndLoad("about:blank"); 666 667 RefPtrWillBeRawPtr<LocalFrame> frame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame()); 668 NonThrowableExceptionState exceptionState; 669 frame->domWindow()->postMessage(SerializedScriptValue::create("message"), 0, "*", frame->domWindow(), exceptionState); 670 webViewHelper.reset(); 671 EXPECT_FALSE(exceptionState.hadException()); 672 673 // Success is not crashing. 674 runPendingTasks(); 675 } 676 677 class FixedLayoutTestWebViewClient : public FrameTestHelpers::TestWebViewClient { 678 public: 679 virtual WebScreenInfo screenInfo() OVERRIDE { return m_screenInfo; } 680 681 WebScreenInfo m_screenInfo; 682 }; 683 684 // Viewport settings need to be set before the page gets loaded 685 static void enableViewportSettings(WebSettings* settings) 686 { 687 settings->setViewportMetaEnabled(true); 688 settings->setViewportEnabled(true); 689 settings->setMainFrameResizesAreOrientationChanges(true); 690 settings->setShrinksViewportContentToFit(true); 691 } 692 693 // Helper function to check or set text autosizing multipliers on a document. 694 static bool checkOrSetTextAutosizingMultiplier(Document* document, float multiplier, bool setMultiplier) 695 { 696 bool multiplierCheckedOrSetAtLeastOnce = false; 697 for (RenderObject* renderer = document->renderView(); renderer; renderer = renderer->nextInPreOrder()) { 698 if (renderer->style()) { 699 if (setMultiplier) 700 renderer->style()->setTextAutosizingMultiplier(multiplier); 701 EXPECT_EQ(multiplier, renderer->style()->textAutosizingMultiplier()); 702 multiplierCheckedOrSetAtLeastOnce = true; 703 } 704 } 705 return multiplierCheckedOrSetAtLeastOnce; 706 707 } 708 709 static bool setTextAutosizingMultiplier(Document* document, float multiplier) 710 { 711 return checkOrSetTextAutosizingMultiplier(document, multiplier, true); 712 } 713 714 static bool checkTextAutosizingMultiplier(Document* document, float multiplier) 715 { 716 return checkOrSetTextAutosizingMultiplier(document, multiplier, false); 717 } 718 719 TEST_F(WebFrameTest, ChangeInFixedLayoutResetsTextAutosizingMultipliers) 720 { 721 UseMockScrollbarSettings mockScrollbarSettings; 722 registerMockedHttpURLLoad("fixed_layout.html"); 723 724 FixedLayoutTestWebViewClient client; 725 int viewportWidth = 640; 726 int viewportHeight = 480; 727 728 FrameTestHelpers::WebViewHelper webViewHelper; 729 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 730 731 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document(); 732 document->settings()->setTextAutosizingEnabled(true); 733 EXPECT_TRUE(document->settings()->textAutosizingEnabled()); 734 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight)); 735 webViewHelper.webViewImpl()->layout(); 736 737 EXPECT_TRUE(setTextAutosizingMultiplier(document, 2)); 738 739 ViewportDescription description = document->viewportDescription(); 740 // Choose a width that's not going match the viewport width of the loaded document. 741 description.minWidth = Length(100, blink::Fixed); 742 description.maxWidth = Length(100, blink::Fixed); 743 webViewHelper.webViewImpl()->updatePageDefinedViewportConstraints(description); 744 745 EXPECT_TRUE(checkTextAutosizingMultiplier(document, 1)); 746 } 747 748 TEST_F(WebFrameTest, SetFrameRectInvalidatesTextAutosizingMultipliers) 749 { 750 UseMockScrollbarSettings mockScrollbarSettings; 751 registerMockedHttpURLLoad("iframe_reload.html"); 752 registerMockedHttpURLLoad("visible_iframe.html"); 753 754 FixedLayoutTestWebViewClient client; 755 int viewportWidth = 640; 756 int viewportHeight = 480; 757 758 FrameTestHelpers::WebViewHelper webViewHelper; 759 webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true, 0, &client, enableViewportSettings); 760 761 LocalFrame* mainFrame = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame()); 762 Document* document = mainFrame->document(); 763 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 764 document->settings()->setTextAutosizingEnabled(true); 765 EXPECT_TRUE(document->settings()->textAutosizingEnabled()); 766 webViewHelper.webViewImpl()->resize(WebSize(viewportWidth, viewportHeight)); 767 webViewHelper.webViewImpl()->layout(); 768 769 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) { 770 if (!frame->isLocalFrame()) 771 continue; 772 EXPECT_TRUE(setTextAutosizingMultiplier(toLocalFrame(frame)->document(), 2)); 773 for (RenderObject* renderer = toLocalFrame(frame)->document()->renderView(); renderer; renderer = renderer->nextInPreOrder()) { 774 if (renderer->isText()) 775 EXPECT_FALSE(renderer->needsLayout()); 776 } 777 } 778 779 frameView->setFrameRect(IntRect(0, 0, 200, 200)); 780 for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) { 781 if (!frame->isLocalFrame()) 782 continue; 783 for (RenderObject* renderer = toLocalFrame(frame)->document()->renderView(); renderer; renderer = renderer->nextInPreOrder()) { 784 if (renderer->isText()) 785 EXPECT_TRUE(renderer->needsLayout()); 786 } 787 } 788 } 789 790 TEST_F(WebFrameTest, ZeroHeightPositiveWidthNotIgnored) 791 { 792 UseMockScrollbarSettings mockScrollbarSettings; 793 794 FixedLayoutTestWebViewClient client; 795 client.m_screenInfo.deviceScaleFactor = 1; 796 int viewportWidth = 1280; 797 int viewportHeight = 0; 798 799 FrameTestHelpers::WebViewHelper webViewHelper; 800 webViewHelper.initialize(true, 0, &client, enableViewportSettings); 801 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 802 803 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 804 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 805 } 806 807 TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag) 808 { 809 UseMockScrollbarSettings mockScrollbarSettings; 810 registerMockedHttpURLLoad("no_viewport_tag.html"); 811 812 int viewportWidth = 640; 813 int viewportHeight = 480; 814 815 FixedLayoutTestWebViewClient client; 816 client.m_screenInfo.deviceScaleFactor = 2; 817 818 FrameTestHelpers::WebViewHelper webViewHelper; 819 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings); 820 821 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 822 webViewHelper.webView()->layout(); 823 824 EXPECT_EQ(2, webViewHelper.webView()->deviceScaleFactor()); 825 826 // Device scale factor should be independent of page scale. 827 webViewHelper.webView()->setPageScaleFactorLimits(1, 2); 828 webViewHelper.webView()->setPageScaleFactor(0.5); 829 webViewHelper.webView()->layout(); 830 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor()); 831 832 // Force the layout to happen before leaving the test. 833 webViewHelper.webView()->mainFrame()->contentAsText(1024).utf8(); 834 } 835 836 TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumScale) 837 { 838 UseMockScrollbarSettings mockScrollbarSettings; 839 840 registerMockedHttpURLLoad("fixed_layout.html"); 841 842 FixedLayoutTestWebViewClient client; 843 client.m_screenInfo.deviceScaleFactor = 1; 844 int viewportWidth = 640; 845 int viewportHeight = 480; 846 847 // Make sure we initialize to minimum scale, even if the window size 848 // only becomes available after the load begins. 849 FrameTestHelpers::WebViewHelper webViewHelper; 850 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 851 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 852 853 int defaultFixedLayoutWidth = 980; 854 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth; 855 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 856 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor()); 857 858 // Assume the user has pinch zoomed to page scale factor 2. 859 float userPinchPageScaleFactor = 2; 860 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor); 861 webViewHelper.webView()->layout(); 862 863 // Make sure we don't reset to initial scale if the page continues to load. 864 webViewHelper.webViewImpl()->didCommitLoad(false, false); 865 webViewHelper.webViewImpl()->didChangeContentsSize(); 866 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 867 868 // Make sure we don't reset to initial scale if the viewport size changes. 869 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100)); 870 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 871 } 872 873 TEST_F(WebFrameTest, WideDocumentInitializeAtMinimumScale) 874 { 875 UseMockScrollbarSettings mockScrollbarSettings; 876 877 registerMockedHttpURLLoad("wide_document.html"); 878 879 FixedLayoutTestWebViewClient client; 880 client.m_screenInfo.deviceScaleFactor = 1; 881 int viewportWidth = 640; 882 int viewportHeight = 480; 883 884 // Make sure we initialize to minimum scale, even if the window size 885 // only becomes available after the load begins. 886 FrameTestHelpers::WebViewHelper webViewHelper; 887 webViewHelper.initializeAndLoad(m_baseURL + "wide_document.html", true, 0, &client, enableViewportSettings); 888 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 889 890 int wideDocumentWidth = 1500; 891 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth; 892 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 893 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor()); 894 895 // Assume the user has pinch zoomed to page scale factor 2. 896 float userPinchPageScaleFactor = 2; 897 webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor); 898 webViewHelper.webView()->layout(); 899 900 // Make sure we don't reset to initial scale if the page continues to load. 901 webViewHelper.webViewImpl()->didCommitLoad(false, false); 902 webViewHelper.webViewImpl()->didChangeContentsSize(); 903 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 904 905 // Make sure we don't reset to initial scale if the viewport size changes. 906 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight + 100)); 907 EXPECT_EQ(userPinchPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 908 } 909 910 TEST_F(WebFrameTest, DelayedViewportInitialScale) 911 { 912 UseMockScrollbarSettings mockScrollbarSettings; 913 registerMockedHttpURLLoad("viewport-auto-initial-scale.html"); 914 915 FixedLayoutTestWebViewClient client; 916 client.m_screenInfo.deviceScaleFactor = 1; 917 int viewportWidth = 640; 918 int viewportHeight = 480; 919 920 FrameTestHelpers::WebViewHelper webViewHelper; 921 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings); 922 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 923 924 EXPECT_EQ(0.25f, webViewHelper.webView()->pageScaleFactor()); 925 926 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document(); 927 ViewportDescription description = document->viewportDescription(); 928 description.zoom = 2; 929 document->setViewportDescription(description); 930 webViewHelper.webView()->layout(); 931 EXPECT_EQ(2, webViewHelper.webView()->pageScaleFactor()); 932 } 933 934 TEST_F(WebFrameTest, setLoadWithOverviewModeToFalse) 935 { 936 UseMockScrollbarSettings mockScrollbarSettings; 937 registerMockedHttpURLLoad("viewport-auto-initial-scale.html"); 938 939 FixedLayoutTestWebViewClient client; 940 client.m_screenInfo.deviceScaleFactor = 1; 941 int viewportWidth = 640; 942 int viewportHeight = 480; 943 944 FrameTestHelpers::WebViewHelper webViewHelper; 945 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings); 946 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 947 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 948 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 949 950 // The page must be displayed at 100% zoom. 951 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor()); 952 } 953 954 TEST_F(WebFrameTest, SetLoadWithOverviewModeToFalseAndNoWideViewport) 955 { 956 UseMockScrollbarSettings mockScrollbarSettings; 957 registerMockedHttpURLLoad("large-div.html"); 958 959 FixedLayoutTestWebViewClient client; 960 client.m_screenInfo.deviceScaleFactor = 1; 961 int viewportWidth = 640; 962 int viewportHeight = 480; 963 964 FrameTestHelpers::WebViewHelper webViewHelper; 965 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings); 966 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 967 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 968 webViewHelper.webView()->settings()->setUseWideViewport(false); 969 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 970 971 // The page must be displayed at 100% zoom, despite that it hosts a wide div element. 972 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor()); 973 } 974 975 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidth) 976 { 977 UseMockScrollbarSettings mockScrollbarSettings; 978 registerMockedHttpURLLoad("viewport-auto-initial-scale.html"); 979 980 FixedLayoutTestWebViewClient client; 981 client.m_screenInfo.deviceScaleFactor = 1; 982 int viewportWidth = 640; 983 int viewportHeight = 480; 984 985 FrameTestHelpers::WebViewHelper webViewHelper; 986 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings); 987 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 988 webViewHelper.webView()->settings()->setUseWideViewport(false); 989 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 990 991 // The page sets viewport width to 3000, but with UseWideViewport == false is must be ignored. 992 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 993 EXPECT_EQ(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height()); 994 } 995 996 TEST_F(WebFrameTest, NoWideViewportIgnoresPageViewportWidthButAccountsScale) 997 { 998 UseMockScrollbarSettings mockScrollbarSettings; 999 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html"); 1000 1001 FixedLayoutTestWebViewClient client; 1002 client.m_screenInfo.deviceScaleFactor = 1; 1003 int viewportWidth = 640; 1004 int viewportHeight = 480; 1005 1006 FrameTestHelpers::WebViewHelper webViewHelper; 1007 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings); 1008 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1009 webViewHelper.webView()->settings()->setUseWideViewport(false); 1010 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1011 1012 // The page sets viewport width to 3000, but with UseWideViewport == false it must be ignored. 1013 // While the initial scale specified by the page must be accounted. 1014 EXPECT_EQ(viewportWidth / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1015 EXPECT_EQ(viewportHeight / 2, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height()); 1016 } 1017 1018 TEST_F(WebFrameTest, WideViewportSetsTo980WithoutViewportTag) 1019 { 1020 UseMockScrollbarSettings mockScrollbarSettings; 1021 registerMockedHttpURLLoad("no_viewport_tag.html"); 1022 1023 FixedLayoutTestWebViewClient client; 1024 client.m_screenInfo.deviceScaleFactor = 1; 1025 int viewportWidth = 640; 1026 int viewportHeight = 480; 1027 1028 FrameTestHelpers::WebViewHelper webViewHelper; 1029 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings); 1030 applyViewportStyleOverride(&webViewHelper); 1031 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1032 webViewHelper.webView()->settings()->setUseWideViewport(true); 1033 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1034 1035 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1036 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height()); 1037 } 1038 1039 TEST_F(WebFrameTest, NoWideViewportAndHeightInMeta) 1040 { 1041 UseMockScrollbarSettings mockScrollbarSettings; 1042 registerMockedHttpURLLoad("viewport-height-1000.html"); 1043 1044 FixedLayoutTestWebViewClient client; 1045 client.m_screenInfo.deviceScaleFactor = 1; 1046 int viewportWidth = 640; 1047 int viewportHeight = 480; 1048 1049 FrameTestHelpers::WebViewHelper webViewHelper; 1050 webViewHelper.initializeAndLoad(m_baseURL + "viewport-height-1000.html", true, 0, &client, enableViewportSettings); 1051 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1052 webViewHelper.webView()->settings()->setUseWideViewport(false); 1053 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1054 1055 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1056 } 1057 1058 TEST_F(WebFrameTest, WideViewportSetsTo980WithAutoWidth) 1059 { 1060 UseMockScrollbarSettings mockScrollbarSettings; 1061 registerMockedHttpURLLoad("viewport-2x-initial-scale.html"); 1062 1063 FixedLayoutTestWebViewClient client; 1064 client.m_screenInfo.deviceScaleFactor = 1; 1065 int viewportWidth = 640; 1066 int viewportHeight = 480; 1067 1068 FrameTestHelpers::WebViewHelper webViewHelper; 1069 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale.html", true, 0, &client, enableViewportSettings); 1070 applyViewportStyleOverride(&webViewHelper); 1071 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1072 webViewHelper.webView()->settings()->setUseWideViewport(true); 1073 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1074 1075 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1076 EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().height()); 1077 } 1078 1079 TEST_F(WebFrameTest, PageViewportInitialScaleOverridesLoadWithOverviewMode) 1080 { 1081 UseMockScrollbarSettings mockScrollbarSettings; 1082 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html"); 1083 1084 FixedLayoutTestWebViewClient client; 1085 client.m_screenInfo.deviceScaleFactor = 1; 1086 int viewportWidth = 640; 1087 int viewportHeight = 480; 1088 1089 FrameTestHelpers::WebViewHelper webViewHelper; 1090 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings); 1091 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 1092 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1093 1094 // The page must be displayed at 200% zoom, as specified in its viewport meta tag. 1095 EXPECT_EQ(2.0f, webViewHelper.webView()->pageScaleFactor()); 1096 } 1097 1098 TEST_F(WebFrameTest, setInitialPageScaleFactorPermanently) 1099 { 1100 UseMockScrollbarSettings mockScrollbarSettings; 1101 1102 registerMockedHttpURLLoad("fixed_layout.html"); 1103 1104 FixedLayoutTestWebViewClient client; 1105 client.m_screenInfo.deviceScaleFactor = 1; 1106 float enforcedPageScaleFactor = 2.0f; 1107 1108 FrameTestHelpers::WebViewHelper webViewHelper; 1109 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1110 applyViewportStyleOverride(&webViewHelper); 1111 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1112 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 1113 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1114 webViewHelper.webView()->layout(); 1115 1116 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1117 1118 int viewportWidth = 640; 1119 int viewportHeight = 480; 1120 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1121 webViewHelper.webView()->layout(); 1122 1123 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1124 1125 webViewHelper.webView()->setInitialPageScaleOverride(-1); 1126 webViewHelper.webView()->layout(); 1127 EXPECT_EQ(1.0, webViewHelper.webView()->pageScaleFactor()); 1128 } 1129 1130 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode) 1131 { 1132 UseMockScrollbarSettings mockScrollbarSettings; 1133 registerMockedHttpURLLoad("viewport-auto-initial-scale.html"); 1134 1135 FixedLayoutTestWebViewClient client; 1136 client.m_screenInfo.deviceScaleFactor = 1; 1137 int viewportWidth = 640; 1138 int viewportHeight = 480; 1139 float enforcedPageScaleFactor = 0.5f; 1140 1141 FrameTestHelpers::WebViewHelper webViewHelper; 1142 webViewHelper.initializeAndLoad(m_baseURL + "viewport-auto-initial-scale.html", true, 0, &client, enableViewportSettings); 1143 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 1144 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1145 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1146 1147 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1148 } 1149 1150 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorOverridesPageViewportInitialScale) 1151 { 1152 UseMockScrollbarSettings mockScrollbarSettings; 1153 registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html"); 1154 1155 FixedLayoutTestWebViewClient client; 1156 client.m_screenInfo.deviceScaleFactor = 1; 1157 int viewportWidth = 640; 1158 int viewportHeight = 480; 1159 float enforcedPageScaleFactor = 0.5f; 1160 1161 FrameTestHelpers::WebViewHelper webViewHelper; 1162 webViewHelper.initializeAndLoad(m_baseURL + "viewport-wide-2x-initial-scale.html", true, 0, &client, enableViewportSettings); 1163 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1164 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1165 1166 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1167 } 1168 1169 TEST_F(WebFrameTest, SmallPermanentInitialPageScaleFactorIsClobbered) 1170 { 1171 UseMockScrollbarSettings mockScrollbarSettings; 1172 const char* pages[] = { 1173 // These pages trigger the clobbering condition. There must be a matching item in "pageScaleFactors" array. 1174 "viewport-device-0.5x-initial-scale.html", 1175 "viewport-initial-scale-1.html", 1176 // These ones do not. 1177 "viewport-auto-initial-scale.html", 1178 "viewport-target-densitydpi-device-and-fixed-width.html" 1179 }; 1180 float pageScaleFactors[] = { 0.5f, 1.0f }; 1181 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i) 1182 registerMockedHttpURLLoad(pages[i]); 1183 1184 FixedLayoutTestWebViewClient client; 1185 client.m_screenInfo.deviceScaleFactor = 1; 1186 int viewportWidth = 400; 1187 int viewportHeight = 300; 1188 float enforcedPageScaleFactor = 0.75f; 1189 1190 for (size_t i = 0; i < ARRAY_SIZE(pages); ++i) { 1191 for (int quirkEnabled = 0; quirkEnabled <= 1; ++quirkEnabled) { 1192 FrameTestHelpers::WebViewHelper webViewHelper; 1193 webViewHelper.initializeAndLoad(m_baseURL + pages[i], true, 0, &client, enableViewportSettings); 1194 applyViewportStyleOverride(&webViewHelper); 1195 webViewHelper.webView()->settings()->setClobberUserAgentInitialScaleQuirk(quirkEnabled); 1196 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1197 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1198 1199 float expectedPageScaleFactor = quirkEnabled && i < ARRAY_SIZE(pageScaleFactors) ? pageScaleFactors[i] : enforcedPageScaleFactor; 1200 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1201 } 1202 } 1203 } 1204 1205 TEST_F(WebFrameTest, PermanentInitialPageScaleFactorAffectsLayoutWidth) 1206 { 1207 UseMockScrollbarSettings mockScrollbarSettings; 1208 1209 FixedLayoutTestWebViewClient client; 1210 client.m_screenInfo.deviceScaleFactor = 1; 1211 int viewportWidth = 640; 1212 int viewportHeight = 480; 1213 float enforcedPageScaleFactor = 0.5; 1214 1215 FrameTestHelpers::WebViewHelper webViewHelper; 1216 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings); 1217 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1218 webViewHelper.webView()->settings()->setUseWideViewport(false); 1219 webViewHelper.webView()->settings()->setLoadWithOverviewMode(false); 1220 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1221 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1222 1223 EXPECT_EQ(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1224 EXPECT_EQ(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1225 } 1226 1227 TEST_F(WebFrameTest, SetForceZeroLayoutHeight) 1228 { 1229 UseMockScrollbarSettings mockScrollbarSettings; 1230 registerMockedHttpURLLoad("200-by-300.html"); 1231 1232 FixedLayoutTestWebViewClient client; 1233 client.m_screenInfo.deviceScaleFactor = 1; 1234 int viewportWidth = 640; 1235 int viewportHeight = 480; 1236 1237 FrameTestHelpers::WebViewHelper webViewHelper; 1238 1239 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings); 1240 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1241 webViewHelper.webView()->layout(); 1242 1243 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1244 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true); 1245 EXPECT_TRUE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout()); 1246 1247 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1248 1249 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight * 2)); 1250 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout()); 1251 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1252 1253 webViewHelper.webView()->resize(WebSize(viewportWidth * 2, viewportHeight)); 1254 webViewHelper.webView()->layout(); 1255 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1256 1257 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(false); 1258 EXPECT_LE(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1259 } 1260 1261 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWorksAcrossNavigations) 1262 { 1263 UseMockScrollbarSettings mockScrollbarSettings; 1264 registerMockedHttpURLLoad("200-by-300.html"); 1265 registerMockedHttpURLLoad("large-div.html"); 1266 1267 FixedLayoutTestWebViewClient client; 1268 client.m_screenInfo.deviceScaleFactor = 1; 1269 int viewportWidth = 640; 1270 int viewportHeight = 480; 1271 1272 FrameTestHelpers::WebViewHelper webViewHelper; 1273 1274 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings); 1275 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true); 1276 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1277 webViewHelper.webView()->layout(); 1278 1279 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html"); 1280 webViewHelper.webView()->layout(); 1281 1282 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1283 } 1284 1285 TEST_F(WebFrameTest, SetForceZeroLayoutHeightWithWideViewportQuirk) 1286 { 1287 UseMockScrollbarSettings mockScrollbarSettings; 1288 registerMockedHttpURLLoad("200-by-300.html"); 1289 1290 FixedLayoutTestWebViewClient client; 1291 client.m_screenInfo.deviceScaleFactor = 1; 1292 int viewportWidth = 640; 1293 int viewportHeight = 480; 1294 1295 FrameTestHelpers::WebViewHelper webViewHelper; 1296 1297 webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, 0, &client, enableViewportSettings); 1298 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1299 webViewHelper.webView()->settings()->setUseWideViewport(true); 1300 webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true); 1301 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1302 webViewHelper.webView()->layout(); 1303 1304 EXPECT_EQ(0, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1305 } 1306 1307 TEST_F(WebFrameTest, WideViewportAndWideContentWithInitialScale) 1308 { 1309 UseMockScrollbarSettings mockScrollbarSettings; 1310 registerMockedHttpURLLoad("wide_document_width_viewport.html"); 1311 1312 FixedLayoutTestWebViewClient client; 1313 client.m_screenInfo.deviceScaleFactor = 1; 1314 int viewportWidth = 600; 1315 int viewportHeight = 800; 1316 1317 FrameTestHelpers::WebViewHelper webViewHelper; 1318 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings); 1319 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1320 webViewHelper.webView()->settings()->setUseWideViewport(true); 1321 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true); 1322 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1323 1324 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "wide_document_width_viewport.html"); 1325 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1326 1327 int wideDocumentWidth = 800; 1328 float minimumPageScaleFactor = viewportWidth / (float) wideDocumentWidth; 1329 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1330 EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->minimumPageScaleFactor()); 1331 } 1332 1333 TEST_F(WebFrameTest, WideViewportQuirkClobbersHeight) 1334 { 1335 UseMockScrollbarSettings mockScrollbarSettings; 1336 registerMockedHttpURLLoad("viewport-height-1000.html"); 1337 1338 FixedLayoutTestWebViewClient client; 1339 client.m_screenInfo.deviceScaleFactor = 1; 1340 int viewportWidth = 600; 1341 int viewportHeight = 800; 1342 1343 FrameTestHelpers::WebViewHelper webViewHelper; 1344 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings); 1345 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1346 webViewHelper.webView()->settings()->setUseWideViewport(false); 1347 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true); 1348 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1349 1350 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-height-1000.html"); 1351 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1352 1353 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1354 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor()); 1355 } 1356 1357 TEST_F(WebFrameTest, LayoutSize320Quirk) 1358 { 1359 UseMockScrollbarSettings mockScrollbarSettings; 1360 registerMockedHttpURLLoad("viewport/viewport-30.html"); 1361 1362 FixedLayoutTestWebViewClient client; 1363 client.m_screenInfo.deviceScaleFactor = 1; 1364 int viewportWidth = 600; 1365 int viewportHeight = 800; 1366 1367 FrameTestHelpers::WebViewHelper webViewHelper; 1368 webViewHelper.initializeAndLoad("about:blank", true, 0, &client, enableViewportSettings); 1369 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1370 webViewHelper.webView()->settings()->setUseWideViewport(true); 1371 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true); 1372 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1373 1374 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport/viewport-30.html"); 1375 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1376 1377 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1378 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1379 EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor()); 1380 1381 // The magic number to snap to device-width is 320, so test that 321 is 1382 // respected. 1383 Document* document = toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->document(); 1384 ViewportDescription description = document->viewportDescription(); 1385 description.minWidth = Length(321, blink::Fixed); 1386 description.maxWidth = Length(321, blink::Fixed); 1387 document->setViewportDescription(description); 1388 webViewHelper.webView()->layout(); 1389 EXPECT_EQ(321, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1390 1391 description.minWidth = Length(320, blink::Fixed); 1392 description.maxWidth = Length(320, blink::Fixed); 1393 document->setViewportDescription(description); 1394 webViewHelper.webView()->layout(); 1395 EXPECT_EQ(600, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1396 1397 description = document->viewportDescription(); 1398 description.maxHeight = Length(1000, blink::Fixed); 1399 document->setViewportDescription(description); 1400 webViewHelper.webView()->layout(); 1401 EXPECT_EQ(1000, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1402 1403 description.maxHeight = Length(320, blink::Fixed); 1404 document->setViewportDescription(description); 1405 webViewHelper.webView()->layout(); 1406 EXPECT_EQ(800, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height()); 1407 } 1408 1409 TEST_F(WebFrameTest, ZeroValuesQuirk) 1410 { 1411 UseMockScrollbarSettings mockScrollbarSettings; 1412 registerMockedHttpURLLoad("viewport-zero-values.html"); 1413 1414 FixedLayoutTestWebViewClient client; 1415 client.m_screenInfo.deviceScaleFactor = 1; 1416 int viewportWidth = 640; 1417 int viewportHeight = 480; 1418 1419 FrameTestHelpers::WebViewHelper webViewHelper; 1420 webViewHelper.initialize(true, 0, &client, enableViewportSettings); 1421 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true); 1422 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1423 webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true); 1424 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-zero-values.html"); 1425 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1426 1427 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1428 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor()); 1429 1430 webViewHelper.webView()->settings()->setUseWideViewport(true); 1431 webViewHelper.webView()->layout(); 1432 EXPECT_EQ(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1433 EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor()); 1434 } 1435 1436 TEST_F(WebFrameTest, OverflowHiddenDisablesScrolling) 1437 { 1438 registerMockedHttpURLLoad("body-overflow-hidden.html"); 1439 1440 FixedLayoutTestWebViewClient client; 1441 client.m_screenInfo.deviceScaleFactor = 1; 1442 int viewportWidth = 640; 1443 int viewportHeight = 480; 1444 1445 FrameTestHelpers::WebViewHelper webViewHelper; 1446 webViewHelper.initialize(true, 0, &client); 1447 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html"); 1448 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1449 1450 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 1451 EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar)); 1452 } 1453 1454 TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk) 1455 { 1456 registerMockedHttpURLLoad("body-overflow-hidden.html"); 1457 1458 FixedLayoutTestWebViewClient client; 1459 client.m_screenInfo.deviceScaleFactor = 1; 1460 int viewportWidth = 640; 1461 int viewportHeight = 480; 1462 1463 FrameTestHelpers::WebViewHelper webViewHelper; 1464 webViewHelper.initialize(true, 0, &client); 1465 webViewHelper.webView()->settings()->setIgnoreMainFrameOverflowHiddenQuirk(true); 1466 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "body-overflow-hidden.html"); 1467 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1468 1469 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 1470 EXPECT_TRUE(view->userInputScrollable(VerticalScrollbar)); 1471 } 1472 1473 TEST_F(WebFrameTest, NonZeroValuesNoQuirk) 1474 { 1475 UseMockScrollbarSettings mockScrollbarSettings; 1476 registerMockedHttpURLLoad("viewport-nonzero-values.html"); 1477 1478 FixedLayoutTestWebViewClient client; 1479 client.m_screenInfo.deviceScaleFactor = 1; 1480 int viewportWidth = 640; 1481 int viewportHeight = 480; 1482 float expectedPageScaleFactor = 0.5f; 1483 1484 FrameTestHelpers::WebViewHelper webViewHelper; 1485 webViewHelper.initialize(true, 0, &client, enableViewportSettings); 1486 webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true); 1487 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1488 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "viewport-nonzero-values.html"); 1489 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1490 1491 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1492 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1493 1494 webViewHelper.webView()->settings()->setUseWideViewport(true); 1495 webViewHelper.webView()->layout(); 1496 EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width()); 1497 EXPECT_EQ(expectedPageScaleFactor, webViewHelper.webView()->pageScaleFactor()); 1498 } 1499 1500 TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout) 1501 { 1502 UseMockScrollbarSettings mockScrollbarSettings; 1503 registerMockedHttpURLLoad("fixed_layout.html"); 1504 1505 FixedLayoutTestWebViewClient client; 1506 client.m_screenInfo.deviceScaleFactor = 1; 1507 // Small viewport to ensure there are always scrollbars. 1508 int viewportWidth = 64; 1509 int viewportHeight = 48; 1510 1511 FrameTestHelpers::WebViewHelper webViewHelper; 1512 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1513 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1514 webViewHelper.webView()->layout(); 1515 1516 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount(); 1517 webViewHelper.webViewImpl()->setPageScaleFactor(3); 1518 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout()); 1519 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount()); 1520 } 1521 1522 TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) 1523 { 1524 UseMockScrollbarSettings mockScrollbarSettings; 1525 1526 registerMockedHttpURLLoad("fixed_layout.html"); 1527 1528 FixedLayoutTestWebViewClient client; 1529 client.m_screenInfo.deviceScaleFactor = 1; 1530 int viewportWidth = 640; 1531 int viewportHeight = 480; 1532 1533 FrameTestHelpers::WebViewHelper webViewHelper; 1534 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1535 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1536 webViewHelper.webView()->layout(); 1537 1538 int prevLayoutCount = webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount(); 1539 webViewHelper.webViewImpl()->setPageScaleFactor(30); 1540 EXPECT_FALSE(webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->needsLayout()); 1541 EXPECT_EQ(prevLayoutCount, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutCount()); 1542 1543 } 1544 1545 TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem) 1546 { 1547 UseMockScrollbarSettings mockScrollbarSettings; 1548 registerMockedHttpURLLoad("fixed_layout.html"); 1549 1550 FixedLayoutTestWebViewClient client; 1551 client.m_screenInfo.deviceScaleFactor = 1; 1552 int viewportWidth = 640; 1553 int viewportHeight = 480; 1554 1555 FrameTestHelpers::WebViewHelper webViewHelper; 1556 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1557 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1558 webViewHelper.webView()->layout(); 1559 1560 webViewHelper.webView()->setPageScaleFactor(3); 1561 EXPECT_EQ(3, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor()); 1562 } 1563 1564 TEST_F(WebFrameTest, initialScaleWrittenToHistoryItem) 1565 { 1566 UseMockScrollbarSettings mockScrollbarSettings; 1567 registerMockedHttpURLLoad("fixed_layout.html"); 1568 1569 FixedLayoutTestWebViewClient client; 1570 client.m_screenInfo.deviceScaleFactor = 1; 1571 int viewportWidth = 640; 1572 int viewportHeight = 480; 1573 1574 FrameTestHelpers::WebViewHelper webViewHelper; 1575 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1576 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1577 webViewHelper.webView()->layout(); 1578 1579 int defaultFixedLayoutWidth = 980; 1580 float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth; 1581 EXPECT_EQ(minimumPageScaleFactor, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->loader().currentItem()->pageScaleFactor()); 1582 } 1583 1584 TEST_F(WebFrameTest, pageScaleFactorShrinksViewport) 1585 { 1586 UseMockScrollbarSettings mockScrollbarSettings; 1587 registerMockedHttpURLLoad("large-div.html"); 1588 1589 FixedLayoutTestWebViewClient client; 1590 client.m_screenInfo.deviceScaleFactor = 1; 1591 // Small viewport to ensure there are always scrollbars. 1592 int viewportWidth = 64; 1593 int viewportHeight = 48; 1594 1595 FrameTestHelpers::WebViewHelper webViewHelper; 1596 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings); 1597 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1598 webViewHelper.webView()->layout(); 1599 1600 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 1601 int viewportWidthMinusScrollbar = viewportWidth - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15); 1602 int viewportHeightMinusScrollbar = viewportHeight - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15); 1603 1604 webViewHelper.webView()->setPageScaleFactor(2); 1605 1606 IntSize unscaledSize = view->unscaledVisibleContentSize(IncludeScrollbars); 1607 EXPECT_EQ(viewportWidth, unscaledSize.width()); 1608 EXPECT_EQ(viewportHeight, unscaledSize.height()); 1609 1610 IntSize unscaledSizeMinusScrollbar = view->unscaledVisibleContentSize(ExcludeScrollbars); 1611 EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width()); 1612 EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height()); 1613 1614 IntSize scaledSize = view->visibleContentRect().size(); 1615 EXPECT_EQ(ceil(viewportWidthMinusScrollbar / 2.0), scaledSize.width()); 1616 EXPECT_EQ(ceil(viewportHeightMinusScrollbar / 2.0), scaledSize.height()); 1617 } 1618 1619 TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform) 1620 { 1621 UseMockScrollbarSettings mockScrollbarSettings; 1622 registerMockedHttpURLLoad("fixed_layout.html"); 1623 1624 FixedLayoutTestWebViewClient client; 1625 client.m_screenInfo.deviceScaleFactor = 1; 1626 int viewportWidth = 640; 1627 int viewportHeight = 480; 1628 1629 FrameTestHelpers::WebViewHelper webViewHelper; 1630 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 1631 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1632 webViewHelper.webView()->layout(); 1633 1634 webViewHelper.webView()->setPageScaleFactor(2); 1635 1636 EXPECT_EQ(980, toLocalFrame(webViewHelper.webViewImpl()->page()->mainFrame())->contentRenderer()->unscaledDocumentRect().width()); 1637 EXPECT_EQ(980, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->contentsSize().width()); 1638 } 1639 1640 TEST_F(WebFrameTest, targetDensityDpiHigh) 1641 { 1642 UseMockScrollbarSettings mockScrollbarSettings; 1643 registerMockedHttpURLLoad("viewport-target-densitydpi-high.html"); 1644 1645 FixedLayoutTestWebViewClient client; 1646 // high-dpi = 240 1647 float targetDpi = 240.0f; 1648 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f }; 1649 int viewportWidth = 640; 1650 int viewportHeight = 480; 1651 1652 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) { 1653 float deviceScaleFactor = deviceScaleFactors[i]; 1654 float deviceDpi = deviceScaleFactor * 160.0f; 1655 client.m_screenInfo.deviceScaleFactor = deviceScaleFactor; 1656 1657 FrameTestHelpers::WebViewHelper webViewHelper; 1658 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-high.html", true, 0, &client, enableViewportSettings); 1659 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1660 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1661 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1662 1663 // We need to account for the fact that logical pixels are unconditionally multiplied by deviceScaleFactor to produce 1664 // physical pixels. 1665 float densityDpiScaleRatio = deviceScaleFactor * targetDpi / deviceDpi; 1666 EXPECT_NEAR(viewportWidth * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1667 EXPECT_NEAR(viewportHeight * densityDpiScaleRatio, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1668 EXPECT_NEAR(1.0f / densityDpiScaleRatio, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1669 } 1670 } 1671 1672 TEST_F(WebFrameTest, targetDensityDpiDevice) 1673 { 1674 UseMockScrollbarSettings mockScrollbarSettings; 1675 registerMockedHttpURLLoad("viewport-target-densitydpi-device.html"); 1676 1677 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f }; 1678 1679 FixedLayoutTestWebViewClient client; 1680 int viewportWidth = 640; 1681 int viewportHeight = 480; 1682 1683 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) { 1684 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i]; 1685 1686 FrameTestHelpers::WebViewHelper webViewHelper; 1687 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device.html", true, 0, &client, enableViewportSettings); 1688 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1689 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1690 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1691 1692 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1693 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1694 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1695 } 1696 } 1697 1698 TEST_F(WebFrameTest, targetDensityDpiDeviceAndFixedWidth) 1699 { 1700 UseMockScrollbarSettings mockScrollbarSettings; 1701 registerMockedHttpURLLoad("viewport-target-densitydpi-device-and-fixed-width.html"); 1702 1703 float deviceScaleFactors[] = { 1.0f, 4.0f / 3.0f, 2.0f }; 1704 1705 FixedLayoutTestWebViewClient client; 1706 int viewportWidth = 640; 1707 int viewportHeight = 480; 1708 1709 for (size_t i = 0; i < ARRAY_SIZE(deviceScaleFactors); ++i) { 1710 client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i]; 1711 1712 FrameTestHelpers::WebViewHelper webViewHelper; 1713 webViewHelper.initializeAndLoad(m_baseURL + "viewport-target-densitydpi-device-and-fixed-width.html", true, 0, &client, enableViewportSettings); 1714 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1715 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1716 webViewHelper.webView()->settings()->setUseWideViewport(true); 1717 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1718 1719 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1720 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1721 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1722 } 1723 } 1724 1725 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOne) 1726 { 1727 UseMockScrollbarSettings mockScrollbarSettings; 1728 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html"); 1729 1730 FixedLayoutTestWebViewClient client; 1731 client.m_screenInfo.deviceScaleFactor = 1.33f; 1732 int viewportWidth = 640; 1733 int viewportHeight = 480; 1734 1735 FrameTestHelpers::WebViewHelper webViewHelper; 1736 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1.html", true, 0, &client, enableViewportSettings); 1737 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1738 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1739 webViewHelper.webView()->settings()->setUseWideViewport(false); 1740 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1741 webViewHelper.webView()->layout(); 1742 1743 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1744 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1745 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1746 } 1747 1748 TEST_F(WebFrameTest, NoWideViewportAndScaleLessThanOneWithDeviceWidth) 1749 { 1750 UseMockScrollbarSettings mockScrollbarSettings; 1751 registerMockedHttpURLLoad("viewport-initial-scale-less-than-1-device-width.html"); 1752 1753 FixedLayoutTestWebViewClient client; 1754 client.m_screenInfo.deviceScaleFactor = 1.33f; 1755 int viewportWidth = 640; 1756 int viewportHeight = 480; 1757 1758 FrameTestHelpers::WebViewHelper webViewHelper; 1759 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true, 0, &client, enableViewportSettings); 1760 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1761 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1762 webViewHelper.webView()->settings()->setUseWideViewport(false); 1763 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1764 webViewHelper.webView()->layout(); 1765 1766 const float pageZoom = 0.25f; 1767 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1768 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1769 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1770 } 1771 1772 TEST_F(WebFrameTest, NoWideViewportAndNoViewportWithInitialPageScaleOverride) 1773 { 1774 UseMockScrollbarSettings mockScrollbarSettings; 1775 registerMockedHttpURLLoad("large-div.html"); 1776 1777 FixedLayoutTestWebViewClient client; 1778 int viewportWidth = 640; 1779 int viewportHeight = 480; 1780 float enforcedPageScaleFactor = 5.0f; 1781 1782 FrameTestHelpers::WebViewHelper webViewHelper; 1783 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client, enableViewportSettings); 1784 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1785 webViewHelper.webView()->settings()->setUseWideViewport(false); 1786 webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor); 1787 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1788 webViewHelper.webView()->layout(); 1789 1790 EXPECT_NEAR(viewportWidth / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1791 EXPECT_NEAR(viewportHeight / enforcedPageScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1792 EXPECT_NEAR(enforcedPageScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1793 } 1794 1795 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScale) 1796 { 1797 UseMockScrollbarSettings mockScrollbarSettings; 1798 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html"); 1799 1800 FixedLayoutTestWebViewClient client; 1801 int viewportWidth = 640; 1802 int viewportHeight = 480; 1803 1804 FrameTestHelpers::WebViewHelper webViewHelper; 1805 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings); 1806 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true); 1807 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1808 webViewHelper.webView()->layout(); 1809 1810 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1811 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1812 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1813 } 1814 1815 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForNonWideViewport) 1816 { 1817 UseMockScrollbarSettings mockScrollbarSettings; 1818 registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html"); 1819 1820 FixedLayoutTestWebViewClient client; 1821 client.m_screenInfo.deviceScaleFactor = 1.33f; 1822 int viewportWidth = 640; 1823 int viewportHeight = 480; 1824 1825 FrameTestHelpers::WebViewHelper webViewHelper; 1826 webViewHelper.initializeAndLoad(m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true, 0, &client, enableViewportSettings); 1827 webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(true); 1828 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true); 1829 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1830 webViewHelper.webView()->settings()->setUseWideViewport(false); 1831 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1832 webViewHelper.webView()->layout(); 1833 1834 EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1835 EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1836 EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1837 } 1838 1839 TEST_F(WebFrameTest, NoUserScalableQuirkIgnoresViewportScaleForWideViewport) 1840 { 1841 UseMockScrollbarSettings mockScrollbarSettings; 1842 registerMockedHttpURLLoad("viewport-2x-initial-scale-non-user-scalable.html"); 1843 1844 FixedLayoutTestWebViewClient client; 1845 int viewportWidth = 640; 1846 int viewportHeight = 480; 1847 1848 FrameTestHelpers::WebViewHelper webViewHelper; 1849 webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale-non-user-scalable.html", true, 0, &client, enableViewportSettings); 1850 webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(true); 1851 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1852 webViewHelper.webView()->settings()->setUseWideViewport(true); 1853 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1854 1855 EXPECT_NEAR(viewportWidth, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().width(), 1.0f); 1856 EXPECT_NEAR(viewportHeight, webViewHelper.webViewImpl()->mainFrameImpl()->frameView()->layoutSize().height(), 1.0f); 1857 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1858 } 1859 1860 TEST_F(WebFrameTest, DesktopPageCanBeZoomedInWhenWideViewportIsTurnedOff) 1861 { 1862 UseMockScrollbarSettings mockScrollbarSettings; 1863 registerMockedHttpURLLoad("no_viewport_tag.html"); 1864 1865 FixedLayoutTestWebViewClient client; 1866 int viewportWidth = 640; 1867 int viewportHeight = 480; 1868 1869 FrameTestHelpers::WebViewHelper webViewHelper; 1870 webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client, enableViewportSettings); 1871 webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true); 1872 webViewHelper.webView()->settings()->setUseWideViewport(false); 1873 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 1874 1875 EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f); 1876 EXPECT_NEAR(1.0f, webViewHelper.webView()->minimumPageScaleFactor(), 0.01f); 1877 EXPECT_NEAR(5.0f, webViewHelper.webView()->maximumPageScaleFactor(), 0.01f); 1878 } 1879 1880 class WebFrameResizeTest : public WebFrameTest { 1881 protected: 1882 1883 static FloatSize computeRelativeOffset(const IntPoint& absoluteOffset, const LayoutRect& rect) 1884 { 1885 FloatSize relativeOffset = FloatPoint(absoluteOffset) - rect.location(); 1886 relativeOffset.scale(1.f / rect.width(), 1.f / rect.height()); 1887 return relativeOffset; 1888 } 1889 1890 void testResizeYieldsCorrectScrollAndScale(const char* url, 1891 const float initialPageScaleFactor, 1892 const WebSize scrollOffset, 1893 const WebSize viewportSize, 1894 const bool shouldScaleRelativeToViewportWidth) { 1895 UseMockScrollbarSettings mockScrollbarSettings; 1896 registerMockedHttpURLLoad(url); 1897 1898 const float aspectRatio = static_cast<float>(viewportSize.width) / viewportSize.height; 1899 1900 FrameTestHelpers::WebViewHelper webViewHelper; 1901 webViewHelper.initializeAndLoad(m_baseURL + url, true, 0, 0, enableViewportSettings); 1902 1903 // Origin scrollOffsets preserved under resize. 1904 { 1905 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height)); 1906 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor); 1907 ASSERT_EQ(viewportSize, webViewHelper.webViewImpl()->size()); 1908 ASSERT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor()); 1909 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width)); 1910 float expectedPageScaleFactor = initialPageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1); 1911 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f); 1912 EXPECT_EQ(WebSize(), webViewHelper.webViewImpl()->mainFrame()->scrollOffset()); 1913 } 1914 1915 // Resizing just the height should not affect pageScaleFactor or scrollOffset. 1916 { 1917 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height)); 1918 webViewHelper.webViewImpl()->setPageScaleFactor(initialPageScaleFactor); 1919 webViewHelper.webViewImpl()->setMainFrameScrollOffset(WebPoint(scrollOffset.width, scrollOffset.height)); 1920 webViewHelper.webViewImpl()->layout(); 1921 const WebSize expectedScrollOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset(); 1922 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f)); 1923 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor()); 1924 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset()); 1925 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height * 0.8f)); 1926 EXPECT_EQ(initialPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor()); 1927 EXPECT_EQ(expectedScrollOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset()); 1928 } 1929 1930 // Generic resize preserves scrollOffset relative to anchor node located 1931 // the top center of the screen. 1932 { 1933 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width)); 1934 float pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor(); 1935 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.width, viewportSize.height)); 1936 float expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? aspectRatio : 1); 1937 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f); 1938 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(scrollOffset); 1939 1940 IntPoint anchorPoint = IntPoint(scrollOffset) + IntPoint(viewportSize.width / 2, 0); 1941 RefPtrWillBeRawPtr<Node> anchorNode = webViewHelper.webViewImpl()->mainFrameImpl()->frame()->eventHandler().hitTestResultAtPoint(anchorPoint, HitTestRequest::ReadOnly | HitTestRequest::Active).innerNode(); 1942 ASSERT(anchorNode); 1943 1944 pageScaleFactor = webViewHelper.webViewImpl()->pageScaleFactor(); 1945 const FloatSize preResizeRelativeOffset 1946 = computeRelativeOffset(anchorPoint, anchorNode->boundingBox()); 1947 webViewHelper.webViewImpl()->resize(WebSize(viewportSize.height, viewportSize.width)); 1948 IntPoint newAnchorPoint = IntPoint(webViewHelper.webViewImpl()->mainFrame()->scrollOffset()) + IntPoint(viewportSize.height / 2, 0); 1949 const FloatSize postResizeRelativeOffset 1950 = computeRelativeOffset(newAnchorPoint, anchorNode->boundingBox()); 1951 EXPECT_NEAR(preResizeRelativeOffset.width(), postResizeRelativeOffset.width(), 0.15f); 1952 expectedPageScaleFactor = pageScaleFactor * (shouldScaleRelativeToViewportWidth ? 1 / aspectRatio : 1); 1953 EXPECT_NEAR(expectedPageScaleFactor, webViewHelper.webViewImpl()->pageScaleFactor(), 0.05f); 1954 } 1955 } 1956 }; 1957 1958 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForWidthEqualsDeviceWidth) 1959 { 1960 // With width=device-width, pageScaleFactor is preserved across resizes as 1961 // long as the content adjusts according to the device-width. 1962 const char* url = "resize_scroll_mobile.html"; 1963 const float initialPageScaleFactor = 1; 1964 const WebSize scrollOffset(0, 50); 1965 const WebSize viewportSize(120, 160); 1966 const bool shouldScaleRelativeToViewportWidth = true; 1967 1968 testResizeYieldsCorrectScrollAndScale( 1969 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth); 1970 } 1971 1972 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForMinimumScale) 1973 { 1974 // This tests a scenario where minimum-scale is set to 1.0, but some element 1975 // on the page is slightly larger than the portrait width, so our "natural" 1976 // minimum-scale would be lower. In that case, we should stick to 1.0 scale 1977 // on rotation and not do anything strange. 1978 const char* url = "resize_scroll_minimum_scale.html"; 1979 const float initialPageScaleFactor = 1; 1980 const WebSize scrollOffset(0, 0); 1981 const WebSize viewportSize(240, 320); 1982 const bool shouldScaleRelativeToViewportWidth = false; 1983 1984 testResizeYieldsCorrectScrollAndScale( 1985 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth); 1986 } 1987 1988 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedWidth) 1989 { 1990 // With a fixed width, pageScaleFactor scales by the relative change in viewport width. 1991 const char* url = "resize_scroll_fixed_width.html"; 1992 const float initialPageScaleFactor = 2; 1993 const WebSize scrollOffset(0, 200); 1994 const WebSize viewportSize(240, 320); 1995 const bool shouldScaleRelativeToViewportWidth = true; 1996 1997 testResizeYieldsCorrectScrollAndScale( 1998 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth); 1999 } 2000 2001 TEST_F(WebFrameResizeTest, ResizeYieldsCorrectScrollAndScaleForFixedLayout) 2002 { 2003 // With a fixed layout, pageScaleFactor scales by the relative change in viewport width. 2004 const char* url = "resize_scroll_fixed_layout.html"; 2005 const float initialPageScaleFactor = 2; 2006 const WebSize scrollOffset(200, 400); 2007 const WebSize viewportSize(320, 240); 2008 const bool shouldScaleRelativeToViewportWidth = true; 2009 2010 testResizeYieldsCorrectScrollAndScale( 2011 url, initialPageScaleFactor, scrollOffset, viewportSize, shouldScaleRelativeToViewportWidth); 2012 } 2013 2014 TEST_F(WebFrameTest, pageScaleFactorScalesPaintClip) 2015 { 2016 UseMockScrollbarSettings mockScrollbarSettings; 2017 registerMockedHttpURLLoad("large-div.html"); 2018 2019 FixedLayoutTestWebViewClient client; 2020 client.m_screenInfo.deviceScaleFactor = 1; 2021 int viewportWidth = 50; 2022 int viewportHeight = 50; 2023 2024 FrameTestHelpers::WebViewHelper webViewHelper; 2025 webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, 0, &client); 2026 // FIXME: This test breaks if the viewport is enabled before loading the page due to the paint 2027 // calls below not working on composited layers. For some reason, enabling the viewport here 2028 // doesn't cause compositing 2029 webViewHelper.webView()->settings()->setViewportEnabled(true); 2030 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2031 webViewHelper.webView()->layout(); 2032 2033 // Set <1 page scale so that the clip rect should be larger than 2034 // the viewport size as passed into resize(). 2035 webViewHelper.webView()->setPageScaleFactor(0.5); 2036 2037 SkBitmap bitmap; 2038 bitmap.allocN32Pixels(200, 200); 2039 bitmap.eraseColor(0); 2040 SkCanvas canvas(bitmap); 2041 2042 GraphicsContext context(&canvas); 2043 context.setRegionTrackingMode(GraphicsContext::RegionTrackingOpaque); 2044 2045 EXPECT_RECT_EQ(IntRect(0, 0, 0, 0), context.opaqueRegion().asRect()); 2046 2047 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 2048 IntRect paintRect(0, 0, 200, 200); 2049 view->paint(&context, paintRect); 2050 2051 // FIXME: This test broke in release builds when changing the FixedLayoutTestWebViewClient 2052 // to return a non-null layerTreeView, which is what all our shipping configurations do, 2053 // so this is just exposing an existing bug. 2054 // crbug.com/365812 2055 #ifndef NDEBUG 2056 int viewportWidthMinusScrollbar = 50 - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15); 2057 int viewportHeightMinusScrollbar = 50 - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15); 2058 IntRect clippedRect(0, 0, viewportWidthMinusScrollbar * 2, viewportHeightMinusScrollbar * 2); 2059 EXPECT_RECT_EQ(clippedRect, context.opaqueRegion().asRect()); 2060 #endif 2061 } 2062 2063 TEST_F(WebFrameTest, pageScaleFactorUpdatesScrollbars) 2064 { 2065 UseMockScrollbarSettings mockScrollbarSettings; 2066 registerMockedHttpURLLoad("fixed_layout.html"); 2067 2068 FixedLayoutTestWebViewClient client; 2069 client.m_screenInfo.deviceScaleFactor = 1; 2070 int viewportWidth = 640; 2071 int viewportHeight = 480; 2072 2073 FrameTestHelpers::WebViewHelper webViewHelper; 2074 webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client, enableViewportSettings); 2075 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2076 webViewHelper.webView()->layout(); 2077 2078 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 2079 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width()); 2080 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height()); 2081 2082 webViewHelper.webView()->setPageScaleFactor(10); 2083 2084 EXPECT_EQ(view->scrollSize(HorizontalScrollbar), view->contentsSize().width() - view->visibleContentRect().width()); 2085 EXPECT_EQ(view->scrollSize(VerticalScrollbar), view->contentsSize().height() - view->visibleContentRect().height()); 2086 } 2087 2088 TEST_F(WebFrameTest, CanOverrideScaleLimits) 2089 { 2090 UseMockScrollbarSettings mockScrollbarSettings; 2091 2092 registerMockedHttpURLLoad("no_scale_for_you.html"); 2093 2094 FixedLayoutTestWebViewClient client; 2095 client.m_screenInfo.deviceScaleFactor = 1; 2096 int viewportWidth = 640; 2097 int viewportHeight = 480; 2098 2099 FrameTestHelpers::WebViewHelper webViewHelper; 2100 webViewHelper.initializeAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client, enableViewportSettings); 2101 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2102 2103 EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor()); 2104 EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor()); 2105 2106 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(true); 2107 webViewHelper.webView()->layout(); 2108 2109 EXPECT_EQ(1.0f, webViewHelper.webView()->minimumPageScaleFactor()); 2110 EXPECT_EQ(5.0f, webViewHelper.webView()->maximumPageScaleFactor()); 2111 2112 webViewHelper.webView()->setIgnoreViewportTagScaleLimits(false); 2113 webViewHelper.webView()->layout(); 2114 2115 EXPECT_EQ(2.0f, webViewHelper.webView()->minimumPageScaleFactor()); 2116 EXPECT_EQ(2.0f, webViewHelper.webView()->maximumPageScaleFactor()); 2117 } 2118 2119 TEST_F(WebFrameTest, updateOverlayScrollbarLayers) 2120 { 2121 UseMockScrollbarSettings mockScrollbarSettings; 2122 2123 registerMockedHttpURLLoad("large-div.html"); 2124 2125 int viewWidth = 500; 2126 int viewHeight = 500; 2127 2128 OwnPtr<FakeCompositingWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FakeCompositingWebViewClient()); 2129 FrameTestHelpers::WebViewHelper webViewHelper; 2130 webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView); 2131 2132 webViewHelper.webView()->setPageScaleFactorLimits(1, 1); 2133 webViewHelper.webView()->resize(WebSize(viewWidth, viewHeight)); 2134 FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(), m_baseURL + "large-div.html"); 2135 2136 FrameView* view = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 2137 EXPECT_TRUE(view->renderView()->compositor()->layerForHorizontalScrollbar()); 2138 EXPECT_TRUE(view->renderView()->compositor()->layerForVerticalScrollbar()); 2139 2140 webViewHelper.webView()->resize(WebSize(viewWidth * 10, viewHeight * 10)); 2141 webViewHelper.webView()->layout(); 2142 EXPECT_FALSE(view->renderView()->compositor()->layerForHorizontalScrollbar()); 2143 EXPECT_FALSE(view->renderView()->compositor()->layerForVerticalScrollbar()); 2144 } 2145 2146 void setScaleAndScrollAndLayout(WebView* webView, WebPoint scroll, float scale) 2147 { 2148 webView->setPageScaleFactor(scale); 2149 webView->setMainFrameScrollOffset(WebPoint(scroll.x, scroll.y)); 2150 webView->layout(); 2151 } 2152 2153 TEST_F(WebFrameTest, DivAutoZoomParamsTest) 2154 { 2155 registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html"); 2156 2157 const float deviceScaleFactor = 2.0f; 2158 int viewportWidth = 640 / deviceScaleFactor; 2159 int viewportHeight = 1280 / deviceScaleFactor; 2160 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2161 FrameTestHelpers::WebViewHelper webViewHelper; 2162 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html"); 2163 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor); 2164 webViewHelper.webView()->setPageScaleFactorLimits(0.01f, 4); 2165 webViewHelper.webView()->setPageScaleFactor(0.5f); 2166 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2167 webViewHelper.webView()->layout(); 2168 2169 WebRect wideDiv(200, 100, 400, 150); 2170 WebRect tallDiv(200, 300, 400, 800); 2171 WebRect doubleTapPointWide(wideDiv.x + 50, wideDiv.y + 50, touchPointPadding, touchPointPadding); 2172 WebRect doubleTapPointTall(tallDiv.x + 50, tallDiv.y + 50, touchPointPadding, touchPointPadding); 2173 WebRect wideBlockBounds; 2174 WebRect tallBlockBounds; 2175 float scale; 2176 WebPoint scroll; 2177 2178 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2179 2180 // Test double-tap zooming into wide div. 2181 wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false); 2182 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll); 2183 // The div should horizontally fill the screen (modulo margins), and 2184 // vertically centered (modulo integer rounding). 2185 EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1); 2186 EXPECT_NEAR(wideDiv.x, scroll.x, 20); 2187 EXPECT_EQ(0, scroll.y); 2188 2189 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale); 2190 2191 // Test zoom out back to minimum scale. 2192 wideBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointWide, false); 2193 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointWide.x, doubleTapPointWide.y), wideBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll); 2194 2195 scale = webViewHelper.webViewImpl()->minimumPageScaleFactor(); 2196 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), scale); 2197 2198 // Test double-tap zooming into tall div. 2199 tallBlockBounds = webViewHelper.webViewImpl()->computeBlockBounds(doubleTapPointTall, false); 2200 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(doubleTapPointTall.x, doubleTapPointTall.y), tallBlockBounds, touchPointPadding, doubleTapZoomAlreadyLegibleScale, scale, scroll); 2201 // The div should start at the top left of the viewport. 2202 EXPECT_NEAR(viewportWidth / (float) tallDiv.width, scale, 0.1); 2203 EXPECT_NEAR(tallDiv.x, scroll.x, 20); 2204 EXPECT_NEAR(tallDiv.y, scroll.y, 20); 2205 2206 // Test for Non-doubletap scaling 2207 // Test zooming into div. 2208 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(WebPoint(250, 250), webViewHelper.webViewImpl()->computeBlockBounds(WebRect(250, 250, 10, 10), true), 0, doubleTapZoomAlreadyLegibleScale, scale, scroll); 2209 EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1); 2210 } 2211 2212 void simulatePageScale(WebViewImpl* webViewImpl, float& scale) 2213 { 2214 IntSize scrollDelta = webViewImpl->fakePageScaleAnimationTargetPositionForTesting() - webViewImpl->mainFrameImpl()->frameView()->scrollPosition(); 2215 float scaleDelta = webViewImpl->fakePageScaleAnimationPageScaleForTesting() / webViewImpl->pageScaleFactor(); 2216 webViewImpl->applyViewportDeltas(scrollDelta, scaleDelta, 0); 2217 scale = webViewImpl->pageScaleFactor(); 2218 } 2219 2220 void simulateMultiTargetZoom(WebViewImpl* webViewImpl, const WebRect& rect, float& scale) 2221 { 2222 if (webViewImpl->zoomToMultipleTargetsRect(rect)) 2223 simulatePageScale(webViewImpl, scale); 2224 } 2225 2226 void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale) 2227 { 2228 webViewImpl->animateDoubleTapZoom(point); 2229 EXPECT_TRUE(webViewImpl->fakeDoubleTapAnimationPendingForTesting()); 2230 simulatePageScale(webViewImpl, scale); 2231 } 2232 2233 TEST_F(WebFrameTest, DivAutoZoomWideDivTest) 2234 { 2235 registerMockedHttpURLLoad("get_wide_div_for_auto_zoom_test.html"); 2236 2237 const float deviceScaleFactor = 2.0f; 2238 int viewportWidth = 640 / deviceScaleFactor; 2239 int viewportHeight = 1280 / deviceScaleFactor; 2240 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2241 FrameTestHelpers::WebViewHelper webViewHelper; 2242 webViewHelper.initializeAndLoad(m_baseURL + "get_wide_div_for_auto_zoom_test.html"); 2243 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2244 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4); 2245 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor); 2246 webViewHelper.webView()->setPageScaleFactor(1.0f); 2247 webViewHelper.webView()->layout(); 2248 2249 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2250 2251 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2252 2253 WebRect div(0, 100, viewportWidth, 150); 2254 WebPoint point(div.x + 50, div.y + 50); 2255 float scale; 2256 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2257 2258 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale); 2259 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2260 simulateDoubleTap(webViewHelper.webViewImpl(), point, scale); 2261 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2262 } 2263 2264 TEST_F(WebFrameTest, DivAutoZoomVeryTallTest) 2265 { 2266 // When a block is taller than the viewport and a zoom targets a lower part 2267 // of it, then we should keep the target point onscreen instead of snapping 2268 // back up the top of the block. 2269 registerMockedHttpURLLoad("very_tall_div.html"); 2270 2271 const float deviceScaleFactor = 2.0f; 2272 int viewportWidth = 640 / deviceScaleFactor; 2273 int viewportHeight = 1280 / deviceScaleFactor; 2274 FrameTestHelpers::WebViewHelper webViewHelper; 2275 webViewHelper.initializeAndLoad(m_baseURL + "very_tall_div.html", true, 0, 0, enableViewportSettings); 2276 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2277 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4); 2278 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor); 2279 webViewHelper.webView()->setPageScaleFactor(1.0f); 2280 webViewHelper.webView()->layout(); 2281 2282 WebRect div(200, 300, 400, 5000); 2283 WebPoint point(div.x + 50, div.y + 3000); 2284 float scale; 2285 WebPoint scroll; 2286 2287 WebRect blockBounds = webViewHelper.webViewImpl()->computeBlockBounds(WebRect(point.x, point.y, 0, 0), true); 2288 webViewHelper.webViewImpl()->computeScaleAndScrollForBlockRect(point, blockBounds, 0, 1.0f, scale, scroll); 2289 EXPECT_EQ(scale, 1.0f); 2290 EXPECT_EQ(scroll.y, 2660); 2291 } 2292 2293 TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTest) 2294 { 2295 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html"); 2296 2297 const float deviceScaleFactor = 2.0f; 2298 int viewportWidth = 640 / deviceScaleFactor; 2299 int viewportHeight = 1280 / deviceScaleFactor; 2300 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2301 FrameTestHelpers::WebViewHelper webViewHelper; 2302 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html"); 2303 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2304 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4); 2305 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor); 2306 webViewHelper.webView()->setPageScaleFactor(0.5f); 2307 webViewHelper.webView()->layout(); 2308 2309 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2310 2311 WebRect topDiv(200, 100, 200, 150); 2312 WebRect bottomDiv(200, 300, 200, 150); 2313 WebPoint topPoint(topDiv.x + 50, topDiv.y + 50); 2314 WebPoint bottomPoint(bottomDiv.x + 50, bottomDiv.y + 50); 2315 float scale; 2316 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2317 2318 // Test double tap on two different divs 2319 // After first zoom, we should go back to minimum page scale with a second double tap. 2320 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale); 2321 EXPECT_FLOAT_EQ(1, scale); 2322 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale); 2323 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2324 2325 // If the user pinch zooms after double tap, a second double tap should zoom back to the div. 2326 simulateDoubleTap(webViewHelper.webViewImpl(), topPoint, scale); 2327 EXPECT_FLOAT_EQ(1, scale); 2328 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 0.6f, 0); 2329 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale); 2330 EXPECT_FLOAT_EQ(1, scale); 2331 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale); 2332 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2333 2334 // If we didn't yet get an auto-zoom update and a second double-tap arrives, should go back to minimum scale. 2335 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2336 webViewHelper.webViewImpl()->animateDoubleTapZoom(topPoint); 2337 EXPECT_TRUE(webViewHelper.webViewImpl()->fakeDoubleTapAnimationPendingForTesting()); 2338 simulateDoubleTap(webViewHelper.webViewImpl(), bottomPoint, scale); 2339 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2340 } 2341 2342 TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTest) 2343 { 2344 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html"); 2345 2346 int viewportWidth = 320; 2347 int viewportHeight = 480; 2348 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2349 FrameTestHelpers::WebViewHelper webViewHelper; 2350 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html"); 2351 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2352 webViewHelper.webView()->setDeviceScaleFactor(1.5f); 2353 webViewHelper.webView()->layout(); 2354 2355 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2356 2357 WebRect div(200, 100, 200, 150); 2358 WebPoint doubleTapPoint(div.x + 50, div.y + 50); 2359 float scale; 2360 2361 // Test double tap scale bounds. 2362 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 2363 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4); 2364 webViewHelper.webView()->layout(); 2365 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2366 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2367 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2368 EXPECT_FLOAT_EQ(1, scale); 2369 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2370 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2371 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2372 EXPECT_FLOAT_EQ(1, scale); 2373 2374 // Zoom in to reset double_tap_zoom_in_effect flag. 2375 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2376 // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale 2377 webViewHelper.webView()->setPageScaleFactorLimits(1.1f, 4); 2378 webViewHelper.webView()->layout(); 2379 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2380 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2381 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2382 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2383 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2384 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2385 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2386 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2387 2388 // Zoom in to reset double_tap_zoom_in_effect flag. 2389 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2390 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale 2391 webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4); 2392 webViewHelper.webView()->layout(); 2393 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2394 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2395 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2396 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2397 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2398 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2399 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2400 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2401 } 2402 2403 TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTest) 2404 { 2405 registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html"); 2406 2407 int viewportWidth = 320; 2408 int viewportHeight = 480; 2409 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2410 float accessibilityFontScaleFactor = 1.13f; 2411 FrameTestHelpers::WebViewHelper webViewHelper; 2412 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html"); 2413 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2414 webViewHelper.webView()->layout(); 2415 2416 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2417 webViewHelper.webViewImpl()->page()->settings().setTextAutosizingEnabled(true); 2418 webViewHelper.webViewImpl()->page()->settings().setAccessibilityFontScaleFactor(accessibilityFontScaleFactor); 2419 2420 WebRect div(200, 100, 200, 150); 2421 WebPoint doubleTapPoint(div.x + 50, div.y + 50); 2422 float scale; 2423 2424 // Test double tap scale bounds. 2425 // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < accessibilityFontScaleFactor 2426 float legibleScale = accessibilityFontScaleFactor; 2427 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2428 float doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2429 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4); 2430 webViewHelper.webView()->layout(); 2431 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2432 EXPECT_FLOAT_EQ(legibleScale, scale); 2433 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2434 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2435 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2436 EXPECT_FLOAT_EQ(legibleScale, scale); 2437 2438 // Zoom in to reset double_tap_zoom_in_effect flag. 2439 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2440 // 1 < accessibilityFontScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale 2441 webViewHelper.webView()->setPageScaleFactorLimits(1.0f, 4); 2442 webViewHelper.webView()->layout(); 2443 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2444 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2445 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2446 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2447 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2448 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2449 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2450 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2451 2452 // Zoom in to reset double_tap_zoom_in_effect flag. 2453 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2454 // minimumPageScale < 1 < accessibilityFontScaleFactor < doubleTapZoomAlreadyLegibleScale 2455 webViewHelper.webView()->setPageScaleFactorLimits(0.95f, 4); 2456 webViewHelper.webView()->layout(); 2457 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2458 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2459 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2460 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2461 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2462 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2463 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2464 EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale); 2465 2466 // Zoom in to reset double_tap_zoom_in_effect flag. 2467 webViewHelper.webViewImpl()->applyViewportDeltas(WebSize(), 1.1f, 0); 2468 // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < accessibilityFontScaleFactor 2469 webViewHelper.webView()->setPageScaleFactorLimits(0.9f, 4); 2470 webViewHelper.webView()->layout(); 2471 doubleTapZoomAlreadyLegibleScale = webViewHelper.webViewImpl()->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio; 2472 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2473 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2474 EXPECT_FLOAT_EQ(legibleScale, scale); 2475 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2476 EXPECT_FLOAT_EQ(webViewHelper.webViewImpl()->minimumPageScaleFactor(), scale); 2477 simulateDoubleTap(webViewHelper.webViewImpl(), doubleTapPoint, scale); 2478 EXPECT_FLOAT_EQ(legibleScale, scale); 2479 } 2480 2481 TEST_F(WebFrameTest, DivMultipleTargetZoomMultipleDivsTest) 2482 { 2483 registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html"); 2484 2485 const float deviceScaleFactor = 2.0f; 2486 int viewportWidth = 640 / deviceScaleFactor; 2487 int viewportHeight = 1280 / deviceScaleFactor; 2488 float doubleTapZoomAlreadyLegibleRatio = 1.2f; 2489 FrameTestHelpers::WebViewHelper webViewHelper; 2490 webViewHelper.initializeAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html"); 2491 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2492 webViewHelper.webView()->setPageScaleFactorLimits(0.5f, 4); 2493 webViewHelper.webView()->setDeviceScaleFactor(deviceScaleFactor); 2494 webViewHelper.webView()->setPageScaleFactor(0.5f); 2495 webViewHelper.webView()->layout(); 2496 2497 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2498 2499 WebRect viewportRect(0, 0, viewportWidth, viewportHeight); 2500 WebRect topDiv(200, 100, 200, 150); 2501 WebRect bottomDiv(200, 300, 200, 150); 2502 float scale; 2503 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), WebPoint(0, 0), (webViewHelper.webViewImpl()->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2); 2504 2505 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale); 2506 EXPECT_FLOAT_EQ(1, scale); 2507 simulateMultiTargetZoom(webViewHelper.webViewImpl(), bottomDiv, scale); 2508 EXPECT_FLOAT_EQ(1, scale); 2509 simulateMultiTargetZoom(webViewHelper.webViewImpl(), viewportRect, scale); 2510 EXPECT_FLOAT_EQ(1, scale); 2511 webViewHelper.webViewImpl()->setPageScaleFactor(webViewHelper.webViewImpl()->minimumPageScaleFactor()); 2512 simulateMultiTargetZoom(webViewHelper.webViewImpl(), topDiv, scale); 2513 EXPECT_FLOAT_EQ(1, scale); 2514 } 2515 2516 TEST_F(WebFrameTest, DivScrollIntoEditableTest) 2517 { 2518 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html"); 2519 2520 int viewportWidth = 450; 2521 int viewportHeight = 300; 2522 float leftBoxRatio = 0.3f; 2523 int caretPadding = 10; 2524 float minReadableCaretHeight = 18.0f; 2525 FrameTestHelpers::WebViewHelper webViewHelper; 2526 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html"); 2527 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2528 webViewHelper.webView()->setPageScaleFactorLimits(1, 4); 2529 webViewHelper.webView()->layout(); 2530 webViewHelper.webView()->setDeviceScaleFactor(1.5f); 2531 webViewHelper.webView()->settings()->setAutoZoomFocusedNodeToLegibleScale(true); 2532 2533 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2534 2535 WebRect editBoxWithText(200, 200, 250, 20); 2536 WebRect editBoxWithNoText(200, 250, 250, 20); 2537 2538 // Test scrolling the focused node 2539 // The edit box is shorter and narrower than the viewport when legible. 2540 webViewHelper.webView()->advanceFocus(false); 2541 // Set the caret to the end of the input box. 2542 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(1000, 1000); 2543 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1); 2544 WebRect rect, caret; 2545 webViewHelper.webViewImpl()->selectionBounds(caret, rect); 2546 2547 float scale; 2548 IntPoint scroll; 2549 bool needAnimation; 2550 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2551 EXPECT_TRUE(needAnimation); 2552 // The edit box should be left aligned with a margin for possible label. 2553 int hScroll = editBoxWithText.x - leftBoxRatio * viewportWidth / scale; 2554 EXPECT_NEAR(hScroll, scroll.x(), 1); 2555 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2; 2556 EXPECT_NEAR(vScroll, scroll.y(), 1); 2557 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1); 2558 2559 // The edit box is wider than the viewport when legible. 2560 viewportWidth = 200; 2561 viewportHeight = 150; 2562 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2563 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1); 2564 webViewHelper.webViewImpl()->selectionBounds(caret, rect); 2565 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2566 EXPECT_TRUE(needAnimation); 2567 // The caret should be right aligned since the caret would be offscreen when the edit box is left aligned. 2568 hScroll = caret.x + caret.width + caretPadding - viewportWidth / scale; 2569 EXPECT_NEAR(hScroll, scroll.x(), 1); 2570 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1); 2571 2572 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1); 2573 // Move focus to edit box with text. 2574 webViewHelper.webView()->advanceFocus(false); 2575 webViewHelper.webViewImpl()->selectionBounds(caret, rect); 2576 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2577 EXPECT_TRUE(needAnimation); 2578 // The edit box should be left aligned. 2579 hScroll = editBoxWithNoText.x; 2580 EXPECT_NEAR(hScroll, scroll.x(), 1); 2581 vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2; 2582 EXPECT_NEAR(vScroll, scroll.y(), 1); 2583 EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1); 2584 2585 setScaleAndScrollAndLayout(webViewHelper.webViewImpl(), scroll, scale); 2586 2587 // Move focus back to the first edit box. 2588 webViewHelper.webView()->advanceFocus(true); 2589 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2590 // The position should have stayed the same since this box was already on screen with the right scale. 2591 EXPECT_FALSE(needAnimation); 2592 } 2593 2594 TEST_F(WebFrameTest, DivScrollIntoEditablePreservePageScaleTest) 2595 { 2596 registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html"); 2597 2598 const int viewportWidth = 450; 2599 const int viewportHeight = 300; 2600 const float minReadableCaretHeight = 18.0f; 2601 FrameTestHelpers::WebViewHelper webViewHelper; 2602 webViewHelper.initializeAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html"); 2603 webViewHelper.webView()->resize(WebSize(viewportWidth, viewportHeight)); 2604 webViewHelper.webView()->setPageScaleFactorLimits(1, 4); 2605 webViewHelper.webView()->layout(); 2606 webViewHelper.webView()->setDeviceScaleFactor(1.5f); 2607 webViewHelper.webView()->settings()->setAutoZoomFocusedNodeToLegibleScale(true); 2608 webViewHelper.webViewImpl()->enableFakePageScaleAnimationForTesting(true); 2609 2610 const WebRect editBoxWithText(200, 200, 250, 20); 2611 2612 webViewHelper.webView()->advanceFocus(false); 2613 // Set the caret to the begining of the input box. 2614 webViewHelper.webView()->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(0, 0); 2615 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), 1); 2616 WebRect rect, caret; 2617 webViewHelper.webViewImpl()->selectionBounds(caret, rect); 2618 2619 // Set page scale twice larger then minimal readable scale 2620 float newScale = minReadableCaretHeight / caret.height * 2.0; 2621 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(0, 0), newScale); 2622 2623 float scale; 2624 IntPoint scroll; 2625 bool needAnimation; 2626 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2627 EXPECT_TRUE(needAnimation); 2628 // Edit box and caret should be left alinged 2629 int hScroll = editBoxWithText.x; 2630 EXPECT_NEAR(hScroll, scroll.x(), 1); 2631 int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2; 2632 EXPECT_NEAR(vScroll, scroll.y(), 1); 2633 // Page scale have to be unchanged 2634 EXPECT_EQ(newScale, scale); 2635 2636 // Set page scale and scroll such that edit box will be under the screen 2637 newScale = 3.0; 2638 hScroll = 200; 2639 setScaleAndScrollAndLayout(webViewHelper.webView(), WebPoint(hScroll, 0), newScale); 2640 webViewHelper.webViewImpl()->computeScaleAndScrollForFocusedNode(webViewHelper.webViewImpl()->focusedElement(), scale, scroll, needAnimation); 2641 EXPECT_TRUE(needAnimation); 2642 // Horizontal scroll have to be the same 2643 EXPECT_NEAR(hScroll, scroll.x(), 1); 2644 vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2; 2645 EXPECT_NEAR(vScroll, scroll.y(), 1); 2646 // Page scale have to be unchanged 2647 EXPECT_EQ(newScale, scale); 2648 } 2649 2650 class TestReloadDoesntRedirectWebFrameClient : public FrameTestHelpers::TestWebFrameClient { 2651 public: 2652 virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE 2653 { 2654 EXPECT_FALSE(info.isRedirect); 2655 return WebNavigationPolicyCurrentTab; 2656 } 2657 }; 2658 2659 TEST_F(WebFrameTest, ReloadDoesntSetRedirect) 2660 { 2661 // Test for case in http://crbug.com/73104. Reloading a frame very quickly 2662 // would sometimes call decidePolicyForNavigation with isRedirect=true 2663 registerMockedHttpURLLoad("form.html"); 2664 2665 TestReloadDoesntRedirectWebFrameClient webFrameClient; 2666 FrameTestHelpers::WebViewHelper webViewHelper; 2667 webViewHelper.initializeAndLoad(m_baseURL + "form.html", false, &webFrameClient); 2668 2669 webViewHelper.webView()->mainFrame()->reload(true); 2670 // start another reload before request is delivered. 2671 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame()); 2672 } 2673 2674 class ReloadWithOverrideURLTask : public WebThread::Task { 2675 public: 2676 ReloadWithOverrideURLTask(WebFrame* frame, const KURL& url, bool ignoreCache) 2677 : m_frame(frame), m_url(url), m_ignoreCache(ignoreCache) 2678 { 2679 } 2680 2681 virtual void run() OVERRIDE 2682 { 2683 m_frame->reloadWithOverrideURL(m_url, m_ignoreCache); 2684 } 2685 2686 private: 2687 WebFrame* const m_frame; 2688 const KURL m_url; 2689 const bool m_ignoreCache; 2690 }; 2691 2692 TEST_F(WebFrameTest, ReloadWithOverrideURLPreservesState) 2693 { 2694 const std::string firstURL = "find.html"; 2695 const std::string secondURL = "form.html"; 2696 const std::string thirdURL = "history.html"; 2697 const float pageScaleFactor = 1.1684f; 2698 const int pageWidth = 640; 2699 const int pageHeight = 480; 2700 2701 registerMockedHttpURLLoad(firstURL); 2702 registerMockedHttpURLLoad(secondURL); 2703 registerMockedHttpURLLoad(thirdURL); 2704 2705 FrameTestHelpers::WebViewHelper webViewHelper; 2706 webViewHelper.initializeAndLoad(m_baseURL + firstURL, true); 2707 webViewHelper.webViewImpl()->resize(WebSize(pageWidth, pageHeight)); 2708 webViewHelper.webViewImpl()->mainFrame()->setScrollOffset(WebSize(pageWidth / 4, pageHeight / 4)); 2709 webViewHelper.webViewImpl()->setPageScaleFactor(pageScaleFactor); 2710 2711 WebSize previousOffset = webViewHelper.webViewImpl()->mainFrame()->scrollOffset(); 2712 float previousScale = webViewHelper.webViewImpl()->pageScaleFactor(); 2713 2714 // Reload the page using the cache. 2715 Platform::current()->currentThread()->postTask( 2716 new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + secondURL), false)); 2717 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame()); 2718 ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset()); 2719 ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor()); 2720 2721 // Reload the page while ignoring the cache. 2722 Platform::current()->currentThread()->postTask( 2723 new ReloadWithOverrideURLTask(webViewHelper.webViewImpl()->mainFrame(), toKURL(m_baseURL + thirdURL), true)); 2724 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webViewImpl()->mainFrame()); 2725 ASSERT_EQ(previousOffset, webViewHelper.webViewImpl()->mainFrame()->scrollOffset()); 2726 ASSERT_EQ(previousScale, webViewHelper.webViewImpl()->pageScaleFactor()); 2727 } 2728 2729 TEST_F(WebFrameTest, ReloadWhileProvisional) 2730 { 2731 // Test that reloading while the previous load is still pending does not cause the initial 2732 // request to get lost. 2733 registerMockedHttpURLLoad("fixed_layout.html"); 2734 2735 FrameTestHelpers::WebViewHelper webViewHelper; 2736 webViewHelper.initialize(); 2737 WebURLRequest request; 2738 request.initialize(); 2739 request.setURL(toKURL(m_baseURL + "fixed_layout.html")); 2740 webViewHelper.webView()->mainFrame()->loadRequest(request); 2741 // start reload before first request is delivered. 2742 FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame()); 2743 2744 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource(); 2745 ASSERT_TRUE(dataSource); 2746 EXPECT_EQ(toKURL(m_baseURL + "fixed_layout.html"), toKURL(dataSource->request().url().spec())); 2747 } 2748 2749 TEST_F(WebFrameTest, AppendRedirects) 2750 { 2751 const std::string firstURL = "about:blank"; 2752 const std::string secondURL = "http://www.test.com"; 2753 2754 FrameTestHelpers::WebViewHelper webViewHelper; 2755 webViewHelper.initializeAndLoad(firstURL, true); 2756 2757 WebDataSource* dataSource = webViewHelper.webView()->mainFrame()->dataSource(); 2758 ASSERT_TRUE(dataSource); 2759 dataSource->appendRedirect(toKURL(secondURL)); 2760 2761 WebVector<WebURL> redirects; 2762 dataSource->redirectChain(redirects); 2763 ASSERT_EQ(2U, redirects.size()); 2764 EXPECT_EQ(toKURL(firstURL), toKURL(redirects[0].spec().data())); 2765 EXPECT_EQ(toKURL(secondURL), toKURL(redirects[1].spec().data())); 2766 } 2767 2768 TEST_F(WebFrameTest, IframeRedirect) 2769 { 2770 registerMockedHttpURLLoad("iframe_redirect.html"); 2771 registerMockedHttpURLLoad("visible_iframe.html"); 2772 2773 FrameTestHelpers::WebViewHelper webViewHelper; 2774 webViewHelper.initializeAndLoad(m_baseURL + "iframe_redirect.html", true); 2775 // Pump pending requests one more time. The test page loads script that navigates. 2776 FrameTestHelpers::pumpPendingRequestsDoNotUse(webViewHelper.webView()->mainFrame()); 2777 2778 WebFrame* iframe = webViewHelper.webView()->findFrameByName(WebString::fromUTF8("ifr")); 2779 ASSERT_TRUE(iframe); 2780 WebDataSource* iframeDataSource = iframe->dataSource(); 2781 ASSERT_TRUE(iframeDataSource); 2782 WebVector<WebURL> redirects; 2783 iframeDataSource->redirectChain(redirects); 2784 ASSERT_EQ(2U, redirects.size()); 2785 EXPECT_EQ(toKURL("about:blank"), toKURL(redirects[0].spec().data())); 2786 EXPECT_EQ(toKURL("http://www.test.com/visible_iframe.html"), toKURL(redirects[1].spec().data())); 2787 } 2788 2789 TEST_F(WebFrameTest, ClearFocusedNodeTest) 2790 { 2791 registerMockedHttpURLLoad("iframe_clear_focused_node_test.html"); 2792 registerMockedHttpURLLoad("autofocus_input_field_iframe.html"); 2793 2794 FrameTestHelpers::WebViewHelper webViewHelper; 2795 webViewHelper.initializeAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true); 2796 2797 // Clear the focused node. 2798 webViewHelper.webView()->clearFocusedElement(); 2799 2800 // Now retrieve the FocusedNode and test it should be null. 2801 EXPECT_EQ(0, webViewHelper.webViewImpl()->focusedElement()); 2802 } 2803 2804 // Implementation of WebFrameClient that tracks the v8 contexts that are created 2805 // and destroyed for verification. 2806 class ContextLifetimeTestWebFrameClient : public FrameTestHelpers::TestWebFrameClient { 2807 public: 2808 struct Notification { 2809 public: 2810 Notification(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId) 2811 : frame(frame) 2812 , context(context->GetIsolate(), context) 2813 , worldId(worldId) 2814 { 2815 } 2816 2817 ~Notification() 2818 { 2819 context.Reset(); 2820 } 2821 2822 bool Equals(Notification* other) 2823 { 2824 return other && frame == other->frame && context == other->context && worldId == other->worldId; 2825 } 2826 2827 WebLocalFrame* frame; 2828 v8::Persistent<v8::Context> context; 2829 int worldId; 2830 }; 2831 2832 virtual ~ContextLifetimeTestWebFrameClient() 2833 { 2834 reset(); 2835 } 2836 2837 void reset() 2838 { 2839 for (size_t i = 0; i < createNotifications.size(); ++i) 2840 delete createNotifications[i]; 2841 2842 for (size_t i = 0; i < releaseNotifications.size(); ++i) 2843 delete releaseNotifications[i]; 2844 2845 createNotifications.clear(); 2846 releaseNotifications.clear(); 2847 } 2848 2849 std::vector<Notification*> createNotifications; 2850 std::vector<Notification*> releaseNotifications; 2851 2852 private: 2853 virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE 2854 { 2855 createNotifications.push_back(new Notification(frame, context, worldId)); 2856 } 2857 2858 virtual void willReleaseScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int worldId) OVERRIDE 2859 { 2860 releaseNotifications.push_back(new Notification(frame, context, worldId)); 2861 } 2862 }; 2863 2864 // TODO(aa): Deflake this test. 2865 TEST_F(WebFrameTest, FLAKY_ContextNotificationsLoadUnload) 2866 { 2867 v8::HandleScope handleScope(v8::Isolate::GetCurrent()); 2868 2869 registerMockedHttpURLLoad("context_notifications_test.html"); 2870 registerMockedHttpURLLoad("context_notifications_test_frame.html"); 2871 2872 // Load a frame with an iframe, make sure we get the right create notifications. 2873 ContextLifetimeTestWebFrameClient webFrameClient; 2874 FrameTestHelpers::WebViewHelper webViewHelper; 2875 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient); 2876 2877 WebFrame* mainFrame = webViewHelper.webView()->mainFrame(); 2878 WebFrame* childFrame = mainFrame->firstChild(); 2879 2880 ASSERT_EQ(2u, webFrameClient.createNotifications.size()); 2881 EXPECT_EQ(0u, webFrameClient.releaseNotifications.size()); 2882 2883 ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0]; 2884 ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1]; 2885 2886 EXPECT_EQ(mainFrame, firstCreateNotification->frame); 2887 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context); 2888 EXPECT_EQ(0, firstCreateNotification->worldId); 2889 2890 EXPECT_EQ(childFrame, secondCreateNotification->frame); 2891 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context); 2892 EXPECT_EQ(0, secondCreateNotification->worldId); 2893 2894 // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order. 2895 webViewHelper.reset(); 2896 2897 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size()); 2898 ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0]; 2899 ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1]; 2900 2901 ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification)); 2902 ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification)); 2903 } 2904 2905 TEST_F(WebFrameTest, ContextNotificationsReload) 2906 { 2907 v8::HandleScope handleScope(v8::Isolate::GetCurrent()); 2908 2909 registerMockedHttpURLLoad("context_notifications_test.html"); 2910 registerMockedHttpURLLoad("context_notifications_test_frame.html"); 2911 2912 ContextLifetimeTestWebFrameClient webFrameClient; 2913 FrameTestHelpers::WebViewHelper webViewHelper; 2914 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient); 2915 2916 // Refresh, we should get two release notifications and two more create notifications. 2917 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame()); 2918 ASSERT_EQ(4u, webFrameClient.createNotifications.size()); 2919 ASSERT_EQ(2u, webFrameClient.releaseNotifications.size()); 2920 2921 // The two release notifications we got should be exactly the same as the first two create notifications. 2922 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) { 2923 EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals( 2924 webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i])); 2925 } 2926 2927 // The last two create notifications should be for the current frames and context. 2928 WebFrame* mainFrame = webViewHelper.webView()->mainFrame(); 2929 WebFrame* childFrame = mainFrame->firstChild(); 2930 ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2]; 2931 ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3]; 2932 2933 EXPECT_EQ(mainFrame, firstRefreshNotification->frame); 2934 EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context); 2935 EXPECT_EQ(0, firstRefreshNotification->worldId); 2936 2937 EXPECT_EQ(childFrame, secondRefreshNotification->frame); 2938 EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context); 2939 EXPECT_EQ(0, secondRefreshNotification->worldId); 2940 } 2941 2942 TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds) 2943 { 2944 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 2945 v8::HandleScope handleScope(isolate); 2946 2947 registerMockedHttpURLLoad("context_notifications_test.html"); 2948 registerMockedHttpURLLoad("context_notifications_test_frame.html"); 2949 2950 ContextLifetimeTestWebFrameClient webFrameClient; 2951 FrameTestHelpers::WebViewHelper webViewHelper; 2952 webViewHelper.initializeAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient); 2953 2954 // Add an isolated world. 2955 webFrameClient.reset(); 2956 2957 int isolatedWorldId = 42; 2958 WebScriptSource scriptSource("hi!"); 2959 int numSources = 1; 2960 int extensionGroup = 0; 2961 webViewHelper.webView()->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup); 2962 2963 // We should now have a new create notification. 2964 ASSERT_EQ(1u, webFrameClient.createNotifications.size()); 2965 ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0]; 2966 ASSERT_EQ(isolatedWorldId, notification->worldId); 2967 ASSERT_EQ(webViewHelper.webView()->mainFrame(), notification->frame); 2968 2969 // We don't have an API to enumarate isolated worlds for a frame, but we can at least assert that the context we got is *not* the main world's context. 2970 ASSERT_NE(webViewHelper.webView()->mainFrame()->mainWorldScriptContext(), v8::Local<v8::Context>::New(isolate, notification->context)); 2971 2972 webViewHelper.reset(); 2973 2974 // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context). 2975 ASSERT_EQ(3u, webFrameClient.releaseNotifications.size()); 2976 2977 // And one of them should be exactly the same as the create notification for the isolated context. 2978 int matchCount = 0; 2979 for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) { 2980 if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0])) 2981 ++matchCount; 2982 } 2983 EXPECT_EQ(1, matchCount); 2984 } 2985 2986 TEST_F(WebFrameTest, FindInPage) 2987 { 2988 registerMockedHttpURLLoad("find.html"); 2989 FrameTestHelpers::WebViewHelper webViewHelper; 2990 webViewHelper.initializeAndLoad(m_baseURL + "find.html"); 2991 WebFrame* frame = webViewHelper.webView()->mainFrame(); 2992 const int findIdentifier = 12345; 2993 WebFindOptions options; 2994 2995 // Find in a <div> element. 2996 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0)); 2997 frame->stopFinding(false); 2998 WebRange range = frame->selectionRange(); 2999 EXPECT_EQ(5, range.startOffset()); 3000 EXPECT_EQ(9, range.endOffset()); 3001 EXPECT_TRUE(frame->document().focusedElement().isNull()); 3002 3003 // Find in an <input> value. 3004 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0)); 3005 // Confirm stopFinding(false) sets the selection on the found text. 3006 frame->stopFinding(false); 3007 range = frame->selectionRange(); 3008 ASSERT_FALSE(range.isNull()); 3009 EXPECT_EQ(5, range.startOffset()); 3010 EXPECT_EQ(9, range.endOffset()); 3011 EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedElement().tagName()); 3012 3013 // Find in a <textarea> content. 3014 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0)); 3015 // Confirm stopFinding(false) sets the selection on the found text. 3016 frame->stopFinding(false); 3017 range = frame->selectionRange(); 3018 ASSERT_FALSE(range.isNull()); 3019 EXPECT_EQ(5, range.startOffset()); 3020 EXPECT_EQ(9, range.endOffset()); 3021 EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedElement().tagName()); 3022 3023 // Find in a contentEditable element. 3024 EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0)); 3025 // Confirm stopFinding(false) sets the selection on the found text. 3026 frame->stopFinding(false); 3027 range = frame->selectionRange(); 3028 ASSERT_FALSE(range.isNull()); 3029 EXPECT_EQ(0, range.startOffset()); 3030 EXPECT_EQ(4, range.endOffset()); 3031 // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>. 3032 EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedElement().tagName()); 3033 3034 // Find in <select> content. 3035 EXPECT_FALSE(frame->find(findIdentifier, WebString::fromUTF8("bar5"), options, false, 0)); 3036 // If there are any matches, stopFinding will set the selection on the found text. 3037 // However, we do not expect any matches, so check that the selection is null. 3038 frame->stopFinding(false); 3039 range = frame->selectionRange(); 3040 ASSERT_TRUE(range.isNull()); 3041 } 3042 3043 TEST_F(WebFrameTest, GetContentAsPlainText) 3044 { 3045 FrameTestHelpers::WebViewHelper webViewHelper; 3046 webViewHelper.initializeAndLoad("about:blank", true); 3047 // We set the size because it impacts line wrapping, which changes the 3048 // resulting text value. 3049 webViewHelper.webView()->resize(WebSize(640, 480)); 3050 WebFrame* frame = webViewHelper.webView()->mainFrame(); 3051 3052 // Generate a simple test case. 3053 const char simpleSource[] = "<div>Foo bar</div><div></div>baz"; 3054 KURL testURL = toKURL("about:blank"); 3055 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL); 3056 3057 // Make sure it comes out OK. 3058 const std::string expected("Foo bar\nbaz"); 3059 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max()); 3060 EXPECT_EQ(expected, text.utf8()); 3061 3062 // Try reading the same one with clipping of the text. 3063 const int length = 5; 3064 text = frame->contentAsText(length); 3065 EXPECT_EQ(expected.substr(0, length), text.utf8()); 3066 3067 // Now do a new test with a subframe. 3068 const char outerFrameSource[] = "Hello<iframe></iframe> world"; 3069 FrameTestHelpers::loadHTMLString(frame, outerFrameSource, testURL); 3070 3071 // Load something into the subframe. 3072 WebFrame* subframe = frame->firstChild(); 3073 ASSERT_TRUE(subframe); 3074 FrameTestHelpers::loadHTMLString(subframe, "sub<p>text", testURL); 3075 3076 text = frame->contentAsText(std::numeric_limits<size_t>::max()); 3077 EXPECT_EQ("Hello world\n\nsub\ntext", text.utf8()); 3078 3079 // Get the frame text where the subframe separator falls on the boundary of 3080 // what we'll take. There used to be a crash in this case. 3081 text = frame->contentAsText(12); 3082 EXPECT_EQ("Hello world", text.utf8()); 3083 } 3084 3085 TEST_F(WebFrameTest, GetFullHtmlOfPage) 3086 { 3087 FrameTestHelpers::WebViewHelper webViewHelper; 3088 webViewHelper.initializeAndLoad("about:blank", true); 3089 WebFrame* frame = webViewHelper.webView()->mainFrame(); 3090 3091 // Generate a simple test case. 3092 const char simpleSource[] = "<p>Hello</p><p>World</p>"; 3093 KURL testURL = toKURL("about:blank"); 3094 FrameTestHelpers::loadHTMLString(frame, simpleSource, testURL); 3095 3096 WebString text = frame->contentAsText(std::numeric_limits<size_t>::max()); 3097 EXPECT_EQ("Hello\n\nWorld", text.utf8()); 3098 3099 const std::string html = frame->contentAsMarkup().utf8(); 3100 3101 // Load again with the output html. 3102 FrameTestHelpers::loadHTMLString(frame, html, testURL); 3103 3104 EXPECT_EQ(html, frame->contentAsMarkup().utf8()); 3105 3106 text = frame->contentAsText(std::numeric_limits<size_t>::max()); 3107 EXPECT_EQ("Hello\n\nWorld", text.utf8()); 3108 3109 // Test selection check 3110 EXPECT_FALSE(frame->hasSelection()); 3111 frame->executeCommand(WebString::fromUTF8("SelectAll")); 3112 EXPECT_TRUE(frame->hasSelection()); 3113 frame->executeCommand(WebString::fromUTF8("Unselect")); 3114 EXPECT_FALSE(frame->hasSelection()); 3115 WebString selectionHtml = frame->selectionAsMarkup(); 3116 EXPECT_TRUE(selectionHtml.isEmpty()); 3117 } 3118 3119 class TestExecuteScriptDuringDidCreateScriptContext : public FrameTestHelpers::TestWebFrameClient { 3120 public: 3121 virtual void didCreateScriptContext(WebLocalFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE 3122 { 3123 frame->executeScript(WebScriptSource("window.history = 'replaced';")); 3124 } 3125 }; 3126 3127 TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext) 3128 { 3129 registerMockedHttpURLLoad("hello_world.html"); 3130 3131 TestExecuteScriptDuringDidCreateScriptContext webFrameClient; 3132 FrameTestHelpers::WebViewHelper webViewHelper; 3133 webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient); 3134 3135 FrameTestHelpers::reloadFrame(webViewHelper.webView()->mainFrame()); 3136 } 3137 3138 class FindUpdateWebFrameClient : public FrameTestHelpers::TestWebFrameClient { 3139 public: 3140 FindUpdateWebFrameClient() 3141 : m_findResultsAreReady(false) 3142 , m_count(-1) 3143 { 3144 } 3145 3146 virtual void reportFindInPageMatchCount(int, int count, bool finalUpdate) OVERRIDE 3147 { 3148 m_count = count; 3149 if (finalUpdate) 3150 m_findResultsAreReady = true; 3151 } 3152 3153 bool findResultsAreReady() const { return m_findResultsAreReady; } 3154 int count() const { return m_count; } 3155 3156 private: 3157 bool m_findResultsAreReady; 3158 int m_count; 3159 }; 3160 3161 // This fails on Mac https://bugs.webkit.org/show_bug.cgi?id=108574 3162 // Also failing on Android: http://crbug.com/341314 3163 #if OS(MACOSX) || OS(ANDROID) 3164 TEST_F(WebFrameTest, DISABLED_FindInPageMatchRects) 3165 #else 3166 TEST_F(WebFrameTest, FindInPageMatchRects) 3167 #endif 3168 { 3169 registerMockedHttpURLLoad("find_in_page.html"); 3170 registerMockedHttpURLLoad("find_in_page_frame.html"); 3171 3172 FindUpdateWebFrameClient client; 3173 FrameTestHelpers::WebViewHelper webViewHelper; 3174 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client); 3175 webViewHelper.webView()->resize(WebSize(640, 480)); 3176 webViewHelper.webView()->layout(); 3177 runPendingTasks(); 3178 3179 // Note that the 'result 19' in the <select> element is not expected to produce a match. 3180 static const char* kFindString = "result"; 3181 static const int kFindIdentifier = 12345; 3182 static const int kNumResults = 19; 3183 3184 WebFindOptions options; 3185 WebString searchText = WebString::fromUTF8(kFindString); 3186 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3187 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0)); 3188 3189 mainFrame->resetMatchCount(); 3190 3191 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3192 frame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3193 3194 runPendingTasks(); 3195 EXPECT_TRUE(client.findResultsAreReady()); 3196 3197 WebVector<WebFloatRect> webMatchRects; 3198 mainFrame->findMatchRects(webMatchRects); 3199 ASSERT_EQ(webMatchRects.size(), static_cast<size_t>(kNumResults)); 3200 int rectsVersion = mainFrame->findMatchMarkersVersion(); 3201 3202 for (int resultIndex = 0; resultIndex < kNumResults; ++resultIndex) { 3203 FloatRect resultRect = static_cast<FloatRect>(webMatchRects[resultIndex]); 3204 3205 // Select the match by the center of its rect. 3206 EXPECT_EQ(mainFrame->selectNearestFindMatch(resultRect.center(), 0), resultIndex + 1); 3207 3208 // Check that the find result ordering matches with our expectations. 3209 Range* result = mainFrame->activeMatchFrame()->activeMatch(); 3210 ASSERT_TRUE(result); 3211 result->setEnd(result->endContainer(), result->endOffset() + 3); 3212 EXPECT_EQ(result->text(), String::format("%s %02d", kFindString, resultIndex)); 3213 3214 // Verify that the expected match rect also matches the currently active match. 3215 // Compare the enclosing rects to prevent precision issues caused by CSS transforms. 3216 FloatRect activeMatch = mainFrame->activeFindMatchRect(); 3217 EXPECT_EQ(enclosingIntRect(activeMatch), enclosingIntRect(resultRect)); 3218 3219 // The rects version should not have changed. 3220 EXPECT_EQ(mainFrame->findMatchMarkersVersion(), rectsVersion); 3221 } 3222 3223 // All results after the first two ones should be below between them in find-in-page coordinates. 3224 // This is because results 2 to 9 are inside an iframe located between results 0 and 1. This applies to the fixed div too. 3225 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[1].y); 3226 for (int resultIndex = 2; resultIndex < kNumResults; ++resultIndex) { 3227 EXPECT_TRUE(webMatchRects[0].y < webMatchRects[resultIndex].y); 3228 EXPECT_TRUE(webMatchRects[1].y > webMatchRects[resultIndex].y); 3229 } 3230 3231 // Result 3 should be below both 2 and 4. This is caused by the CSS transform in the containing div. 3232 // If the transform doesn't work then 3 will be between 2 and 4. 3233 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[2].y); 3234 EXPECT_TRUE(webMatchRects[3].y > webMatchRects[4].y); 3235 3236 // Results 6, 7, 8 and 9 should be one below the other in that same order. 3237 // If overflow:scroll is not properly handled then result 8 would be below result 9 or 3238 // result 7 above result 6 depending on the scroll. 3239 EXPECT_TRUE(webMatchRects[6].y < webMatchRects[7].y); 3240 EXPECT_TRUE(webMatchRects[7].y < webMatchRects[8].y); 3241 EXPECT_TRUE(webMatchRects[8].y < webMatchRects[9].y); 3242 3243 // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are inside the table. 3244 EXPECT_TRUE(webMatchRects[11].y > webMatchRects[10].y); 3245 EXPECT_TRUE(webMatchRects[12].y > webMatchRects[10].y); 3246 EXPECT_TRUE(webMatchRects[13].y > webMatchRects[10].y); 3247 EXPECT_TRUE(webMatchRects[14].y > webMatchRects[10].y); 3248 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[15].y); 3249 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[15].y); 3250 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[15].y); 3251 EXPECT_TRUE(webMatchRects[14].y < webMatchRects[15].y); 3252 3253 // Result 11 should be above 12, 13 and 14 as it's in the table header. 3254 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[12].y); 3255 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[13].y); 3256 EXPECT_TRUE(webMatchRects[11].y < webMatchRects[14].y); 3257 3258 // Result 11 should also be right to 12, 13 and 14 because of the colspan. 3259 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[12].x); 3260 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[13].x); 3261 EXPECT_TRUE(webMatchRects[11].x > webMatchRects[14].x); 3262 3263 // Result 12 should be left to results 11, 13 and 14 in the table layout. 3264 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[11].x); 3265 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[13].x); 3266 EXPECT_TRUE(webMatchRects[12].x < webMatchRects[14].x); 3267 3268 // Results 13, 12 and 14 should be one above the other in that order because of the rowspan 3269 // and vertical-align: middle by default. 3270 EXPECT_TRUE(webMatchRects[13].y < webMatchRects[12].y); 3271 EXPECT_TRUE(webMatchRects[12].y < webMatchRects[14].y); 3272 3273 // Result 16 should be below result 15. 3274 EXPECT_TRUE(webMatchRects[15].y > webMatchRects[14].y); 3275 3276 // Result 18 should be normalized with respect to the position:relative div, and not it's 3277 // immediate containing div. Consequently, result 18 should be above result 17. 3278 EXPECT_TRUE(webMatchRects[17].y > webMatchRects[18].y); 3279 3280 // Resizing should update the rects version. 3281 webViewHelper.webView()->resize(WebSize(800, 600)); 3282 runPendingTasks(); 3283 EXPECT_TRUE(mainFrame->findMatchMarkersVersion() != rectsVersion); 3284 } 3285 3286 TEST_F(WebFrameTest, FindInPageSkipsHiddenFrames) 3287 { 3288 registerMockedHttpURLLoad("find_in_hidden_frame.html"); 3289 3290 FindUpdateWebFrameClient client; 3291 FrameTestHelpers::WebViewHelper webViewHelper; 3292 webViewHelper.initializeAndLoad(m_baseURL + "find_in_hidden_frame.html", true, &client); 3293 webViewHelper.webView()->resize(WebSize(640, 480)); 3294 webViewHelper.webView()->layout(); 3295 runPendingTasks(); 3296 3297 static const char* kFindString = "hello"; 3298 static const int kFindIdentifier = 12345; 3299 static const int kNumResults = 1; 3300 3301 WebFindOptions options; 3302 WebString searchText = WebString::fromUTF8(kFindString); 3303 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3304 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0)); 3305 3306 mainFrame->resetMatchCount(); 3307 3308 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3309 frame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3310 3311 runPendingTasks(); 3312 EXPECT_TRUE(client.findResultsAreReady()); 3313 EXPECT_EQ(kNumResults, client.count()); 3314 } 3315 3316 TEST_F(WebFrameTest, FindOnDetachedFrame) 3317 { 3318 registerMockedHttpURLLoad("find_in_page.html"); 3319 registerMockedHttpURLLoad("find_in_page_frame.html"); 3320 3321 FindUpdateWebFrameClient client; 3322 FrameTestHelpers::WebViewHelper webViewHelper; 3323 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client); 3324 webViewHelper.webView()->resize(WebSize(640, 480)); 3325 webViewHelper.webView()->layout(); 3326 runPendingTasks(); 3327 3328 static const char* kFindString = "result"; 3329 static const int kFindIdentifier = 12345; 3330 3331 WebFindOptions options; 3332 WebString searchText = WebString::fromUTF8(kFindString); 3333 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3334 RefPtrWillBeRawPtr<WebLocalFrameImpl> secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false)); 3335 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame()); 3336 3337 // Detach the frame before finding. 3338 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove()); 3339 3340 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0)); 3341 EXPECT_FALSE(secondFrame->find(kFindIdentifier, searchText, options, false, 0)); 3342 3343 runPendingTasks(); 3344 EXPECT_FALSE(client.findResultsAreReady()); 3345 3346 mainFrame->resetMatchCount(); 3347 3348 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3349 frame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3350 3351 runPendingTasks(); 3352 EXPECT_TRUE(client.findResultsAreReady()); 3353 } 3354 3355 TEST_F(WebFrameTest, FindDetachFrameBeforeScopeStrings) 3356 { 3357 registerMockedHttpURLLoad("find_in_page.html"); 3358 registerMockedHttpURLLoad("find_in_page_frame.html"); 3359 3360 FindUpdateWebFrameClient client; 3361 FrameTestHelpers::WebViewHelper webViewHelper; 3362 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client); 3363 webViewHelper.webView()->resize(WebSize(640, 480)); 3364 webViewHelper.webView()->layout(); 3365 runPendingTasks(); 3366 3367 static const char* kFindString = "result"; 3368 static const int kFindIdentifier = 12345; 3369 3370 WebFindOptions options; 3371 WebString searchText = WebString::fromUTF8(kFindString); 3372 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3373 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false)); 3374 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame()); 3375 3376 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3377 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0)); 3378 3379 runPendingTasks(); 3380 EXPECT_FALSE(client.findResultsAreReady()); 3381 3382 // Detach the frame between finding and scoping. 3383 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove()); 3384 3385 mainFrame->resetMatchCount(); 3386 3387 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3388 frame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3389 3390 runPendingTasks(); 3391 EXPECT_TRUE(client.findResultsAreReady()); 3392 } 3393 3394 TEST_F(WebFrameTest, FindDetachFrameWhileScopingStrings) 3395 { 3396 registerMockedHttpURLLoad("find_in_page.html"); 3397 registerMockedHttpURLLoad("find_in_page_frame.html"); 3398 3399 FindUpdateWebFrameClient client; 3400 FrameTestHelpers::WebViewHelper webViewHelper; 3401 webViewHelper.initializeAndLoad(m_baseURL + "find_in_page.html", true, &client); 3402 webViewHelper.webView()->resize(WebSize(640, 480)); 3403 webViewHelper.webView()->layout(); 3404 runPendingTasks(); 3405 3406 static const char* kFindString = "result"; 3407 static const int kFindIdentifier = 12345; 3408 3409 WebFindOptions options; 3410 WebString searchText = WebString::fromUTF8(kFindString); 3411 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3412 WebLocalFrameImpl* secondFrame = toWebLocalFrameImpl(mainFrame->traverseNext(false)); 3413 RefPtrWillBeRawPtr<LocalFrame> holdSecondFrame(secondFrame->frame()); 3414 3415 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3416 EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0)); 3417 3418 runPendingTasks(); 3419 EXPECT_FALSE(client.findResultsAreReady()); 3420 3421 mainFrame->resetMatchCount(); 3422 3423 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) 3424 frame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3425 3426 // The first scopeStringMatches will have reset the state. Detach before it actually scopes. 3427 EXPECT_TRUE(mainFrame->document().getElementById("frame").remove()); 3428 3429 runPendingTasks(); 3430 EXPECT_TRUE(client.findResultsAreReady()); 3431 } 3432 3433 TEST_F(WebFrameTest, ResetMatchCount) 3434 { 3435 registerMockedHttpURLLoad("find_in_generated_frame.html"); 3436 3437 FindUpdateWebFrameClient client; 3438 FrameTestHelpers::WebViewHelper webViewHelper; 3439 webViewHelper.initializeAndLoad(m_baseURL + "find_in_generated_frame.html", true, &client); 3440 webViewHelper.webView()->resize(WebSize(640, 480)); 3441 webViewHelper.webView()->layout(); 3442 runPendingTasks(); 3443 3444 static const char* kFindString = "result"; 3445 static const int kFindIdentifier = 12345; 3446 3447 WebFindOptions options; 3448 WebString searchText = WebString::fromUTF8(kFindString); 3449 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3450 3451 // Check that child frame exists. 3452 EXPECT_TRUE(!!mainFrame->traverseNext(false)); 3453 3454 for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false)) { 3455 EXPECT_FALSE(frame->find(kFindIdentifier, searchText, options, false, 0)); 3456 } 3457 3458 runPendingTasks(); 3459 EXPECT_FALSE(client.findResultsAreReady()); 3460 3461 mainFrame->resetMatchCount(); 3462 } 3463 3464 TEST_F(WebFrameTest, SetTickmarks) 3465 { 3466 registerMockedHttpURLLoad("find.html"); 3467 3468 FindUpdateWebFrameClient client; 3469 FrameTestHelpers::WebViewHelper webViewHelper; 3470 webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client); 3471 webViewHelper.webView()->resize(WebSize(640, 480)); 3472 webViewHelper.webView()->layout(); 3473 runPendingTasks(); 3474 3475 static const char* kFindString = "foo"; 3476 static const int kFindIdentifier = 12345; 3477 3478 WebFindOptions options; 3479 WebString searchText = WebString::fromUTF8(kFindString); 3480 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3481 EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0)); 3482 3483 mainFrame->resetMatchCount(); 3484 mainFrame->scopeStringMatches(kFindIdentifier, searchText, options, true); 3485 3486 runPendingTasks(); 3487 EXPECT_TRUE(client.findResultsAreReady()); 3488 3489 // Get the tickmarks for the original find request. 3490 FrameView* frameView = webViewHelper.webViewImpl()->mainFrameImpl()->frameView(); 3491 RefPtr<Scrollbar> scrollbar = frameView->createScrollbar(HorizontalScrollbar); 3492 Vector<IntRect> originalTickmarks; 3493 scrollbar->getTickmarks(originalTickmarks); 3494 EXPECT_EQ(4u, originalTickmarks.size()); 3495 3496 // Override the tickmarks. 3497 Vector<IntRect> overridingTickmarksExpected; 3498 overridingTickmarksExpected.append(IntRect(0, 0, 100, 100)); 3499 overridingTickmarksExpected.append(IntRect(0, 20, 100, 100)); 3500 overridingTickmarksExpected.append(IntRect(0, 30, 100, 100)); 3501 mainFrame->setTickmarks(overridingTickmarksExpected); 3502 3503 // Check the tickmarks are overriden correctly. 3504 Vector<IntRect> overridingTickmarksActual; 3505 scrollbar->getTickmarks(overridingTickmarksActual); 3506 EXPECT_EQ(overridingTickmarksExpected, overridingTickmarksActual); 3507 3508 // Reset the tickmark behavior. 3509 Vector<IntRect> resetTickmarks; 3510 mainFrame->setTickmarks(resetTickmarks); 3511 3512 // Check that the original tickmarks are returned 3513 Vector<IntRect> originalTickmarksAfterReset; 3514 scrollbar->getTickmarks(originalTickmarksAfterReset); 3515 EXPECT_EQ(originalTickmarks, originalTickmarksAfterReset); 3516 } 3517 3518 static WebPoint topLeft(const WebRect& rect) 3519 { 3520 return WebPoint(rect.x, rect.y); 3521 } 3522 3523 static WebPoint bottomRightMinusOne(const WebRect& rect) 3524 { 3525 // FIXME: If we don't subtract 1 from the x- and y-coordinates of the 3526 // selection bounds, selectRange() will select the *next* element. That's 3527 // strictly correct, as hit-testing checks the pixel to the lower-right of 3528 // the input coordinate, but it's a wart on the API. 3529 return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1); 3530 } 3531 3532 static WebRect elementBounds(WebFrame* frame, const WebString& id) 3533 { 3534 return frame->document().getElementById(id).boundsInViewportSpace(); 3535 } 3536 3537 static std::string selectionAsString(WebFrame* frame) 3538 { 3539 return frame->selectionAsText().utf8(); 3540 } 3541 3542 TEST_F(WebFrameTest, SelectRange) 3543 { 3544 WebFrame* frame; 3545 WebRect startWebRect; 3546 WebRect endWebRect; 3547 3548 registerMockedHttpURLLoad("select_range_basic.html"); 3549 registerMockedHttpURLLoad("select_range_scroll.html"); 3550 3551 FrameTestHelpers::WebViewHelper webViewHelper; 3552 initializeTextSelectionWebView(m_baseURL + "select_range_basic.html", &webViewHelper); 3553 frame = webViewHelper.webView()->mainFrame(); 3554 EXPECT_EQ("Some test text for testing.", selectionAsString(frame)); 3555 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3556 frame->executeCommand(WebString::fromUTF8("Unselect")); 3557 EXPECT_EQ("", selectionAsString(frame)); 3558 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect)); 3559 EXPECT_EQ("Some test text for testing.", selectionAsString(frame)); 3560 3561 initializeTextSelectionWebView(m_baseURL + "select_range_scroll.html", &webViewHelper); 3562 frame = webViewHelper.webView()->mainFrame(); 3563 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame)); 3564 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3565 frame->executeCommand(WebString::fromUTF8("Unselect")); 3566 EXPECT_EQ("", selectionAsString(frame)); 3567 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect)); 3568 EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame)); 3569 } 3570 3571 TEST_F(WebFrameTest, SelectRangeInIframe) 3572 { 3573 WebFrame* frame; 3574 WebRect startWebRect; 3575 WebRect endWebRect; 3576 3577 registerMockedHttpURLLoad("select_range_iframe.html"); 3578 registerMockedHttpURLLoad("select_range_basic.html"); 3579 3580 FrameTestHelpers::WebViewHelper webViewHelper; 3581 initializeTextSelectionWebView(m_baseURL + "select_range_iframe.html", &webViewHelper); 3582 frame = webViewHelper.webView()->mainFrame(); 3583 WebFrame* subframe = frame->firstChild(); 3584 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe)); 3585 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3586 subframe->executeCommand(WebString::fromUTF8("Unselect")); 3587 EXPECT_EQ("", selectionAsString(subframe)); 3588 subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect)); 3589 EXPECT_EQ("Some test text for testing.", selectionAsString(subframe)); 3590 } 3591 3592 TEST_F(WebFrameTest, SelectRangeDivContentEditable) 3593 { 3594 WebFrame* frame; 3595 WebRect startWebRect; 3596 WebRect endWebRect; 3597 3598 registerMockedHttpURLLoad("select_range_div_editable.html"); 3599 3600 // Select the middle of an editable element, then try to extend the selection to the top of the document. 3601 // The selection range should be clipped to the bounds of the editable element. 3602 FrameTestHelpers::WebViewHelper webViewHelper; 3603 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper); 3604 frame = webViewHelper.webView()->mainFrame(); 3605 EXPECT_EQ("This text is initially selected.", selectionAsString(frame)); 3606 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3607 3608 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0)); 3609 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame)); 3610 3611 // As above, but extending the selection to the bottom of the document. 3612 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper); 3613 frame = webViewHelper.webView()->mainFrame(); 3614 3615 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3616 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect)); 3617 EXPECT_EQ("This text is initially selected.", selectionAsString(frame)); 3618 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3619 3620 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3621 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480)); 3622 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame)); 3623 } 3624 3625 // positionForPoint returns the wrong values for contenteditable spans. See 3626 // http://crbug.com/238334. 3627 TEST_F(WebFrameTest, DISABLED_SelectRangeSpanContentEditable) 3628 { 3629 WebFrame* frame; 3630 WebRect startWebRect; 3631 WebRect endWebRect; 3632 3633 registerMockedHttpURLLoad("select_range_span_editable.html"); 3634 3635 // Select the middle of an editable element, then try to extend the selection to the top of the document. 3636 // The selection range should be clipped to the bounds of the editable element. 3637 FrameTestHelpers::WebViewHelper webViewHelper; 3638 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper); 3639 frame = webViewHelper.webView()->mainFrame(); 3640 EXPECT_EQ("This text is initially selected.", selectionAsString(frame)); 3641 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3642 3643 frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0)); 3644 EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame)); 3645 3646 // As above, but extending the selection to the bottom of the document. 3647 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper); 3648 frame = webViewHelper.webView()->mainFrame(); 3649 3650 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3651 frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect)); 3652 EXPECT_EQ("This text is initially selected.", selectionAsString(frame)); 3653 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3654 3655 EXPECT_EQ("This text is initially selected.", selectionAsString(frame)); 3656 webViewHelper.webView()->selectionBounds(startWebRect, endWebRect); 3657 frame->selectRange(topLeft(startWebRect), WebPoint(640, 480)); 3658 EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame)); 3659 } 3660 3661 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart) 3662 { 3663 registerMockedHttpURLLoad("text_selection.html"); 3664 FrameTestHelpers::WebViewHelper webViewHelper; 3665 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper); 3666 WebFrame* frame = webViewHelper.webView()->mainFrame(); 3667 3668 // Select second span. We can move the start to include the first span. 3669 frame->executeScript(WebScriptSource("selectElement('header_2');")); 3670 EXPECT_EQ("Header 2.", selectionAsString(frame)); 3671 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1"))); 3672 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame)); 3673 3674 // We can move the start and end together. 3675 frame->executeScript(WebScriptSource("selectElement('header_1');")); 3676 EXPECT_EQ("Header 1.", selectionAsString(frame)); 3677 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1"))); 3678 EXPECT_EQ("", selectionAsString(frame)); 3679 // Selection is a caret, not empty. 3680 EXPECT_FALSE(frame->selectionRange().isNull()); 3681 3682 // We can move the start across the end. 3683 frame->executeScript(WebScriptSource("selectElement('header_1');")); 3684 EXPECT_EQ("Header 1.", selectionAsString(frame)); 3685 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2"))); 3686 EXPECT_EQ(" Header 2.", selectionAsString(frame)); 3687 3688 // Can't extend the selection part-way into an editable element. 3689 frame->executeScript(WebScriptSource("selectElement('footer_2');")); 3690 EXPECT_EQ("Footer 2.", selectionAsString(frame)); 3691 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2"))); 3692 EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame)); 3693 3694 // Can extend the selection completely across editable elements. 3695 frame->executeScript(WebScriptSource("selectElement('footer_2');")); 3696 EXPECT_EQ("Footer 2.", selectionAsString(frame)); 3697 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2"))); 3698 EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame)); 3699 3700 // If the selection is editable text, we can't extend it into non-editable text. 3701 frame->executeScript(WebScriptSource("selectElement('editable_2');")); 3702 EXPECT_EQ("Editable 2.", selectionAsString(frame)); 3703 frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2"))); 3704 // positionForPoint returns the wrong values for contenteditable spans. See 3705 // http://crbug.com/238334. 3706 // EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame)); 3707 } 3708 3709 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd) 3710 { 3711 registerMockedHttpURLLoad("text_selection.html"); 3712 FrameTestHelpers::WebViewHelper webViewHelper; 3713 initializeTextSelectionWebView(m_baseURL + "text_selection.html", &webViewHelper); 3714 WebFrame* frame = webViewHelper.webView()->mainFrame(); 3715 3716 // Select first span. We can move the end to include the second span. 3717 frame->executeScript(WebScriptSource("selectElement('header_1');")); 3718 EXPECT_EQ("Header 1.", selectionAsString(frame)); 3719 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2"))); 3720 EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame)); 3721 3722 // We can move the start and end together. 3723 frame->executeScript(WebScriptSource("selectElement('header_2');")); 3724 EXPECT_EQ("Header 2.", selectionAsString(frame)); 3725 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2"))); 3726 EXPECT_EQ("", selectionAsString(frame)); 3727 // Selection is a caret, not empty. 3728 EXPECT_FALSE(frame->selectionRange().isNull()); 3729 3730 // We can move the end across the start. 3731 frame->executeScript(WebScriptSource("selectElement('header_2');")); 3732 EXPECT_EQ("Header 2.", selectionAsString(frame)); 3733 frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1"))); 3734 EXPECT_EQ("Header 1. ", selectionAsString(frame)); 3735 3736 // Can't extend the selection part-way into an editable element. 3737 frame->executeScript(WebScriptSource("selectElement('header_1');")); 3738 EXPECT_EQ("Header 1.", selectionAsString(frame)); 3739 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1"))); 3740 EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame)); 3741 3742 // Can extend the selection completely across editable elements. 3743 frame->executeScript(WebScriptSource("selectElement('header_1');")); 3744 EXPECT_EQ("Header 1.", selectionAsString(frame)); 3745 frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1"))); 3746 EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame)); 3747 3748 // If the selection is editable text, we can't extend it into non-editable text. 3749 frame->executeScript(WebScriptSource("selectElement('editable_1');")); 3750 EXPECT_EQ("Editable 1.", selectionAsString(frame)); 3751 frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1"))); 3752 // positionForPoint returns the wrong values for contenteditable spans. See 3753 // http://crbug.com/238334. 3754 // EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame)); 3755 } 3756 3757 static int computeOffset(RenderObject* renderer, int x, int y) 3758 { 3759 return VisiblePosition(renderer->positionForPoint(LayoutPoint(x, y))).deepEquivalent().computeOffsetInContainerNode(); 3760 } 3761 3762 // positionForPoint returns the wrong values for contenteditable spans. See 3763 // http://crbug.com/238334. 3764 TEST_F(WebFrameTest, DISABLED_PositionForPointTest) 3765 { 3766 registerMockedHttpURLLoad("select_range_span_editable.html"); 3767 FrameTestHelpers::WebViewHelper webViewHelper; 3768 initializeTextSelectionWebView(m_baseURL + "select_range_span_editable.html", &webViewHelper); 3769 WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3770 RenderObject* renderer = mainFrame->frame()->selection().rootEditableElement()->renderer(); 3771 EXPECT_EQ(0, computeOffset(renderer, -1, -1)); 3772 EXPECT_EQ(64, computeOffset(renderer, 1000, 1000)); 3773 3774 registerMockedHttpURLLoad("select_range_div_editable.html"); 3775 initializeTextSelectionWebView(m_baseURL + "select_range_div_editable.html", &webViewHelper); 3776 mainFrame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3777 renderer = mainFrame->frame()->selection().rootEditableElement()->renderer(); 3778 EXPECT_EQ(0, computeOffset(renderer, -1, -1)); 3779 EXPECT_EQ(64, computeOffset(renderer, 1000, 1000)); 3780 } 3781 3782 #if !OS(MACOSX) && !OS(LINUX) 3783 TEST_F(WebFrameTest, SelectRangeStaysHorizontallyAlignedWhenMoved) 3784 { 3785 registerMockedHttpURLLoad("move_caret.html"); 3786 3787 FrameTestHelpers::WebViewHelper webViewHelper; 3788 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper); 3789 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewHelper.webView()->mainFrame()); 3790 3791 WebRect initialStartRect; 3792 WebRect initialEndRect; 3793 WebRect startRect; 3794 WebRect endRect; 3795 3796 frame->executeScript(WebScriptSource("selectRange();")); 3797 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect); 3798 WebPoint movedStart(topLeft(initialStartRect)); 3799 3800 movedStart.y += 40; 3801 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect)); 3802 webViewHelper.webView()->selectionBounds(startRect, endRect); 3803 EXPECT_EQ(startRect, initialStartRect); 3804 EXPECT_EQ(endRect, initialEndRect); 3805 3806 movedStart.y -= 80; 3807 frame->selectRange(movedStart, bottomRightMinusOne(initialEndRect)); 3808 webViewHelper.webView()->selectionBounds(startRect, endRect); 3809 EXPECT_EQ(startRect, initialStartRect); 3810 EXPECT_EQ(endRect, initialEndRect); 3811 3812 WebPoint movedEnd(bottomRightMinusOne(initialEndRect)); 3813 3814 movedEnd.y += 40; 3815 frame->selectRange(topLeft(initialStartRect), movedEnd); 3816 webViewHelper.webView()->selectionBounds(startRect, endRect); 3817 EXPECT_EQ(startRect, initialStartRect); 3818 EXPECT_EQ(endRect, initialEndRect); 3819 3820 movedEnd.y -= 80; 3821 frame->selectRange(topLeft(initialStartRect), movedEnd); 3822 webViewHelper.webView()->selectionBounds(startRect, endRect); 3823 EXPECT_EQ(startRect, initialStartRect); 3824 EXPECT_EQ(endRect, initialEndRect); 3825 } 3826 3827 TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved) 3828 { 3829 WebLocalFrameImpl* frame; 3830 registerMockedHttpURLLoad("move_caret.html"); 3831 3832 FrameTestHelpers::WebViewHelper webViewHelper; 3833 initializeTextSelectionWebView(m_baseURL + "move_caret.html", &webViewHelper); 3834 frame = (WebLocalFrameImpl*)webViewHelper.webView()->mainFrame(); 3835 3836 WebRect initialStartRect; 3837 WebRect initialEndRect; 3838 WebRect startRect; 3839 WebRect endRect; 3840 3841 frame->executeScript(WebScriptSource("selectCaret();")); 3842 webViewHelper.webView()->selectionBounds(initialStartRect, initialEndRect); 3843 WebPoint moveTo(topLeft(initialStartRect)); 3844 3845 moveTo.y += 40; 3846 frame->moveCaretSelection(moveTo); 3847 webViewHelper.webView()->selectionBounds(startRect, endRect); 3848 EXPECT_EQ(startRect, initialStartRect); 3849 EXPECT_EQ(endRect, initialEndRect); 3850 3851 moveTo.y -= 80; 3852 frame->moveCaretSelection(moveTo); 3853 webViewHelper.webView()->selectionBounds(startRect, endRect); 3854 EXPECT_EQ(startRect, initialStartRect); 3855 EXPECT_EQ(endRect, initialEndRect); 3856 } 3857 #endif 3858 3859 class CompositedSelectionBoundsTestLayerTreeView : public WebLayerTreeView { 3860 public: 3861 CompositedSelectionBoundsTestLayerTreeView() : m_selectionCleared(false) { } 3862 virtual ~CompositedSelectionBoundsTestLayerTreeView() { } 3863 3864 virtual void setSurfaceReady() OVERRIDE { } 3865 virtual void setRootLayer(const WebLayer&) OVERRIDE { } 3866 virtual void clearRootLayer() OVERRIDE { } 3867 virtual void setViewportSize(const WebSize& deviceViewportSize) OVERRIDE { } 3868 virtual WebSize deviceViewportSize() const OVERRIDE { return WebSize(); } 3869 virtual void setDeviceScaleFactor(float) OVERRIDE { } 3870 virtual float deviceScaleFactor() const OVERRIDE { return 1.f; } 3871 virtual void setBackgroundColor(WebColor) OVERRIDE { } 3872 virtual void setHasTransparentBackground(bool) OVERRIDE { } 3873 virtual void setVisible(bool) OVERRIDE { } 3874 virtual void setPageScaleFactorAndLimits(float pageScaleFactor, float minimum, float maximum) OVERRIDE { } 3875 virtual void startPageScaleAnimation(const WebPoint& destination, bool useAnchor, float newPageScale, double durationSec) OVERRIDE { } 3876 virtual void setNeedsAnimate() OVERRIDE { } 3877 virtual bool commitRequested() const OVERRIDE { return false; } 3878 virtual void finishAllRendering() OVERRIDE { } 3879 virtual void registerSelection(const WebSelectionBound& start, const WebSelectionBound& end) OVERRIDE 3880 { 3881 m_start = adoptPtr(new WebSelectionBound(start)); 3882 m_end = adoptPtr(new WebSelectionBound(end)); 3883 } 3884 virtual void clearSelection() OVERRIDE 3885 { 3886 m_selectionCleared = true; 3887 m_start.clear(); 3888 m_end.clear(); 3889 } 3890 3891 bool getAndResetSelectionCleared() 3892 { 3893 bool selectionCleared = m_selectionCleared; 3894 m_selectionCleared = false; 3895 return selectionCleared; 3896 } 3897 3898 const WebSelectionBound* start() const { return m_start.get(); } 3899 const WebSelectionBound* end() const { return m_end.get(); } 3900 3901 private: 3902 bool m_selectionCleared; 3903 OwnPtr<WebSelectionBound> m_start; 3904 OwnPtr<WebSelectionBound> m_end; 3905 }; 3906 3907 class CompositedSelectionBoundsTestWebViewClient : public FrameTestHelpers::TestWebViewClient { 3908 public: 3909 virtual ~CompositedSelectionBoundsTestWebViewClient() { } 3910 virtual WebLayerTreeView* layerTreeView() OVERRIDE { return &m_testLayerTreeView; } 3911 3912 CompositedSelectionBoundsTestLayerTreeView& selectionLayerTreeView() { return m_testLayerTreeView; } 3913 3914 private: 3915 CompositedSelectionBoundsTestLayerTreeView m_testLayerTreeView; 3916 }; 3917 3918 class CompositedSelectionBoundsTest : public WebFrameTest { 3919 protected: 3920 CompositedSelectionBoundsTest() 3921 : m_fakeSelectionLayerTreeView(m_fakeSelectionWebViewClient.selectionLayerTreeView()) 3922 { 3923 blink::RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true); 3924 registerMockedHttpURLLoad("Ahem.ttf"); 3925 3926 m_webViewHelper.initialize(true, 0, &m_fakeSelectionWebViewClient); 3927 m_webViewHelper.webView()->settings()->setDefaultFontSize(12); 3928 m_webViewHelper.webView()->setPageScaleFactorLimits(1, 1); 3929 m_webViewHelper.webView()->resize(WebSize(640, 480)); 3930 } 3931 3932 void runTest(const char* testFile) 3933 { 3934 registerMockedHttpURLLoad(testFile); 3935 FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), m_baseURL + testFile); 3936 m_webViewHelper.webView()->layout(); 3937 3938 const WebSelectionBound* selectStart = m_fakeSelectionLayerTreeView.start(); 3939 const WebSelectionBound* selectEnd = m_fakeSelectionLayerTreeView.end(); 3940 3941 v8::HandleScope handleScope(v8::Isolate::GetCurrent()); 3942 v8::Handle<v8::Value> result = m_webViewHelper.webView()->mainFrame()->toWebLocalFrame()->executeScriptAndReturnValueForTests(WebScriptSource("expectedResult")); 3943 if (result.IsEmpty() || (*result)->IsUndefined()) { 3944 EXPECT_FALSE(selectStart); 3945 EXPECT_FALSE(selectEnd); 3946 return; 3947 } 3948 3949 ASSERT_TRUE(selectStart); 3950 ASSERT_TRUE(selectEnd); 3951 3952 ASSERT_TRUE((*result)->IsArray()); 3953 v8::Array& expectedResult = *v8::Array::Cast(*result); 3954 ASSERT_EQ(10u, expectedResult.Length()); 3955 3956 blink::Node* layerOwnerNodeForStart = blink::V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(0)); 3957 ASSERT_TRUE(layerOwnerNodeForStart); 3958 EXPECT_EQ(layerOwnerNodeForStart->renderer()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectStart->layerId); 3959 EXPECT_EQ(expectedResult.Get(1)->Int32Value(), selectStart->edgeTopInLayer.x); 3960 EXPECT_EQ(expectedResult.Get(2)->Int32Value(), selectStart->edgeTopInLayer.y); 3961 EXPECT_EQ(expectedResult.Get(3)->Int32Value(), selectStart->edgeBottomInLayer.x); 3962 EXPECT_EQ(expectedResult.Get(4)->Int32Value(), selectStart->edgeBottomInLayer.y); 3963 3964 blink::Node* layerOwnerNodeForEnd = blink::V8Node::toImplWithTypeCheck(v8::Isolate::GetCurrent(), expectedResult.Get(5)); 3965 ASSERT_TRUE(layerOwnerNodeForEnd); 3966 EXPECT_EQ(layerOwnerNodeForEnd->renderer()->enclosingLayer()->enclosingLayerForPaintInvalidation()->graphicsLayerBacking()->platformLayer()->id(), selectEnd->layerId); 3967 EXPECT_EQ(expectedResult.Get(6)->Int32Value(), selectEnd->edgeTopInLayer.x); 3968 EXPECT_EQ(expectedResult.Get(7)->Int32Value(), selectEnd->edgeTopInLayer.y); 3969 EXPECT_EQ(expectedResult.Get(8)->Int32Value(), selectEnd->edgeBottomInLayer.x); 3970 EXPECT_EQ(expectedResult.Get(9)->Int32Value(), selectEnd->edgeBottomInLayer.y); 3971 } 3972 3973 void runTestWithMultipleFiles(const char* testFile, ...) 3974 { 3975 va_list auxFiles; 3976 va_start(auxFiles, testFile); 3977 while (const char* auxFile = va_arg(auxFiles, const char*)) 3978 registerMockedHttpURLLoad(auxFile); 3979 va_end(auxFiles); 3980 3981 runTest(testFile); 3982 } 3983 3984 CompositedSelectionBoundsTestWebViewClient m_fakeSelectionWebViewClient; 3985 CompositedSelectionBoundsTestLayerTreeView& m_fakeSelectionLayerTreeView; 3986 FrameTestHelpers::WebViewHelper m_webViewHelper; 3987 }; 3988 3989 TEST_F(CompositedSelectionBoundsTest, None) { runTest("composited_selection_bounds_none.html"); } 3990 TEST_F(CompositedSelectionBoundsTest, Basic) { runTest("composited_selection_bounds_basic.html"); } 3991 TEST_F(CompositedSelectionBoundsTest, Transformed) { runTest("composited_selection_bounds_transformed.html"); } 3992 TEST_F(CompositedSelectionBoundsTest, SplitLayer) { runTest("composited_selection_bounds_split_layer.html"); } 3993 TEST_F(CompositedSelectionBoundsTest, EmptyLayer) { runTest("composited_selection_bounds_empty_layer.html"); } 3994 TEST_F(CompositedSelectionBoundsTest, Iframe) { runTestWithMultipleFiles("composited_selection_bounds_iframe.html", "composited_selection_bounds_basic.html", nullptr); } 3995 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: 4057 virtual bool didTapMultipleTargets(const WebSize&, const WebRect&, const WebVector<WebRect>& targetRects) OVERRIDE 4058 { 4059 EXPECT_GE(targetRects.size(), 2u); 4060 m_triggered = true; 4061 return true; 4062 } 4063 4064 bool triggered() const { return m_triggered; } 4065 void resetTriggered() { m_triggered = false; } 4066 bool m_triggered; 4067 }; 4068 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 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 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 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 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 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 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 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 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: 4335 TestSubstituteDataWebFrameClient() 4336 : m_commitCalled(false) 4337 { 4338 } 4339 4340 virtual void didFailProvisionalLoad(WebLocalFrame* frame, const WebURLError& error) 4341 { 4342 frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true); 4343 } 4344 4345 virtual void didCommitProvisionalLoad(WebLocalFrame* frame, const WebHistoryItem&, WebHistoryCommitType) 4346 { 4347 if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank"))) 4348 m_commitCalled = true; 4349 } 4350 4351 bool commitCalled() const { return m_commitCalled; } 4352 4353 private: 4354 bool m_commitCalled; 4355 }; 4356 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: 4391 TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false) 4392 { 4393 } 4394 4395 virtual void didCommitProvisionalLoad(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE 4396 { 4397 m_numBodies = 0; 4398 m_didLoad = true; 4399 } 4400 4401 virtual void didCreateDocumentElement(WebLocalFrame*) OVERRIDE 4402 { 4403 EXPECT_EQ(0, m_numBodies); 4404 } 4405 4406 virtual void willInsertBody(WebLocalFrame*) OVERRIDE 4407 { 4408 m_numBodies++; 4409 } 4410 4411 int m_numBodies; 4412 bool m_didLoad; 4413 }; 4414 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 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 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 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: 4472 explicit SpellCheckClient(uint32_t hash = 0) : m_numberOfTimesChecked(0), m_hash(hash) { } 4473 virtual ~SpellCheckClient() { } 4474 virtual void requestCheckingOfText(const WebString&, const WebVector<uint32_t>&, const WebVector<unsigned>&, WebTextCheckingCompletion* completion) OVERRIDE 4475 { 4476 ++m_numberOfTimesChecked; 4477 Vector<WebTextCheckingResult> results; 4478 const int misspellingStartOffset = 1; 4479 const int misspellingLength = 8; 4480 results.append(WebTextCheckingResult(WebTextDecorationTypeSpelling, misspellingStartOffset, misspellingLength, WebString(), m_hash)); 4481 completion->didFinishCheckingText(results); 4482 } 4483 int numberOfTimesChecked() const { return m_numberOfTimesChecked; } 4484 private: 4485 int m_numberOfTimesChecked; 4486 uint32_t m_hash; 4487 }; 4488 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 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 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 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: 4609 StubbornSpellCheckClient() : m_completion(0) { } 4610 virtual ~StubbornSpellCheckClient() { } 4611 4612 virtual void requestCheckingOfText( 4613 const WebString&, 4614 const WebVector<uint32_t>&, 4615 const WebVector<unsigned>&, 4616 WebTextCheckingCompletion* completion) OVERRIDE 4617 { 4618 m_completion = completion; 4619 } 4620 4621 void kickNoResults() 4622 { 4623 kick(-1, -1, WebTextDecorationTypeSpelling); 4624 } 4625 4626 void kick() 4627 { 4628 kick(1, 8, WebTextDecorationTypeSpelling); 4629 } 4630 4631 void kickGrammar() 4632 { 4633 kick(1, 8, WebTextDecorationTypeGrammar); 4634 } 4635 4636 void kickInvisibleSpellcheck() 4637 { 4638 kick(1, 8, WebTextDecorationTypeInvisibleSpellcheck); 4639 } 4640 4641 private: 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 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. 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 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 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: 4780 TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false) 4781 { 4782 } 4783 4784 virtual void didAccessInitialDocument(WebLocalFrame* frame) 4785 { 4786 EXPECT_TRUE(!m_didAccessInitialDocument); 4787 m_didAccessInitialDocument = true; 4788 } 4789 4790 bool m_didAccessInitialDocument; 4791 }; 4792 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 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 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) 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) 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: 4947 TestMainFrameUserOrProgrammaticScrollFrameClient() { reset(); } 4948 void reset() 4949 { 4950 m_didScrollMainFrame = false; 4951 m_wasProgrammaticScroll = false; 4952 } 4953 bool wasUserScroll() const { return m_didScrollMainFrame && !m_wasProgrammaticScroll; } 4954 bool wasProgrammaticScroll() const { return m_didScrollMainFrame && m_wasProgrammaticScroll; } 4955 4956 // WebFrameClient: 4957 virtual void didChangeScrollOffset(WebLocalFrame* frame) OVERRIDE 4958 { 4959 if (frame->parent()) 4960 return; 4961 EXPECT_FALSE(m_didScrollMainFrame); 4962 FrameView* view = toWebLocalFrameImpl(frame)->frameView(); 4963 // FrameView can be scrolled in FrameView::setFixedVisibleContentRect 4964 // which is called from LocalFrame::createView (before the frame is associated 4965 // with the the view). 4966 if (view) { 4967 m_didScrollMainFrame = true; 4968 m_wasProgrammaticScroll = view->inProgrammaticScroll(); 4969 } 4970 } 4971 private: 4972 bool m_didScrollMainFrame; 4973 bool m_wasProgrammaticScroll; 4974 }; 4975 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 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 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 5080 virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType) OVERRIDE 5081 { 5082 EXPECT_TRUE(false); 5083 } 5084 }; 5085 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: 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: 5116 TestNewWindowWebFrameClient() 5117 : m_decidePolicyCallCount(0) 5118 { 5119 } 5120 5121 virtual WebNavigationPolicy decidePolicyForNavigation(const NavigationPolicyInfo& info) OVERRIDE 5122 { 5123 m_decidePolicyCallCount++; 5124 return info.defaultPolicy; 5125 } 5126 5127 int decidePolicyCallCount() const { return m_decidePolicyCallCount; } 5128 5129 private: 5130 int m_decidePolicyCallCount; 5131 }; 5132 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 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 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 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 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: 5246 explicit TestCachePolicyWebFrameClient(TestCachePolicyWebFrameClient* parentClient) 5247 : m_parentClient(parentClient) 5248 , m_policy(WebURLRequest::UseProtocolCachePolicy) 5249 , m_childClient(0) 5250 , m_willSendRequestCallCount(0) 5251 , m_childFrameCreationCount(0) 5252 { 5253 } 5254 5255 void setChildWebFrameClient(TestCachePolicyWebFrameClient* client) { m_childClient = client; } 5256 WebURLRequest::CachePolicy cachePolicy() const { return m_policy; } 5257 int willSendRequestCallCount() const { return m_willSendRequestCallCount; } 5258 int childFrameCreationCount() const { return m_childFrameCreationCount; } 5259 5260 virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString&) 5261 { 5262 ASSERT(m_childClient); 5263 m_childFrameCreationCount++; 5264 WebFrame* frame = WebLocalFrame::create(m_childClient); 5265 parent->appendChild(frame); 5266 return frame; 5267 } 5268 5269 virtual void didStartLoading(bool toDifferentDocument) 5270 { 5271 if (m_parentClient) { 5272 m_parentClient->didStartLoading(toDifferentDocument); 5273 return; 5274 } 5275 TestWebFrameClient::didStartLoading(toDifferentDocument); 5276 } 5277 5278 virtual void didStopLoading() 5279 { 5280 if (m_parentClient) { 5281 m_parentClient->didStopLoading(); 5282 return; 5283 } 5284 TestWebFrameClient::didStopLoading(); 5285 } 5286 5287 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) OVERRIDE 5288 { 5289 m_policy = request.cachePolicy(); 5290 m_willSendRequestCallCount++; 5291 } 5292 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 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: 5333 TestSameDocumentWebFrameClient() 5334 : m_frameLoadTypeSameSeen(false) 5335 { 5336 } 5337 5338 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest&, const WebURLResponse&) 5339 { 5340 if (toWebLocalFrameImpl(frame)->frame()->loader().loadType() == FrameLoadTypeSame) 5341 m_frameLoadTypeSameSeen = true; 5342 } 5343 5344 bool frameLoadTypeSameSeen() const { return m_frameLoadTypeSameSeen; } 5345 5346 private: 5347 bool m_frameLoadTypeSameSeen; 5348 }; 5349 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: 5367 TestSameDocumentWithImageWebFrameClient() 5368 : m_numOfImageRequests(0) 5369 { 5370 } 5371 5372 virtual void willSendRequest(WebLocalFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&) 5373 { 5374 if (request.requestContext() == WebURLRequest::RequestContextImage) { 5375 m_numOfImageRequests++; 5376 EXPECT_EQ(WebURLRequest::UseProtocolCachePolicy, request.cachePolicy()); 5377 } 5378 } 5379 5380 int numOfImageRequests() const { return m_numOfImageRequests; } 5381 5382 private: 5383 int m_numOfImageRequests; 5384 }; 5385 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 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: 5428 TestStartStopCallbackWebFrameClient() 5429 : m_startLoadingCount(0) 5430 , m_stopLoadingCount(0) 5431 , m_differentDocumentStartCount(0) 5432 { 5433 } 5434 5435 virtual void didStartLoading(bool toDifferentDocument) OVERRIDE 5436 { 5437 TestWebFrameClient::didStartLoading(toDifferentDocument); 5438 m_startLoadingCount++; 5439 if (toDifferentDocument) 5440 m_differentDocumentStartCount++; 5441 } 5442 5443 virtual void didStopLoading() OVERRIDE 5444 { 5445 TestWebFrameClient::didStopLoading(); 5446 m_stopLoadingCount++; 5447 } 5448 5449 int startLoadingCount() const { return m_startLoadingCount; } 5450 int stopLoadingCount() const { return m_stopLoadingCount; } 5451 int differentDocumentStartCount() const { return m_differentDocumentStartCount; } 5452 5453 private: 5454 int m_startLoadingCount; 5455 int m_stopLoadingCount; 5456 int m_differentDocumentStartCount; 5457 }; 5458 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: 5473 TestDidNavigateCommitTypeWebFrameClient() 5474 : m_lastCommitType(WebHistoryInertCommit) 5475 { 5476 } 5477 5478 virtual void didNavigateWithinPage(WebLocalFrame*, const WebHistoryItem&, WebHistoryCommitType type) OVERRIDE 5479 { 5480 m_lastCommitType = type; 5481 } 5482 5483 WebHistoryCommitType lastCommitType() const { return m_lastCommitType; } 5484 5485 private: 5486 WebHistoryCommitType m_lastCommitType; 5487 }; 5488 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: 5504 TestHistoryWebFrameClient() 5505 { 5506 m_replacesCurrentHistoryItem = false; 5507 m_frame = 0; 5508 } 5509 5510 void didStartProvisionalLoad(WebLocalFrame* frame, bool isTransitionNavigation) 5511 { 5512 WebDataSource* ds = frame->provisionalDataSource(); 5513 m_replacesCurrentHistoryItem = ds->replacesCurrentHistoryItem(); 5514 m_frame = frame; 5515 } 5516 5517 bool replacesCurrentHistoryItem() { return m_replacesCurrentHistoryItem; } 5518 WebFrame* frame() { return m_frame; } 5519 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. 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 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. 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: 5629 FailCreateChildFrame() : m_callCount(0) { } 5630 5631 virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE 5632 { 5633 ++m_callCount; 5634 return 0; 5635 } 5636 5637 int callCount() const { return m_callCount; } 5638 5639 private: 5640 int m_callCount; 5641 }; 5642 5643 // Test that we don't crash if WebFrameClient::createChildFrame() fails. 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 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 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 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 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 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 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 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 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: 5871 ManifestChangeWebFrameClient() : m_manifestChangeCount(0) { } 5872 virtual void didChangeManifest(WebLocalFrame*) OVERRIDE 5873 { 5874 ++m_manifestChangeCount; 5875 } 5876 5877 int manifestChangeCount() { return m_manifestChangeCount; } 5878 5879 private: 5880 int m_manifestChangeCount; 5881 }; 5882 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 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 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 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 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 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 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) 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: 5980 ThemeColorTestWebFrameClient() 5981 : m_didNotify(false) 5982 { 5983 } 5984 5985 void reset() 5986 { 5987 m_didNotify = false; 5988 } 5989 5990 bool didNotify() const 5991 { 5992 return m_didNotify; 5993 } 5994 5995 private: 5996 virtual void didChangeThemeColor() 5997 { 5998 m_didNotify = true; 5999 } 6000 6001 bool m_didNotify; 6002 }; 6003 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: 6033 WebFrameSwapTest() 6034 { 6035 registerMockedHttpURLLoad("frame-a-b-c.html"); 6036 registerMockedHttpURLLoad("subframe-a.html"); 6037 registerMockedHttpURLLoad("subframe-b.html"); 6038 registerMockedHttpURLLoad("subframe-c.html"); 6039 registerMockedHttpURLLoad("subframe-hello.html"); 6040 6041 m_webViewHelper.initializeAndLoad(m_baseURL + "frame-a-b-c.html"); 6042 } 6043 6044 void reset() { m_webViewHelper.reset(); } 6045 WebFrame* mainFrame() const { return m_webViewHelper.webView()->mainFrame(); } 6046 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 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 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 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 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 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 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 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 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: 6206 MockDocumentThreadableLoaderClient() : m_failed(false) { } 6207 virtual void didFail(const ResourceError&) OVERRIDE { m_failed = true;} 6208 6209 void reset() { m_failed = false; } 6210 bool failed() { return m_failed; } 6211 6212 bool m_failed; 6213 }; 6214 6215 // FIXME: This would be better as a unittest on DocumentThreadableLoader but it 6216 // requires spin-up of a frame. It may be possible to remove that requirement 6217 // and convert it to a unittest. 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: 6251 NavigationTransitionCallbackWebFrameClient() 6252 : m_navigationalDataReceivedCount(0) 6253 , m_provisionalLoadCount(0) 6254 , m_wasLastProvisionalLoadATransition(false) { } 6255 6256 virtual void addNavigationTransitionData(const WebString& allowedDestinationOrigin, const WebString& selector, const WebString& markup) OVERRIDE 6257 { 6258 m_navigationalDataReceivedCount++; 6259 } 6260 6261 virtual void didStartProvisionalLoad(WebLocalFrame* localFrame, bool isTransitionNavigation) OVERRIDE 6262 { 6263 m_provisionalLoadCount++; 6264 m_wasLastProvisionalLoadATransition = isTransitionNavigation; 6265 } 6266 6267 unsigned navigationalDataReceivedCount() const { return m_navigationalDataReceivedCount; } 6268 unsigned provisionalLoadCount() const { return m_provisionalLoadCount; } 6269 bool wasLastProvisionalLoadATransition() const { return m_wasLastProvisionalLoadATransition; } 6270 6271 private: 6272 unsigned m_navigationalDataReceivedCount; 6273 unsigned m_provisionalLoadCount; 6274 bool m_wasLastProvisionalLoadATransition; 6275 }; 6276 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