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