1 /* 2 * Copyright (C) 2011, 2012 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 #include "WebView.h" 33 34 #include <gtest/gtest.h> 35 #include "FrameTestHelpers.h" 36 #include "URLTestHelpers.h" 37 #include "WebAutofillClient.h" 38 #include "WebContentDetectionResult.h" 39 #include "WebDateTimeChooserCompletion.h" 40 #include "WebDocument.h" 41 #include "WebElement.h" 42 #include "WebFrame.h" 43 #include "WebFrameClient.h" 44 #include "WebFrameImpl.h" 45 #include "WebHelperPluginImpl.h" 46 #include "WebHitTestResult.h" 47 #include "WebInputEvent.h" 48 #include "WebSettings.h" 49 #include "WebViewClient.h" 50 #include "WebViewImpl.h" 51 #include "WebWidget.h" 52 #include "core/dom/Document.h" 53 #include "core/dom/Element.h" 54 #include "core/html/HTMLDocument.h" 55 #include "core/html/HTMLInputElement.h" 56 #include "core/loader/FrameLoadRequest.h" 57 #include "core/frame/FrameView.h" 58 #include "core/page/Chrome.h" 59 #include "core/frame/Settings.h" 60 #include "platform/KeyboardCodes.h" 61 #include "platform/graphics/Color.h" 62 #include "public/platform/Platform.h" 63 #include "public/platform/WebSize.h" 64 #include "public/platform/WebThread.h" 65 #include "public/platform/WebUnitTestSupport.h" 66 #include "public/web/WebWidgetClient.h" 67 #include "third_party/skia/include/core/SkBitmap.h" 68 #include "third_party/skia/include/core/SkBitmapDevice.h" 69 #include "third_party/skia/include/core/SkCanvas.h" 70 71 using namespace blink; 72 using blink::FrameTestHelpers::runPendingTasks; 73 using blink::URLTestHelpers::toKURL; 74 75 namespace { 76 77 enum HorizontalScrollbarState { 78 NoHorizontalScrollbar, 79 VisibleHorizontalScrollbar, 80 }; 81 82 enum VerticalScrollbarState { 83 NoVerticalScrollbar, 84 VisibleVerticalScrollbar, 85 }; 86 87 class TestData { 88 public: 89 void setWebView(WebView* webView) { m_webView = toWebViewImpl(webView); } 90 void setSize(const WebSize& newSize) { m_size = newSize; } 91 HorizontalScrollbarState horizontalScrollbarState() const 92 { 93 return m_webView->hasHorizontalScrollbar() ? VisibleHorizontalScrollbar: NoHorizontalScrollbar; 94 } 95 VerticalScrollbarState verticalScrollbarState() const 96 { 97 return m_webView->hasVerticalScrollbar() ? VisibleVerticalScrollbar : NoVerticalScrollbar; 98 } 99 int width() const { return m_size.width; } 100 int height() const { return m_size.height; } 101 102 private: 103 WebSize m_size; 104 WebViewImpl* m_webView; 105 }; 106 107 class AutoResizeWebViewClient : public WebViewClient { 108 public: 109 // WebViewClient methods 110 virtual void didAutoResize(const WebSize& newSize) { m_testData.setSize(newSize); } 111 112 // Local methods 113 TestData& testData() { return m_testData; } 114 115 private: 116 TestData m_testData; 117 }; 118 119 class TapHandlingWebViewClient : public WebViewClient { 120 public: 121 // WebViewClient methods 122 virtual void didHandleGestureEvent(const WebGestureEvent& event, bool eventCancelled) 123 { 124 if (event.type == WebInputEvent::GestureTap) { 125 m_tapX = event.x; 126 m_tapY = event.y; 127 } else if (event.type == WebInputEvent::GestureLongPress) { 128 m_longpressX = event.x; 129 m_longpressY = event.y; 130 } 131 } 132 133 // Local methods 134 void reset() 135 { 136 m_tapX = -1; 137 m_tapY = -1; 138 m_longpressX = -1; 139 m_longpressY = -1; 140 } 141 int tapX() { return m_tapX; } 142 int tapY() { return m_tapY; } 143 int longpressX() { return m_longpressX; } 144 int longpressY() { return m_longpressY; } 145 146 private: 147 int m_tapX; 148 int m_tapY; 149 int m_longpressX; 150 int m_longpressY; 151 }; 152 153 class HelperPluginCreatingWebViewClient : public WebViewClient { 154 public: 155 // WebViewClient methods 156 virtual blink::WebWidget* createPopupMenu(blink::WebPopupType popupType) OVERRIDE 157 { 158 EXPECT_EQ(WebPopupTypeHelperPlugin, popupType); 159 m_helperPluginWebWidget = blink::WebHelperPlugin::create(this); 160 // The caller owns the object, but we retain a pointer for use in closeWidgetSoon(). 161 return m_helperPluginWebWidget; 162 } 163 164 virtual void initializeHelperPluginWebFrame(blink::WebHelperPlugin* plugin) OVERRIDE 165 { 166 ASSERT_TRUE(m_webFrameClient); 167 plugin->initializeFrame(m_webFrameClient); 168 } 169 170 // WebWidgetClient methods 171 virtual void closeWidgetSoon() OVERRIDE 172 { 173 ASSERT_TRUE(m_helperPluginWebWidget); 174 m_helperPluginWebWidget->close(); 175 m_helperPluginWebWidget = 0; 176 } 177 178 // Local methods 179 HelperPluginCreatingWebViewClient() 180 : m_helperPluginWebWidget(0) 181 , m_webFrameClient(0) 182 { 183 } 184 185 void setWebFrameClient(WebFrameClient* client) { m_webFrameClient = client; } 186 187 private: 188 WebWidget* m_helperPluginWebWidget; 189 WebFrameClient* m_webFrameClient; 190 }; 191 192 class DateTimeChooserWebViewClient : public WebViewClient { 193 public: 194 WebDateTimeChooserCompletion* chooserCompletion() 195 { 196 return m_chooserCompletion; 197 } 198 199 void clearChooserCompletion() 200 { 201 m_chooserCompletion = 0; 202 } 203 204 // WebViewClient methods 205 virtual bool openDateTimeChooser(const WebDateTimeChooserParams&, WebDateTimeChooserCompletion* chooser_completion) OVERRIDE 206 { 207 m_chooserCompletion = chooser_completion; 208 return true; 209 } 210 211 private: 212 WebDateTimeChooserCompletion* m_chooserCompletion; 213 214 }; 215 216 class WebViewTest : public testing::Test { 217 public: 218 WebViewTest() 219 : m_baseURL("http://www.test.com/") 220 { 221 } 222 223 virtual void TearDown() 224 { 225 Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); 226 } 227 228 protected: 229 void testAutoResize(const WebSize& minAutoResize, const WebSize& maxAutoResize, 230 const std::string& pageWidth, const std::string& pageHeight, 231 int expectedWidth, int expectedHeight, 232 HorizontalScrollbarState expectedHorizontalState, VerticalScrollbarState expectedVerticalState); 233 234 void testTextInputType(WebTextInputType expectedType, const std::string& htmlFile); 235 void testInputMode(const WebString& expectedInputMode, const std::string& htmlFile); 236 237 std::string m_baseURL; 238 FrameTestHelpers::WebViewHelper m_webViewHelper; 239 }; 240 241 TEST_F(WebViewTest, SetBaseBackgroundColor) 242 { 243 const WebColor kWhite = 0xFFFFFFFF; 244 const WebColor kBlue = 0xFF0000FF; 245 const WebColor kDarkCyan = 0xFF227788; 246 const WebColor kTranslucentPutty = 0x80BFB196; 247 248 WebView* webView = m_webViewHelper.initialize(); 249 EXPECT_EQ(kWhite, webView->backgroundColor()); 250 251 webView->setBaseBackgroundColor(kBlue); 252 EXPECT_EQ(kBlue, webView->backgroundColor()); 253 254 WebURL baseURL = URLTestHelpers::toKURL("http://example.com/"); 255 webView->mainFrame()->loadHTMLString( 256 "<html><head><style>body {background-color:#227788}</style></head></html>", baseURL); 257 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); 258 EXPECT_EQ(kDarkCyan, webView->backgroundColor()); 259 260 webView->mainFrame()->loadHTMLString( 261 "<html><head><style>body {background-color:rgba(255,0,0,0.5)}</style></head></html>", baseURL); 262 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); 263 // Expected: red (50% alpha) blended atop base of kBlue. 264 EXPECT_EQ(0xFF7F0080, webView->backgroundColor()); 265 266 webView->setBaseBackgroundColor(kTranslucentPutty); 267 // Expected: red (50% alpha) blended atop kTranslucentPutty. Note the alpha. 268 EXPECT_EQ(0xBFE93B32, webView->backgroundColor()); 269 } 270 271 TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) 272 { 273 const WebColor kBlue = 0xFF0000FF; 274 WebView* webView = WebViewImpl::create(0); 275 EXPECT_NE(kBlue, webView->backgroundColor()); 276 // webView does not have a frame yet, but we should still be able to set the background color. 277 webView->setBaseBackgroundColor(kBlue); 278 EXPECT_EQ(kBlue, webView->backgroundColor()); 279 } 280 281 TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent) 282 { 283 const WebColor kAlphaRed = 0x80FF0000; 284 const WebColor kAlphaGreen = 0x8000FF00; 285 const int kWidth = 100; 286 const int kHeight = 100; 287 288 // Set WebView background to green with alpha. 289 WebView* webView = m_webViewHelper.initialize(); 290 webView->setBaseBackgroundColor(kAlphaGreen); 291 webView->settings()->setShouldClearDocumentBackground(false); 292 webView->resize(WebSize(kWidth, kHeight)); 293 webView->layout(); 294 295 // Set canvas background to red with alpha. 296 SkBitmap bitmap; 297 bitmap.setConfig(SkBitmap::kARGB_8888_Config, kWidth, kHeight); 298 bitmap.allocPixels(); 299 SkBitmapDevice device(bitmap); 300 SkCanvas canvas(&device); 301 canvas.clear(kAlphaRed); 302 webView->paint(&canvas, WebRect(0, 0, kWidth, kHeight)); 303 304 // The result should be a blend of red and green. 305 SkColor color = bitmap.getColor(kWidth / 2, kHeight / 2); 306 EXPECT_TRUE(WebCore::redChannel(color)); 307 EXPECT_TRUE(WebCore::greenChannel(color)); 308 } 309 310 TEST_F(WebViewTest, FocusIsInactive) 311 { 312 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "visible_iframe.html"); 313 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "visible_iframe.html"); 314 315 webView->setFocus(true); 316 webView->setIsActive(true); 317 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 318 EXPECT_TRUE(frame->frame()->document()->isHTMLDocument()); 319 320 WebCore::HTMLDocument* document = WebCore::toHTMLDocument(frame->frame()->document()); 321 EXPECT_TRUE(document->hasFocus()); 322 webView->setFocus(false); 323 webView->setIsActive(false); 324 EXPECT_FALSE(document->hasFocus()); 325 webView->setFocus(true); 326 webView->setIsActive(true); 327 EXPECT_TRUE(document->hasFocus()); 328 webView->setFocus(true); 329 webView->setIsActive(false); 330 EXPECT_FALSE(document->hasFocus()); 331 webView->setFocus(false); 332 webView->setIsActive(true); 333 EXPECT_FALSE(document->hasFocus()); 334 } 335 336 TEST_F(WebViewTest, ActiveState) 337 { 338 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "visible_iframe.html"); 339 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "visible_iframe.html"); 340 341 ASSERT_TRUE(webView); 342 343 webView->setIsActive(true); 344 EXPECT_TRUE(webView->isActive()); 345 346 webView->setIsActive(false); 347 EXPECT_FALSE(webView->isActive()); 348 349 webView->setIsActive(true); 350 EXPECT_TRUE(webView->isActive()); 351 } 352 353 TEST_F(WebViewTest, HitTestResultAtWithPageScale) 354 { 355 std::string url = m_baseURL + "specify_size.html?" + "50px" + ":" + "50px"; 356 URLTestHelpers::registerMockedURLLoad(toKURL(url), "specify_size.html"); 357 WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0); 358 webView->resize(WebSize(100, 100)); 359 WebPoint hitPoint(75, 75); 360 361 // Image is at top left quandrant, so should not hit it. 362 WebHitTestResult negativeResult = webView->hitTestResultAt(hitPoint); 363 ASSERT_EQ(WebNode::ElementNode, negativeResult.node().nodeType()); 364 EXPECT_FALSE(negativeResult.node().to<WebElement>().hasTagName("img")); 365 negativeResult.reset(); 366 367 // Scale page up 2x so image should occupy the whole viewport. 368 webView->setPageScaleFactor(2.0f, WebPoint(0, 0)); 369 WebHitTestResult positiveResult = webView->hitTestResultAt(hitPoint); 370 ASSERT_EQ(WebNode::ElementNode, positiveResult.node().nodeType()); 371 EXPECT_TRUE(positiveResult.node().to<WebElement>().hasTagName("img")); 372 positiveResult.reset(); 373 } 374 375 void WebViewTest::testAutoResize(const WebSize& minAutoResize, const WebSize& maxAutoResize, 376 const std::string& pageWidth, const std::string& pageHeight, 377 int expectedWidth, int expectedHeight, 378 HorizontalScrollbarState expectedHorizontalState, VerticalScrollbarState expectedVerticalState) 379 { 380 AutoResizeWebViewClient client; 381 std::string url = m_baseURL + "specify_size.html?" + pageWidth + ":" + pageHeight; 382 URLTestHelpers::registerMockedURLLoad(toKURL(url), "specify_size.html"); 383 WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0, &client); 384 client.testData().setWebView(webView); 385 386 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 387 WebCore::FrameView* frameView = frame->frame()->view(); 388 frameView->layout(); 389 EXPECT_FALSE(frameView->layoutPending()); 390 EXPECT_FALSE(frameView->needsLayout()); 391 392 webView->enableAutoResizeMode(minAutoResize, maxAutoResize); 393 EXPECT_TRUE(frameView->layoutPending()); 394 EXPECT_TRUE(frameView->needsLayout()); 395 frameView->layout(); 396 397 EXPECT_TRUE(frame->frame()->document()->isHTMLDocument()); 398 399 EXPECT_EQ(expectedWidth, client.testData().width()); 400 EXPECT_EQ(expectedHeight, client.testData().height()); 401 EXPECT_EQ(expectedHorizontalState, client.testData().horizontalScrollbarState()); 402 EXPECT_EQ(expectedVerticalState, client.testData().verticalScrollbarState()); 403 404 m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client. 405 } 406 407 TEST_F(WebViewTest, DISABLED_AutoResizeMinimumSize) 408 { 409 WebSize minAutoResize(91, 56); 410 WebSize maxAutoResize(403, 302); 411 std::string pageWidth = "91px"; 412 std::string pageHeight = "56px"; 413 int expectedWidth = 91; 414 int expectedHeight = 56; 415 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 416 expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar); 417 } 418 419 TEST_F(WebViewTest, AutoResizeHeightOverflowAndFixedWidth) 420 { 421 WebSize minAutoResize(90, 95); 422 WebSize maxAutoResize(90, 100); 423 std::string pageWidth = "60px"; 424 std::string pageHeight = "200px"; 425 int expectedWidth = 90; 426 int expectedHeight = 100; 427 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 428 expectedWidth, expectedHeight, NoHorizontalScrollbar, VisibleVerticalScrollbar); 429 } 430 431 TEST_F(WebViewTest, AutoResizeFixedHeightAndWidthOverflow) 432 { 433 WebSize minAutoResize(90, 100); 434 WebSize maxAutoResize(200, 100); 435 std::string pageWidth = "300px"; 436 std::string pageHeight = "80px"; 437 int expectedWidth = 200; 438 int expectedHeight = 100; 439 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 440 expectedWidth, expectedHeight, VisibleHorizontalScrollbar, NoVerticalScrollbar); 441 } 442 443 // Next three tests disabled for https://bugs.webkit.org/show_bug.cgi?id=92318 . 444 // It seems we can run three AutoResize tests, then the next one breaks. 445 TEST_F(WebViewTest, DISABLED_AutoResizeInBetweenSizes) 446 { 447 WebSize minAutoResize(90, 95); 448 WebSize maxAutoResize(200, 300); 449 std::string pageWidth = "100px"; 450 std::string pageHeight = "200px"; 451 int expectedWidth = 100; 452 int expectedHeight = 200; 453 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 454 expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar); 455 } 456 457 TEST_F(WebViewTest, DISABLED_AutoResizeOverflowSizes) 458 { 459 WebSize minAutoResize(90, 95); 460 WebSize maxAutoResize(200, 300); 461 std::string pageWidth = "300px"; 462 std::string pageHeight = "400px"; 463 int expectedWidth = 200; 464 int expectedHeight = 300; 465 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 466 expectedWidth, expectedHeight, VisibleHorizontalScrollbar, VisibleVerticalScrollbar); 467 } 468 469 TEST_F(WebViewTest, DISABLED_AutoResizeMaxSize) 470 { 471 WebSize minAutoResize(90, 95); 472 WebSize maxAutoResize(200, 300); 473 std::string pageWidth = "200px"; 474 std::string pageHeight = "300px"; 475 int expectedWidth = 200; 476 int expectedHeight = 300; 477 testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight, 478 expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar); 479 } 480 481 void WebViewTest::testTextInputType(WebTextInputType expectedType, const std::string& htmlFile) 482 { 483 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(htmlFile.c_str())); 484 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + htmlFile); 485 webView->setInitialFocus(false); 486 EXPECT_EQ(expectedType, webView->textInputInfo().type); 487 } 488 489 TEST_F(WebViewTest, TextInputType) 490 { 491 testTextInputType(WebTextInputTypeText, "input_field_default.html"); 492 testTextInputType(WebTextInputTypePassword, "input_field_password.html"); 493 testTextInputType(WebTextInputTypeEmail, "input_field_email.html"); 494 testTextInputType(WebTextInputTypeSearch, "input_field_search.html"); 495 testTextInputType(WebTextInputTypeNumber, "input_field_number.html"); 496 testTextInputType(WebTextInputTypeTelephone, "input_field_tel.html"); 497 testTextInputType(WebTextInputTypeURL, "input_field_url.html"); 498 } 499 500 void WebViewTest::testInputMode(const WebString& expectedInputMode, const std::string& htmlFile) 501 { 502 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(htmlFile.c_str())); 503 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + htmlFile); 504 webView->setInitialFocus(false); 505 EXPECT_EQ(expectedInputMode, webView->textInputInfo().inputMode); 506 } 507 508 TEST_F(WebViewTest, InputMode) 509 { 510 testInputMode(WebString(), "input_mode_default.html"); 511 testInputMode(WebString("unknown"), "input_mode_default_unknown.html"); 512 testInputMode(WebString("verbatim"), "input_mode_default_verbatim.html"); 513 testInputMode(WebString("verbatim"), "input_mode_type_text_verbatim.html"); 514 testInputMode(WebString("verbatim"), "input_mode_type_search_verbatim.html"); 515 testInputMode(WebString(), "input_mode_type_url_verbatim.html"); 516 testInputMode(WebString("verbatim"), "input_mode_textarea_verbatim.html"); 517 } 518 519 TEST_F(WebViewTest, SetEditableSelectionOffsetsAndTextInputInfo) 520 { 521 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 522 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 523 webView->setInitialFocus(false); 524 webView->setEditableSelectionOffsets(5, 13); 525 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 526 EXPECT_EQ("56789abc", frame->selectionAsText()); 527 WebTextInputInfo info = webView->textInputInfo(); 528 EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value); 529 EXPECT_EQ(5, info.selectionStart); 530 EXPECT_EQ(13, info.selectionEnd); 531 EXPECT_EQ(-1, info.compositionStart); 532 EXPECT_EQ(-1, info.compositionEnd); 533 534 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_editable_populated.html")); 535 webView = m_webViewHelper.initializeAndLoad(m_baseURL + "content_editable_populated.html"); 536 webView->setInitialFocus(false); 537 webView->setEditableSelectionOffsets(8, 19); 538 frame = toWebFrameImpl(webView->mainFrame()); 539 EXPECT_EQ("89abcdefghi", frame->selectionAsText()); 540 info = webView->textInputInfo(); 541 EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value); 542 EXPECT_EQ(8, info.selectionStart); 543 EXPECT_EQ(19, info.selectionEnd); 544 EXPECT_EQ(-1, info.compositionStart); 545 EXPECT_EQ(-1, info.compositionEnd); 546 } 547 548 TEST_F(WebViewTest, ConfirmCompositionCursorPositionChange) 549 { 550 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 551 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 552 webView->setInitialFocus(false); 553 554 // Set up a composition that needs to be committed. 555 std::string compositionText("hello"); 556 557 WebVector<WebCompositionUnderline> emptyUnderlines; 558 webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 3, 3); 559 560 WebTextInputInfo info = webView->textInputInfo(); 561 EXPECT_EQ("hello", std::string(info.value.utf8().data())); 562 EXPECT_EQ(3, info.selectionStart); 563 EXPECT_EQ(3, info.selectionEnd); 564 EXPECT_EQ(0, info.compositionStart); 565 EXPECT_EQ(5, info.compositionEnd); 566 567 webView->confirmComposition(WebWidget::KeepSelection); 568 info = webView->textInputInfo(); 569 EXPECT_EQ(3, info.selectionStart); 570 EXPECT_EQ(3, info.selectionEnd); 571 EXPECT_EQ(-1, info.compositionStart); 572 EXPECT_EQ(-1, info.compositionEnd); 573 574 webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 3, 3); 575 info = webView->textInputInfo(); 576 EXPECT_EQ("helhellolo", std::string(info.value.utf8().data())); 577 EXPECT_EQ(6, info.selectionStart); 578 EXPECT_EQ(6, info.selectionEnd); 579 EXPECT_EQ(3, info.compositionStart); 580 EXPECT_EQ(8, info.compositionEnd); 581 582 webView->confirmComposition(WebWidget::DoNotKeepSelection); 583 info = webView->textInputInfo(); 584 EXPECT_EQ(8, info.selectionStart); 585 EXPECT_EQ(8, info.selectionEnd); 586 EXPECT_EQ(-1, info.compositionStart); 587 EXPECT_EQ(-1, info.compositionEnd); 588 } 589 590 TEST_F(WebViewTest, InsertNewLinePlacementAfterConfirmComposition) 591 { 592 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("text_area_populated.html")); 593 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "text_area_populated.html"); 594 webView->setInitialFocus(false); 595 596 WebVector<WebCompositionUnderline> emptyUnderlines; 597 598 webView->setEditableSelectionOffsets(4, 4); 599 webView->setCompositionFromExistingText(8, 12, emptyUnderlines); 600 601 WebTextInputInfo info = webView->textInputInfo(); 602 EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data())); 603 EXPECT_EQ(4, info.selectionStart); 604 EXPECT_EQ(4, info.selectionEnd); 605 EXPECT_EQ(8, info.compositionStart); 606 EXPECT_EQ(12, info.compositionEnd); 607 608 webView->confirmComposition(WebWidget::KeepSelection); 609 info = webView->textInputInfo(); 610 EXPECT_EQ(4, info.selectionStart); 611 EXPECT_EQ(4, info.selectionEnd); 612 EXPECT_EQ(-1, info.compositionStart); 613 EXPECT_EQ(-1, info.compositionEnd); 614 615 std::string compositionText("\n"); 616 webView->confirmComposition(WebString::fromUTF8(compositionText.c_str())); 617 info = webView->textInputInfo(); 618 EXPECT_EQ(5, info.selectionStart); 619 EXPECT_EQ(5, info.selectionEnd); 620 EXPECT_EQ(-1, info.compositionStart); 621 EXPECT_EQ(-1, info.compositionEnd); 622 EXPECT_EQ("0123\n456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data())); 623 } 624 625 TEST_F(WebViewTest, ExtendSelectionAndDelete) 626 { 627 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 628 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 629 webView->setInitialFocus(false); 630 webView->setEditableSelectionOffsets(10, 10); 631 webView->extendSelectionAndDelete(5, 8); 632 WebTextInputInfo info = webView->textInputInfo(); 633 EXPECT_EQ("01234ijklmnopqrstuvwxyz", std::string(info.value.utf8().data())); 634 EXPECT_EQ(5, info.selectionStart); 635 EXPECT_EQ(5, info.selectionEnd); 636 webView->extendSelectionAndDelete(10, 0); 637 info = webView->textInputInfo(); 638 EXPECT_EQ("ijklmnopqrstuvwxyz", std::string(info.value.utf8().data())); 639 } 640 641 TEST_F(WebViewTest, SetCompositionFromExistingText) 642 { 643 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 644 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 645 webView->setInitialFocus(false); 646 WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1)); 647 underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false); 648 webView->setEditableSelectionOffsets(4, 10); 649 webView->setCompositionFromExistingText(8, 12, underlines); 650 WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines(); 651 EXPECT_EQ(8u, underlineResults[0].startOffset); 652 EXPECT_EQ(12u, underlineResults[0].endOffset); 653 WebTextInputInfo info = webView->textInputInfo(); 654 EXPECT_EQ(4, info.selectionStart); 655 EXPECT_EQ(10, info.selectionEnd); 656 EXPECT_EQ(8, info.compositionStart); 657 EXPECT_EQ(12, info.compositionEnd); 658 WebVector<WebCompositionUnderline> emptyUnderlines; 659 webView->setCompositionFromExistingText(0, 0, emptyUnderlines); 660 info = webView->textInputInfo(); 661 EXPECT_EQ(4, info.selectionStart); 662 EXPECT_EQ(10, info.selectionEnd); 663 EXPECT_EQ(-1, info.compositionStart); 664 EXPECT_EQ(-1, info.compositionEnd); 665 } 666 667 TEST_F(WebViewTest, SetCompositionFromExistingTextInTextArea) 668 { 669 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("text_area_populated.html")); 670 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "text_area_populated.html"); 671 webView->setInitialFocus(false); 672 WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1)); 673 underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false); 674 webView->setEditableSelectionOffsets(27, 27); 675 std::string newLineText("\n"); 676 webView->confirmComposition(WebString::fromUTF8(newLineText.c_str())); 677 WebTextInputInfo info = webView->textInputInfo(); 678 EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", std::string(info.value.utf8().data())); 679 680 webView->setEditableSelectionOffsets(31, 31); 681 webView->setCompositionFromExistingText(30, 34, underlines); 682 WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines(); 683 EXPECT_EQ(2u, underlineResults[0].startOffset); 684 EXPECT_EQ(6u, underlineResults[0].endOffset); 685 info = webView->textInputInfo(); 686 EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", std::string(info.value.utf8().data())); 687 EXPECT_EQ(31, info.selectionStart); 688 EXPECT_EQ(31, info.selectionEnd); 689 EXPECT_EQ(30, info.compositionStart); 690 EXPECT_EQ(34, info.compositionEnd); 691 692 std::string compositionText("yolo"); 693 webView->confirmComposition(WebString::fromUTF8(compositionText.c_str())); 694 info = webView->textInputInfo(); 695 EXPECT_EQ("0123456789abcdefghijklmnopq\nrsyoloxyz", std::string(info.value.utf8().data())); 696 EXPECT_EQ(34, info.selectionStart); 697 EXPECT_EQ(34, info.selectionEnd); 698 EXPECT_EQ(-1, info.compositionStart); 699 EXPECT_EQ(-1, info.compositionEnd); 700 } 701 702 TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition) 703 { 704 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 705 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 706 webView->setInitialFocus(false); 707 708 std::string compositionTextFirst("hello "); 709 std::string compositionTextSecond("world"); 710 WebVector<WebCompositionUnderline> emptyUnderlines; 711 712 webView->confirmComposition(WebString::fromUTF8(compositionTextFirst.c_str())); 713 webView->setComposition(WebString::fromUTF8(compositionTextSecond.c_str()), emptyUnderlines, 5, 5); 714 715 WebTextInputInfo info = webView->textInputInfo(); 716 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 717 EXPECT_EQ(11, info.selectionStart); 718 EXPECT_EQ(11, info.selectionEnd); 719 EXPECT_EQ(6, info.compositionStart); 720 EXPECT_EQ(11, info.compositionEnd); 721 722 webView->setEditableSelectionOffsets(6, 6); 723 info = webView->textInputInfo(); 724 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 725 EXPECT_EQ(6, info.selectionStart); 726 EXPECT_EQ(6, info.selectionEnd); 727 EXPECT_EQ(6, info.compositionStart); 728 EXPECT_EQ(11, info.compositionEnd); 729 730 webView->setEditableSelectionOffsets(8, 8); 731 info = webView->textInputInfo(); 732 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 733 EXPECT_EQ(8, info.selectionStart); 734 EXPECT_EQ(8, info.selectionEnd); 735 EXPECT_EQ(6, info.compositionStart); 736 EXPECT_EQ(11, info.compositionEnd); 737 738 webView->setEditableSelectionOffsets(11, 11); 739 info = webView->textInputInfo(); 740 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 741 EXPECT_EQ(11, info.selectionStart); 742 EXPECT_EQ(11, info.selectionEnd); 743 EXPECT_EQ(6, info.compositionStart); 744 EXPECT_EQ(11, info.compositionEnd); 745 746 webView->setEditableSelectionOffsets(6, 11); 747 info = webView->textInputInfo(); 748 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 749 EXPECT_EQ(6, info.selectionStart); 750 EXPECT_EQ(11, info.selectionEnd); 751 EXPECT_EQ(6, info.compositionStart); 752 EXPECT_EQ(11, info.compositionEnd); 753 754 webView->setEditableSelectionOffsets(2, 2); 755 info = webView->textInputInfo(); 756 EXPECT_EQ("hello world", std::string(info.value.utf8().data())); 757 EXPECT_EQ(2, info.selectionStart); 758 EXPECT_EQ(2, info.selectionEnd); 759 EXPECT_EQ(-1, info.compositionStart); 760 EXPECT_EQ(-1, info.compositionEnd); 761 } 762 763 TEST_F(WebViewTest, IsSelectionAnchorFirst) 764 { 765 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 766 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 767 WebFrame* frame = webView->mainFrame(); 768 769 webView->setInitialFocus(false); 770 webView->setEditableSelectionOffsets(4, 10); 771 EXPECT_TRUE(webView->isSelectionAnchorFirst()); 772 WebRect anchor; 773 WebRect focus; 774 webView->selectionBounds(anchor, focus); 775 frame->selectRange(WebPoint(focus.x, focus.y), WebPoint(anchor.x, anchor.y)); 776 EXPECT_FALSE(webView->isSelectionAnchorFirst()); 777 } 778 779 TEST_F(WebViewTest, HistoryResetScrollAndScaleState) 780 { 781 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("hello_world.html")); 782 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html")); 783 webViewImpl->resize(WebSize(640, 480)); 784 webViewImpl->layout(); 785 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width); 786 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height); 787 788 // Make the page scale and scroll with the given paremeters. 789 webViewImpl->setPageScaleFactor(2.0f, WebPoint(116, 84)); 790 EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor()); 791 EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width); 792 EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height); 793 webViewImpl->page()->mainFrame()->loader().saveDocumentAndScrollState(); 794 795 // Confirm that restoring the page state restores the parameters. 796 webViewImpl->setPageScaleFactor(1.5f, WebPoint(16, 24)); 797 EXPECT_EQ(1.5f, webViewImpl->pageScaleFactor()); 798 EXPECT_EQ(16, webViewImpl->mainFrame()->scrollOffset().width); 799 EXPECT_EQ(24, webViewImpl->mainFrame()->scrollOffset().height); 800 // WebViewImpl::setPageScaleFactor is performing user scrolls, which will set the 801 // wasScrolledByUser flag on the main frame, and prevent restoreScrollPositionAndViewState 802 // from restoring the scrolling position. 803 webViewImpl->page()->mainFrame()->view()->setWasScrolledByUser(false); 804 webViewImpl->page()->mainFrame()->loader().setLoadType(WebCore::FrameLoadTypeBackForward); 805 webViewImpl->page()->mainFrame()->loader().restoreScrollPositionAndViewState(); 806 EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor()); 807 EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width); 808 EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height); 809 webViewImpl->page()->mainFrame()->loader().saveDocumentAndScrollState(); 810 811 // Confirm that resetting the page state resets the saved scroll position. 812 // The HistoryController treats a page scale factor of 0.0f as special and avoids 813 // restoring it to the WebView. 814 webViewImpl->resetScrollAndScaleState(); 815 EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor()); 816 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width); 817 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height); 818 webViewImpl->page()->mainFrame()->loader().restoreScrollPositionAndViewState(); 819 EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor()); 820 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width); 821 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height); 822 } 823 824 class EnterFullscreenWebViewClient : public WebViewClient { 825 public: 826 // WebViewClient methods 827 virtual bool enterFullScreen() { return true; } 828 virtual void exitFullScreen() { } 829 }; 830 831 832 TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState) 833 { 834 EnterFullscreenWebViewClient client; 835 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("hello_world.html")); 836 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, 0, &client)); 837 webViewImpl->settings()->setFullScreenEnabled(true); 838 webViewImpl->resize(WebSize(640, 480)); 839 webViewImpl->layout(); 840 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width); 841 EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height); 842 843 // Make the page scale and scroll with the given paremeters. 844 webViewImpl->setPageScaleFactor(2.0f, WebPoint(116, 84)); 845 EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor()); 846 EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width); 847 EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height); 848 849 RefPtr<WebCore::Element> element = static_cast<PassRefPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().body()); 850 webViewImpl->enterFullScreenForElement(element.get()); 851 webViewImpl->willEnterFullScreen(); 852 webViewImpl->didEnterFullScreen(); 853 854 // Page scale factor must be 1.0 during fullscreen for elements to be sized 855 // properly. 856 EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor()); 857 858 // Make sure fullscreen nesting doesn't disrupt scroll/scale saving. 859 RefPtr<WebCore::Element> otherElement = static_cast<PassRefPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().head()); 860 webViewImpl->enterFullScreenForElement(otherElement.get()); 861 862 // Confirm that exiting fullscreen restores the parameters. 863 webViewImpl->willExitFullScreen(); 864 webViewImpl->didExitFullScreen(); 865 EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor()); 866 EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width); 867 EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height); 868 869 m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client. 870 } 871 872 class ContentDetectorClient : public WebViewClient { 873 public: 874 ContentDetectorClient() { reset(); } 875 876 virtual WebContentDetectionResult detectContentAround(const WebHitTestResult& hitTest) OVERRIDE 877 { 878 m_contentDetectionRequested = true; 879 return m_contentDetectionResult; 880 } 881 882 virtual void scheduleContentIntent(const WebURL& url) OVERRIDE 883 { 884 m_scheduledIntentURL = url; 885 } 886 887 virtual void cancelScheduledContentIntents() OVERRIDE 888 { 889 m_pendingIntentsCancelled = true; 890 } 891 892 void reset() 893 { 894 m_contentDetectionRequested = false; 895 m_pendingIntentsCancelled = false; 896 m_scheduledIntentURL = WebURL(); 897 m_contentDetectionResult = WebContentDetectionResult(); 898 } 899 900 bool contentDetectionRequested() const { return m_contentDetectionRequested; } 901 bool pendingIntentsCancelled() const { return m_pendingIntentsCancelled; } 902 const WebURL& scheduledIntentURL() const { return m_scheduledIntentURL; } 903 void setContentDetectionResult(const WebContentDetectionResult& result) { m_contentDetectionResult = result; } 904 905 private: 906 bool m_contentDetectionRequested; 907 bool m_pendingIntentsCancelled; 908 WebURL m_scheduledIntentURL; 909 WebContentDetectionResult m_contentDetectionResult; 910 }; 911 912 static bool tapElementById(WebView* webView, WebInputEvent::Type type, const WebString& id) 913 { 914 ASSERT(webView); 915 RefPtr<WebCore::Element> element = static_cast<PassRefPtr<WebCore::Element> >(webView->mainFrame()->document().getElementById(id)); 916 if (!element) 917 return false; 918 919 element->scrollIntoViewIfNeeded(); 920 WebCore::IntPoint center = element->screenRect().center(); 921 922 WebGestureEvent event; 923 event.type = type; 924 event.x = center.x(); 925 event.y = center.y(); 926 927 webView->handleInputEvent(event); 928 runPendingTasks(); 929 return true; 930 } 931 932 TEST_F(WebViewTest, DetectContentAroundPosition) 933 { 934 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_listeners.html")); 935 936 ContentDetectorClient client; 937 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "content_listeners.html", true, 0, &client); 938 webView->resize(WebSize(500, 300)); 939 webView->layout(); 940 runPendingTasks(); 941 942 WebString clickListener = WebString::fromUTF8("clickListener"); 943 WebString touchstartListener = WebString::fromUTF8("touchstartListener"); 944 WebString mousedownListener = WebString::fromUTF8("mousedownListener"); 945 WebString noListener = WebString::fromUTF8("noListener"); 946 WebString link = WebString::fromUTF8("link"); 947 948 // Ensure content detection is not requested for nodes listening to click, 949 // mouse or touch events when we do simple taps. 950 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, clickListener)); 951 EXPECT_FALSE(client.contentDetectionRequested()); 952 client.reset(); 953 954 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, touchstartListener)); 955 EXPECT_FALSE(client.contentDetectionRequested()); 956 client.reset(); 957 958 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, mousedownListener)); 959 EXPECT_FALSE(client.contentDetectionRequested()); 960 client.reset(); 961 962 // Content detection should work normally without these event listeners. 963 // The click listener in the body should be ignored as a special case. 964 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener)); 965 EXPECT_TRUE(client.contentDetectionRequested()); 966 EXPECT_FALSE(client.scheduledIntentURL().isValid()); 967 968 WebURL intentURL = toKURL(m_baseURL); 969 client.setContentDetectionResult(WebContentDetectionResult(WebRange(), WebString(), intentURL)); 970 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener)); 971 EXPECT_TRUE(client.scheduledIntentURL() == intentURL); 972 973 // Tapping elsewhere should cancel the scheduled intent. 974 WebGestureEvent event; 975 event.type = WebInputEvent::GestureTap; 976 webView->handleInputEvent(event); 977 runPendingTasks(); 978 EXPECT_TRUE(client.pendingIntentsCancelled()); 979 } 980 981 TEST_F(WebViewTest, ClientTapHandling) 982 { 983 TapHandlingWebViewClient client; 984 client.reset(); 985 WebView* webView = m_webViewHelper.initializeAndLoad("about:blank", true, 0, &client); 986 WebGestureEvent event; 987 event.type = WebInputEvent::GestureTap; 988 event.x = 3; 989 event.y = 8; 990 webView->handleInputEvent(event); 991 runPendingTasks(); 992 EXPECT_EQ(3, client.tapX()); 993 EXPECT_EQ(8, client.tapY()); 994 client.reset(); 995 event.type = WebInputEvent::GestureLongPress; 996 event.x = 25; 997 event.y = 7; 998 webView->handleInputEvent(event); 999 runPendingTasks(); 1000 EXPECT_EQ(25, client.longpressX()); 1001 EXPECT_EQ(7, client.longpressY()); 1002 1003 m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client. 1004 } 1005 1006 #if OS(ANDROID) 1007 TEST_F(WebViewTest, LongPressSelection) 1008 { 1009 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("longpress_selection.html")); 1010 1011 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "longpress_selection.html", true); 1012 webView->resize(WebSize(500, 300)); 1013 webView->layout(); 1014 runPendingTasks(); 1015 1016 WebString target = WebString::fromUTF8("target"); 1017 WebString onselectstartfalse = WebString::fromUTF8("onselectstartfalse"); 1018 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 1019 1020 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, onselectstartfalse)); 1021 EXPECT_EQ("", std::string(frame->selectionAsText().utf8().data())); 1022 EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, target)); 1023 EXPECT_EQ("testword", std::string(frame->selectionAsText().utf8().data())); 1024 } 1025 #endif 1026 1027 TEST_F(WebViewTest, SelectionOnDisabledInput) 1028 { 1029 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("selection_disabled.html")); 1030 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "selection_disabled.html", true); 1031 webView->resize(WebSize(640, 480)); 1032 webView->layout(); 1033 runPendingTasks(); 1034 1035 std::string testWord = "This text should be selected."; 1036 1037 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 1038 EXPECT_EQ(testWord, std::string(frame->selectionAsText().utf8().data())); 1039 1040 size_t location; 1041 size_t length; 1042 EXPECT_TRUE(toWebViewImpl(webView)->caretOrSelectionRange(&location, &length)); 1043 EXPECT_EQ(location, 0UL); 1044 EXPECT_EQ(length, testWord.length()); 1045 } 1046 1047 TEST_F(WebViewTest, SelectionOnReadOnlyInput) 1048 { 1049 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("selection_readonly.html")); 1050 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "selection_readonly.html", true); 1051 webView->resize(WebSize(640, 480)); 1052 webView->layout(); 1053 runPendingTasks(); 1054 1055 std::string testWord = "This text should be selected."; 1056 1057 WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame()); 1058 EXPECT_EQ(testWord, std::string(frame->selectionAsText().utf8().data())); 1059 1060 size_t location; 1061 size_t length; 1062 EXPECT_TRUE(toWebViewImpl(webView)->caretOrSelectionRange(&location, &length)); 1063 EXPECT_EQ(location, 0UL); 1064 EXPECT_EQ(length, testWord.length()); 1065 } 1066 1067 class MockAutofillClient : public WebAutofillClient { 1068 public: 1069 MockAutofillClient() 1070 : m_ignoreTextChanges(false) 1071 , m_textChangesWhileIgnored(0) 1072 , m_textChangesWhileNotIgnored(0) { } 1073 1074 virtual ~MockAutofillClient() { } 1075 1076 virtual void setIgnoreTextChanges(bool ignore) OVERRIDE { m_ignoreTextChanges = ignore; } 1077 virtual void textFieldDidChange(const WebInputElement&) OVERRIDE 1078 { 1079 if (m_ignoreTextChanges) 1080 ++m_textChangesWhileIgnored; 1081 else 1082 ++m_textChangesWhileNotIgnored; 1083 } 1084 1085 void clearChangeCounts() 1086 { 1087 m_textChangesWhileIgnored = 0; 1088 m_textChangesWhileNotIgnored = 0; 1089 } 1090 1091 int textChangesWhileIgnored() { return m_textChangesWhileIgnored; } 1092 int textChangesWhileNotIgnored() { return m_textChangesWhileNotIgnored; } 1093 1094 private: 1095 bool m_ignoreTextChanges; 1096 int m_textChangesWhileIgnored; 1097 int m_textChangesWhileNotIgnored; 1098 }; 1099 1100 1101 TEST_F(WebViewTest, LosingFocusDoesNotTriggerAutofillTextChange) 1102 { 1103 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 1104 MockAutofillClient client; 1105 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 1106 webView->setAutofillClient(&client); 1107 webView->setInitialFocus(false); 1108 1109 // Set up a composition that needs to be committed. 1110 WebVector<WebCompositionUnderline> emptyUnderlines; 1111 webView->setEditableSelectionOffsets(4, 10); 1112 webView->setCompositionFromExistingText(8, 12, emptyUnderlines); 1113 WebTextInputInfo info = webView->textInputInfo(); 1114 EXPECT_EQ(4, info.selectionStart); 1115 EXPECT_EQ(10, info.selectionEnd); 1116 EXPECT_EQ(8, info.compositionStart); 1117 EXPECT_EQ(12, info.compositionEnd); 1118 1119 // Clear the focus and track that the subsequent composition commit does not trigger a 1120 // text changed notification for autofill. 1121 client.clearChangeCounts(); 1122 webView->setFocus(false); 1123 EXPECT_EQ(1, client.textChangesWhileIgnored()); 1124 EXPECT_EQ(0, client.textChangesWhileNotIgnored()); 1125 1126 webView->setAutofillClient(0); 1127 } 1128 1129 TEST_F(WebViewTest, ConfirmCompositionTriggersAutofillTextChange) 1130 { 1131 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 1132 MockAutofillClient client; 1133 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html"); 1134 webView->setAutofillClient(&client); 1135 webView->setInitialFocus(false); 1136 1137 // Set up a composition that needs to be committed. 1138 std::string compositionText("testingtext"); 1139 1140 WebVector<WebCompositionUnderline> emptyUnderlines; 1141 webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 0, compositionText.length()); 1142 1143 WebTextInputInfo info = webView->textInputInfo(); 1144 EXPECT_EQ(0, info.selectionStart); 1145 EXPECT_EQ((int) compositionText.length(), info.selectionEnd); 1146 EXPECT_EQ(0, info.compositionStart); 1147 EXPECT_EQ((int) compositionText.length(), info.compositionEnd); 1148 1149 client.clearChangeCounts(); 1150 webView->confirmComposition(); 1151 EXPECT_EQ(0, client.textChangesWhileIgnored()); 1152 EXPECT_EQ(1, client.textChangesWhileNotIgnored()); 1153 1154 webView->setAutofillClient(0); 1155 } 1156 1157 TEST_F(WebViewTest, SetCompositionFromExistingTextTriggersAutofillTextChange) 1158 { 1159 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html")); 1160 MockAutofillClient client; 1161 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html", true); 1162 webView->setAutofillClient(&client); 1163 webView->setInitialFocus(false); 1164 1165 WebVector<WebCompositionUnderline> emptyUnderlines; 1166 1167 client.clearChangeCounts(); 1168 webView->setCompositionFromExistingText(8, 12, emptyUnderlines); 1169 1170 WebTextInputInfo info = webView->textInputInfo(); 1171 EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data())); 1172 EXPECT_EQ(8, info.compositionStart); 1173 EXPECT_EQ(12, info.compositionEnd); 1174 1175 EXPECT_EQ(0, client.textChangesWhileIgnored()); 1176 EXPECT_EQ(0, client.textChangesWhileNotIgnored()); 1177 1178 WebDocument document = webView->mainFrame()->document(); 1179 EXPECT_EQ(WebString::fromUTF8("none"), document.getElementById("inputEvent").firstChild().nodeValue()); 1180 1181 webView->setAutofillClient(0); 1182 } 1183 1184 TEST_F(WebViewTest, ShadowRoot) 1185 { 1186 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("shadow_dom_test.html")); 1187 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initializeAndLoad(m_baseURL + "shadow_dom_test.html", true)); 1188 1189 WebDocument document = webViewImpl->mainFrame()->document(); 1190 { 1191 WebElement elementWithShadowRoot = document.getElementById("shadowroot"); 1192 EXPECT_FALSE(elementWithShadowRoot.isNull()); 1193 WebNode shadowRoot = elementWithShadowRoot.shadowRoot(); 1194 EXPECT_FALSE(shadowRoot.isNull()); 1195 } 1196 { 1197 WebElement elementWithoutShadowRoot = document.getElementById("noshadowroot"); 1198 EXPECT_FALSE(elementWithoutShadowRoot.isNull()); 1199 WebNode shadowRoot = elementWithoutShadowRoot.shadowRoot(); 1200 EXPECT_TRUE(shadowRoot.isNull()); 1201 } 1202 } 1203 1204 TEST_F(WebViewTest, HelperPlugin) 1205 { 1206 HelperPluginCreatingWebViewClient client; 1207 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initialize(true, 0, &client)); 1208 1209 WebFrameImpl* frame = toWebFrameImpl(webViewImpl->mainFrame()); 1210 client.setWebFrameClient(frame->client()); 1211 1212 WebHelperPluginImpl* helperPlugin = webViewImpl->createHelperPlugin("dummy-plugin-type", frame->document()); 1213 EXPECT_TRUE(helperPlugin); 1214 EXPECT_EQ(0, helperPlugin->getPlugin()); // Invalid plugin type means no plugin. 1215 1216 webViewImpl->closeHelperPluginSoon(helperPlugin); 1217 1218 m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client. 1219 } 1220 1221 1222 class ViewCreatingWebViewClient : public WebViewClient { 1223 public: 1224 ViewCreatingWebViewClient() 1225 : m_didFocusCalled(false) 1226 { 1227 } 1228 1229 // WebViewClient methods 1230 virtual WebView* createView(WebFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString& name, WebNavigationPolicy, bool) OVERRIDE 1231 { 1232 return m_webViewHelper.initialize(true, 0, 0); 1233 } 1234 1235 // WebWidgetClient methods 1236 virtual void didFocus() OVERRIDE 1237 { 1238 m_didFocusCalled = true; 1239 } 1240 1241 bool didFocusCalled() const { return m_didFocusCalled; } 1242 WebView* createdWebView() const { return m_webViewHelper.webView(); } 1243 1244 private: 1245 FrameTestHelpers::WebViewHelper m_webViewHelper; 1246 bool m_didFocusCalled; 1247 }; 1248 1249 TEST_F(WebViewTest, FocusExistingFrameOnNavigate) 1250 { 1251 ViewCreatingWebViewClient client; 1252 FrameTestHelpers::WebViewHelper m_webViewHelper; 1253 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initialize(true, 0, &client)); 1254 webViewImpl->page()->settings().setJavaScriptCanOpenWindowsAutomatically(true); 1255 WebFrameImpl* frame = toWebFrameImpl(webViewImpl->mainFrame()); 1256 frame->setName("_start"); 1257 1258 // Make a request that will open a new window 1259 WebURLRequest webURLRequest; 1260 webURLRequest.initialize(); 1261 WebCore::FrameLoadRequest request(0, webURLRequest.toResourceRequest(), WTF::String("_blank")); 1262 webViewImpl->page()->mainFrame()->loader().load(request); 1263 ASSERT_TRUE(client.createdWebView()); 1264 EXPECT_FALSE(client.didFocusCalled()); 1265 1266 // Make a request from the new window that will navigate the original window. The original window should be focused. 1267 WebURLRequest webURLRequestWithTargetStart; 1268 webURLRequestWithTargetStart.initialize(); 1269 WebCore::FrameLoadRequest requestWithTargetStart(0, webURLRequestWithTargetStart.toResourceRequest(), WTF::String("_start")); 1270 toWebViewImpl(client.createdWebView())->page()->mainFrame()->loader().load(requestWithTargetStart); 1271 EXPECT_TRUE(client.didFocusCalled()); 1272 1273 m_webViewHelper.reset(); // Remove dependency on locally scoped client. 1274 } 1275 1276 TEST_F(WebViewTest, DispatchesFocusOutFocusInOnViewToggleFocus) 1277 { 1278 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "focusout_focusin_events.html"); 1279 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "focusout_focusin_events.html", true, 0); 1280 1281 webView->setFocus(true); 1282 webView->setFocus(false); 1283 webView->setFocus(true); 1284 1285 WebElement element = webView->mainFrame()->document().getElementById("message"); 1286 EXPECT_STREQ("focusoutfocusin", element.innerText().utf8().data()); 1287 } 1288 1289 TEST_F(WebViewTest, DispatchesDomFocusOutDomFocusInOnViewToggleFocus) 1290 { 1291 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "domfocusout_domfocusin_events.html"); 1292 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "domfocusout_domfocusin_events.html", true, 0); 1293 1294 webView->setFocus(true); 1295 webView->setFocus(false); 1296 webView->setFocus(true); 1297 1298 WebElement element = webView->mainFrame()->document().getElementById("message"); 1299 EXPECT_STREQ("DOMFocusOutDOMFocusIn", element.innerText().utf8().data()); 1300 } 1301 1302 #if !ENABLE(INPUT_MULTIPLE_FIELDS_UI) 1303 static void openDateTimeChooser(WebView* webView, WebCore::HTMLInputElement* inputElement) 1304 { 1305 inputElement->focus(); 1306 1307 WebKeyboardEvent keyEvent; 1308 keyEvent.windowsKeyCode = WebCore::VKEY_SPACE; 1309 keyEvent.type = WebInputEvent::RawKeyDown; 1310 keyEvent.setKeyIdentifierFromWindowsKeyCode(); 1311 webView->handleInputEvent(keyEvent); 1312 1313 keyEvent.type = WebInputEvent::KeyUp; 1314 webView->handleInputEvent(keyEvent); 1315 } 1316 1317 TEST_F(WebViewTest, ChooseValueFromDateTimeChooser) 1318 { 1319 DateTimeChooserWebViewClient client; 1320 std::string url = m_baseURL + "date_time_chooser.html"; 1321 URLTestHelpers::registerMockedURLLoad(toKURL(url), "date_time_chooser.html"); 1322 WebViewImpl* webViewImpl = toWebViewImpl(m_webViewHelper.initializeAndLoad(url, true, 0, &client)); 1323 1324 WebCore::Document* document = webViewImpl->mainFrameImpl()->frame()->document(); 1325 1326 WebCore::HTMLInputElement* inputElement; 1327 1328 inputElement = toHTMLInputElement(document->getElementById("date")); 1329 openDateTimeChooser(webViewImpl, inputElement); 1330 client.chooserCompletion()->didChooseValue(0); 1331 client.clearChooserCompletion(); 1332 EXPECT_STREQ("1970-01-01", inputElement->value().utf8().data()); 1333 1334 openDateTimeChooser(webViewImpl, inputElement); 1335 client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN()); 1336 client.clearChooserCompletion(); 1337 EXPECT_STREQ("", inputElement->value().utf8().data()); 1338 1339 inputElement = toHTMLInputElement(document->getElementById("datetimelocal")); 1340 openDateTimeChooser(webViewImpl, inputElement); 1341 client.chooserCompletion()->didChooseValue(0); 1342 client.clearChooserCompletion(); 1343 EXPECT_STREQ("1970-01-01T00:00", inputElement->value().utf8().data()); 1344 1345 openDateTimeChooser(webViewImpl, inputElement); 1346 client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN()); 1347 client.clearChooserCompletion(); 1348 EXPECT_STREQ("", inputElement->value().utf8().data()); 1349 1350 inputElement = toHTMLInputElement(document->getElementById("month")); 1351 openDateTimeChooser(webViewImpl, inputElement); 1352 client.chooserCompletion()->didChooseValue(0); 1353 client.clearChooserCompletion(); 1354 EXPECT_STREQ("1970-01", inputElement->value().utf8().data()); 1355 1356 openDateTimeChooser(webViewImpl, inputElement); 1357 client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN()); 1358 client.clearChooserCompletion(); 1359 EXPECT_STREQ("", inputElement->value().utf8().data()); 1360 1361 inputElement = toHTMLInputElement(document->getElementById("time")); 1362 openDateTimeChooser(webViewImpl, inputElement); 1363 client.chooserCompletion()->didChooseValue(0); 1364 client.clearChooserCompletion(); 1365 EXPECT_STREQ("00:00", inputElement->value().utf8().data()); 1366 1367 openDateTimeChooser(webViewImpl, inputElement); 1368 client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN()); 1369 client.clearChooserCompletion(); 1370 EXPECT_STREQ("", inputElement->value().utf8().data()); 1371 1372 inputElement = toHTMLInputElement(document->getElementById("week")); 1373 openDateTimeChooser(webViewImpl, inputElement); 1374 client.chooserCompletion()->didChooseValue(0); 1375 client.clearChooserCompletion(); 1376 EXPECT_STREQ("1970-W01", inputElement->value().utf8().data()); 1377 1378 openDateTimeChooser(webViewImpl, inputElement); 1379 client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN()); 1380 client.clearChooserCompletion(); 1381 EXPECT_STREQ("", inputElement->value().utf8().data()); 1382 } 1383 #endif 1384 1385 TEST_F(WebViewTest, SmartClipData) 1386 { 1387 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("Ahem.ttf")); 1388 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("smartclip.html")); 1389 WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip.html"); 1390 webView->resize(WebSize(500, 500)); 1391 webView->layout(); 1392 WebRect cropRect(300, 125, 100, 50); 1393 1394 // FIXME: We should test the structure of the data we get back. 1395 EXPECT_FALSE(webView->getSmartClipData(cropRect).isEmpty()); 1396 } 1397 1398 } 1399