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 #include "WebViewHost.h" 33 34 #include "LayoutTestController.h" 35 #include "TestNavigationController.h" 36 #include "TestShell.h" 37 #include "TestWebWorker.h" 38 #include "WebCString.h" 39 #include "WebConsoleMessage.h" 40 #include "WebContextMenuData.h" 41 #include "WebDataSource.h" 42 #include "WebDeviceOrientationClientMock.h" 43 #include "WebDragData.h" 44 #include "WebElement.h" 45 #include "WebFrame.h" 46 #include "WebGeolocationClientMock.h" 47 #include "WebHistoryItem.h" 48 #include "WebNode.h" 49 #include "WebRange.h" 50 #include "WebRect.h" 51 #include "WebScreenInfo.h" 52 #include "WebSize.h" 53 #include "WebSpeechInputControllerMock.h" 54 #include "WebStorageNamespace.h" 55 #include "WebTextCheckingCompletion.h" 56 #include "WebTextCheckingResult.h" 57 #include "WebURLRequest.h" 58 #include "WebURLResponse.h" 59 #include "WebView.h" 60 #include "WebWindowFeatures.h" 61 #include "skia/ext/platform_canvas.h" 62 #include "webkit/support/webkit_support.h" 63 #include <wtf/Assertions.h> 64 #include <wtf/PassOwnPtr.h> 65 #include <wtf/Vector.h> 66 67 using namespace WebCore; 68 using namespace WebKit; 69 using namespace std; 70 71 static const int screenWidth = 1920; 72 static const int screenHeight = 1080; 73 static const int screenUnavailableBorder = 8; 74 75 // WebNavigationType debugging strings taken from PolicyDelegate.mm. 76 static const char* linkClickedString = "link clicked"; 77 static const char* formSubmittedString = "form submitted"; 78 static const char* backForwardString = "back/forward"; 79 static const char* reloadString = "reload"; 80 static const char* formResubmittedString = "form resubmitted"; 81 static const char* otherString = "other"; 82 static const char* illegalString = "illegal value"; 83 84 static int nextPageID = 1; 85 86 // Used to write a platform neutral file:/// URL by only taking the filename 87 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt"). 88 static string urlSuitableForTestResult(const string& url) 89 { 90 if (url.empty() || string::npos == url.find("file://")) 91 return url; 92 93 size_t pos = url.rfind('/'); 94 if (pos == string::npos) { 95 #if OS(WINDOWS) 96 pos = url.rfind('\\'); 97 if (pos == string::npos) 98 pos = 0; 99 #else 100 pos = 0; 101 #endif 102 } 103 string filename = url.substr(pos + 1); 104 if (filename.empty()) 105 return "file:"; // A WebKit test has this in its expected output. 106 return filename; 107 } 108 109 // Used to write a platform neutral file:/// URL by taking the 110 // filename and its directory. (e.g., converts 111 // "file:///tmp/foo/bar.txt" to just "bar.txt"). 112 static string descriptionSuitableForTestResult(const string& url) 113 { 114 if (url.empty() || string::npos == url.find("file://")) 115 return url; 116 117 size_t pos = url.rfind('/'); 118 if (pos == string::npos || !pos) 119 return "ERROR:" + url; 120 pos = url.rfind('/', pos - 1); 121 if (pos == string::npos) 122 return "ERROR:" + url; 123 124 return url.substr(pos + 1); 125 } 126 127 // Adds a file called "DRTFakeFile" to |data_object| (CF_HDROP). Use to fake 128 // dragging a file. 129 static void addDRTFakeFileToDataObject(WebDragData* dragData) 130 { 131 dragData->appendToFilenames(WebString::fromUTF8("DRTFakeFile")); 132 } 133 134 // Get a debugging string from a WebNavigationType. 135 static const char* webNavigationTypeToString(WebNavigationType type) 136 { 137 switch (type) { 138 case WebKit::WebNavigationTypeLinkClicked: 139 return linkClickedString; 140 case WebKit::WebNavigationTypeFormSubmitted: 141 return formSubmittedString; 142 case WebKit::WebNavigationTypeBackForward: 143 return backForwardString; 144 case WebKit::WebNavigationTypeReload: 145 return reloadString; 146 case WebKit::WebNavigationTypeFormResubmitted: 147 return formResubmittedString; 148 case WebKit::WebNavigationTypeOther: 149 return otherString; 150 } 151 return illegalString; 152 } 153 154 static string URLDescription(const GURL& url) 155 { 156 if (url.SchemeIs("file")) 157 return url.ExtractFileName(); 158 return url.possibly_invalid_spec(); 159 } 160 161 static void printResponseDescription(const WebURLResponse& response) 162 { 163 if (response.isNull()) { 164 fputs("(null)", stdout); 165 return; 166 } 167 string url = response.url().spec(); 168 printf("<NSURLResponse %s, http status code %d>", 169 descriptionSuitableForTestResult(url).c_str(), 170 response.httpStatusCode()); 171 } 172 173 static void printNodeDescription(const WebNode& node, int exception) 174 { 175 if (exception) { 176 fputs("ERROR", stdout); 177 return; 178 } 179 if (node.isNull()) { 180 fputs("(null)", stdout); 181 return; 182 } 183 fputs(node.nodeName().utf8().data(), stdout); 184 const WebNode& parent = node.parentNode(); 185 if (!parent.isNull()) { 186 fputs(" > ", stdout); 187 printNodeDescription(parent, 0); 188 } 189 } 190 191 static void printRangeDescription(const WebRange& range) 192 { 193 if (range.isNull()) { 194 fputs("(null)", stdout); 195 return; 196 } 197 printf("range from %d of ", range.startOffset()); 198 int exception = 0; 199 WebNode startNode = range.startContainer(exception); 200 printNodeDescription(startNode, exception); 201 printf(" to %d of ", range.endOffset()); 202 WebNode endNode = range.endContainer(exception); 203 printNodeDescription(endNode, exception); 204 } 205 206 static string editingActionDescription(WebEditingAction action) 207 { 208 switch (action) { 209 case WebKit::WebEditingActionTyped: 210 return "WebViewInsertActionTyped"; 211 case WebKit::WebEditingActionPasted: 212 return "WebViewInsertActionPasted"; 213 case WebKit::WebEditingActionDropped: 214 return "WebViewInsertActionDropped"; 215 } 216 return "(UNKNOWN ACTION)"; 217 } 218 219 static string textAffinityDescription(WebTextAffinity affinity) 220 { 221 switch (affinity) { 222 case WebKit::WebTextAffinityUpstream: 223 return "NSSelectionAffinityUpstream"; 224 case WebKit::WebTextAffinityDownstream: 225 return "NSSelectionAffinityDownstream"; 226 } 227 return "(UNKNOWN AFFINITY)"; 228 } 229 230 // WebViewClient ------------------------------------------------------------- 231 232 WebView* WebViewHost::createView(WebFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString&) 233 { 234 if (!layoutTestController()->canOpenWindows()) 235 return 0; 236 return m_shell->createNewWindow(WebURL())->webView(); 237 } 238 239 WebWidget* WebViewHost::createPopupMenu(WebPopupType) 240 { 241 return 0; 242 } 243 244 WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&) 245 { 246 return 0; 247 } 248 249 WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota) 250 { 251 return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota); 252 } 253 254 void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine) 255 { 256 // This matches win DumpRenderTree's UIDelegate.cpp. 257 string newMessage; 258 if (!message.text.isEmpty()) { 259 newMessage = message.text.utf8(); 260 size_t fileProtocol = newMessage.find("file://"); 261 if (fileProtocol != string::npos) { 262 newMessage = newMessage.substr(0, fileProtocol) 263 + urlSuitableForTestResult(newMessage.substr(fileProtocol)); 264 } 265 } 266 printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data()); 267 } 268 269 void WebViewHost::didStartLoading() 270 { 271 m_shell->setIsLoading(true); 272 } 273 274 void WebViewHost::didStopLoading() 275 { 276 m_shell->setIsLoading(false); 277 } 278 279 // The output from these methods in layout test mode should match that 280 // expected by the layout tests. See EditingDelegate.m in DumpRenderTree. 281 282 bool WebViewHost::shouldBeginEditing(const WebRange& range) 283 { 284 if (layoutTestController()->shouldDumpEditingCallbacks()) { 285 fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout); 286 printRangeDescription(range); 287 fputs("\n", stdout); 288 } 289 return layoutTestController()->acceptsEditing(); 290 } 291 292 bool WebViewHost::shouldEndEditing(const WebRange& range) 293 { 294 if (layoutTestController()->shouldDumpEditingCallbacks()) { 295 fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout); 296 printRangeDescription(range); 297 fputs("\n", stdout); 298 } 299 return layoutTestController()->acceptsEditing(); 300 } 301 302 bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action) 303 { 304 if (layoutTestController()->shouldDumpEditingCallbacks()) { 305 fputs("EDITING DELEGATE: shouldInsertNode:", stdout); 306 printNodeDescription(node, 0); 307 fputs(" replacingDOMRange:", stdout); 308 printRangeDescription(range); 309 printf(" givenAction:%s\n", editingActionDescription(action).c_str()); 310 } 311 return layoutTestController()->acceptsEditing(); 312 } 313 314 bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action) 315 { 316 if (layoutTestController()->shouldDumpEditingCallbacks()) { 317 printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data()); 318 printRangeDescription(range); 319 printf(" givenAction:%s\n", editingActionDescription(action).c_str()); 320 } 321 return layoutTestController()->acceptsEditing(); 322 } 323 324 bool WebViewHost::shouldChangeSelectedRange( 325 const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting) 326 { 327 if (layoutTestController()->shouldDumpEditingCallbacks()) { 328 fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout); 329 printRangeDescription(fromRange); 330 fputs(" toDOMRange:", stdout); 331 printRangeDescription(toRange); 332 printf(" affinity:%s stillSelecting:%s\n", 333 textAffinityDescription(affinity).c_str(), 334 (stillSelecting ? "TRUE" : "FALSE")); 335 } 336 return layoutTestController()->acceptsEditing(); 337 } 338 339 bool WebViewHost::shouldDeleteRange(const WebRange& range) 340 { 341 if (layoutTestController()->shouldDumpEditingCallbacks()) { 342 fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout); 343 printRangeDescription(range); 344 fputs("\n", stdout); 345 } 346 return layoutTestController()->acceptsEditing(); 347 } 348 349 bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range) 350 { 351 if (layoutTestController()->shouldDumpEditingCallbacks()) { 352 printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data()); 353 printRangeDescription(range); 354 fputs("\n", stdout); 355 } 356 return layoutTestController()->acceptsEditing(); 357 } 358 359 bool WebViewHost::isSmartInsertDeleteEnabled() 360 { 361 return m_smartInsertDeleteEnabled; 362 } 363 364 bool WebViewHost::isSelectTrailingWhitespaceEnabled() 365 { 366 return m_selectTrailingWhitespaceEnabled; 367 } 368 369 void WebViewHost::didBeginEditing() 370 { 371 if (!layoutTestController()->shouldDumpEditingCallbacks()) 372 return; 373 fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout); 374 } 375 376 void WebViewHost::didChangeSelection(bool isEmptySelection) 377 { 378 if (layoutTestController()->shouldDumpEditingCallbacks()) 379 fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout); 380 // No need to update clipboard with the selected text in DRT. 381 } 382 383 void WebViewHost::didChangeContents() 384 { 385 if (!layoutTestController()->shouldDumpEditingCallbacks()) 386 return; 387 fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout); 388 } 389 390 void WebViewHost::didEndEditing() 391 { 392 if (!layoutTestController()->shouldDumpEditingCallbacks()) 393 return; 394 fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout); 395 } 396 397 bool WebViewHost::handleCurrentKeyboardEvent() 398 { 399 if (m_editCommandName.empty()) 400 return false; 401 WebFrame* frame = webView()->focusedFrame(); 402 if (!frame) 403 return false; 404 405 return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue)); 406 } 407 408 void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions) 409 { 410 // Check the spelling of the given text. 411 m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength); 412 } 413 414 void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion) 415 { 416 m_lastRequestedTextCheckingCompletion = completion; 417 m_lastRequestedTextCheckString = text; 418 postDelayedTask(new HostMethodTask(this, &WebViewHost::finishLastTextCheck), 0); 419 } 420 421 void WebViewHost::finishLastTextCheck() 422 { 423 Vector<WebTextCheckingResult> results; 424 // FIXME: Do the grammar check. 425 int offset = 0; 426 String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length()); 427 while (text.length()) { 428 int misspelledPosition = 0; 429 int misspelledLength = 0; 430 m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength); 431 if (!misspelledLength) 432 break; 433 results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength)); 434 text = text.substring(misspelledPosition + misspelledLength); 435 offset += misspelledPosition; 436 } 437 438 m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results); 439 m_lastRequestedTextCheckingCompletion = 0; 440 } 441 442 443 WebString WebViewHost::autoCorrectWord(const WebString&) 444 { 445 // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm') 446 // does. (If this function returns a non-empty string, WebKit replaces the 447 // given misspelled string with the result one. This process executes some 448 // editor commands and causes layout-test failures.) 449 return WebString(); 450 } 451 452 void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message) 453 { 454 printf("ALERT: %s\n", message.utf8().data()); 455 } 456 457 bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message) 458 { 459 printf("CONFIRM: %s\n", message.utf8().data()); 460 return true; 461 } 462 463 bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message, 464 const WebString& defaultValue, WebString*) 465 { 466 printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data()); 467 return true; 468 } 469 470 bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString&) 471 { 472 return true; // Allow window closure. 473 } 474 475 void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData) 476 { 477 m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData)); 478 } 479 480 void WebViewHost::clearContextMenuData() 481 { 482 m_lastContextMenuData.clear(); 483 } 484 485 WebContextMenuData* WebViewHost::lastContextMenuData() const 486 { 487 return m_lastContextMenuData.get(); 488 } 489 490 void WebViewHost::setStatusText(const WebString& text) 491 { 492 if (!layoutTestController()->shouldDumpStatusCallbacks()) 493 return; 494 // When running tests, write to stdout. 495 printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data()); 496 } 497 498 void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&) 499 { 500 WebDragData mutableDragData = data; 501 if (layoutTestController()->shouldAddFileToPasteboard()) { 502 // Add a file called DRTFakeFile to the drag&drop clipboard. 503 addDRTFakeFileToDataObject(&mutableDragData); 504 } 505 506 // When running a test, we need to fake a drag drop operation otherwise 507 // Windows waits for real mouse events to know when the drag is over. 508 m_shell->eventSender()->doDragDrop(mutableDragData, mask); 509 } 510 511 void WebViewHost::navigateBackForwardSoon(int offset) 512 { 513 navigationController()->goToOffset(offset); 514 } 515 516 int WebViewHost::historyBackListCount() 517 { 518 return navigationController()->lastCommittedEntryIndex(); 519 } 520 521 int WebViewHost::historyForwardListCount() 522 { 523 int currentIndex =navigationController()->lastCommittedEntryIndex(); 524 return navigationController()->entryCount() - currentIndex - 1; 525 } 526 527 void WebViewHost::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification) 528 { 529 if (notification == WebAccessibilityNotificationFocusedUIElementChanged) 530 m_shell->accessibilityController()->setFocusedElement(obj); 531 532 if (m_shell->accessibilityController()->shouldDumpAccessibilityNotifications()) { 533 printf("AccessibilityNotification - "); 534 535 switch (notification) { 536 case WebAccessibilityNotificationActiveDescendantChanged: 537 printf("ActiveDescendantChanged"); 538 break; 539 case WebAccessibilityNotificationCheckedStateChanged: 540 printf("CheckedStateChanged"); 541 break; 542 case WebAccessibilityNotificationChildrenChanged: 543 printf("ChildrenChanged"); 544 break; 545 case WebAccessibilityNotificationFocusedUIElementChanged: 546 printf("FocusedUIElementChanged"); 547 break; 548 case WebAccessibilityNotificationLayoutComplete: 549 printf("LayoutComplete"); 550 break; 551 case WebAccessibilityNotificationLoadComplete: 552 printf("LoadComplete"); 553 break; 554 case WebAccessibilityNotificationSelectedChildrenChanged: 555 printf("SelectedChildrenChanged"); 556 break; 557 case WebAccessibilityNotificationSelectedTextChanged: 558 printf("SelectedTextChanged"); 559 break; 560 case WebAccessibilityNotificationValueChanged: 561 printf("ValueChanged"); 562 break; 563 case WebAccessibilityNotificationScrolledToAnchor: 564 printf("ScrolledToAnchor"); 565 break; 566 case WebAccessibilityNotificationLiveRegionChanged: 567 printf("LiveRegionChanged"); 568 break; 569 case WebAccessibilityNotificationMenuListValueChanged: 570 printf("MenuListValueChanged"); 571 break; 572 case WebAccessibilityNotificationRowCountChanged: 573 printf("RowCountChanged"); 574 break; 575 case WebAccessibilityNotificationRowCollapsed: 576 printf("RowCollapsed"); 577 break; 578 case WebAccessibilityNotificationRowExpanded: 579 printf("RowExpanded"); 580 break; 581 default: 582 break; 583 } 584 585 WebKit::WebNode node = obj.node(); 586 if (!node.isNull() && node.isElementNode()) { 587 WebKit::WebElement element = node.to<WebKit::WebElement>(); 588 if (element.hasAttribute("id")) 589 printf(" - id:%s", element.getAttribute("id").utf8().data()); 590 } 591 592 printf("\n"); 593 } 594 } 595 596 WebNotificationPresenter* WebViewHost::notificationPresenter() 597 { 598 return m_shell->notificationPresenter(); 599 } 600 601 WebKit::WebGeolocationClient* WebViewHost::geolocationClient() 602 { 603 return geolocationClientMock(); 604 } 605 606 WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock() 607 { 608 if (!m_geolocationClientMock) 609 m_geolocationClientMock.set(WebGeolocationClientMock::create()); 610 return m_geolocationClientMock.get(); 611 } 612 613 WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener) 614 { 615 if (!m_speechInputControllerMock) 616 m_speechInputControllerMock.set(WebSpeechInputControllerMock::create(listener)); 617 return m_speechInputControllerMock.get(); 618 } 619 620 WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock() 621 { 622 if (!m_deviceOrientationClientMock.get()) 623 m_deviceOrientationClientMock.set(WebDeviceOrientationClientMock::create()); 624 return m_deviceOrientationClientMock.get(); 625 } 626 627 MockSpellCheck* WebViewHost::mockSpellCheck() 628 { 629 return &m_spellcheck; 630 } 631 632 WebDeviceOrientationClient* WebViewHost::deviceOrientationClient() 633 { 634 return deviceOrientationClientMock(); 635 } 636 637 // WebWidgetClient ----------------------------------------------------------- 638 639 void WebViewHost::didInvalidateRect(const WebRect& rect) 640 { 641 updatePaintRect(rect); 642 } 643 644 void WebViewHost::didScrollRect(int, int, const WebRect& clipRect) 645 { 646 // This is used for optimizing painting when the renderer is scrolled. We're 647 // currently not doing any optimizations so just invalidate the region. 648 didInvalidateRect(clipRect); 649 } 650 651 void WebViewHost::scheduleComposite() 652 { 653 WebSize widgetSize = webWidget()->size(); 654 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); 655 didInvalidateRect(clientRect); 656 } 657 658 #if ENABLE(REQUEST_ANIMATION_FRAME) 659 void WebViewHost::scheduleAnimation() 660 { 661 postDelayedTask(new HostMethodTask(this, &WebViewHost::scheduleComposite), 0); 662 } 663 #endif 664 665 void WebViewHost::didFocus() 666 { 667 m_shell->setFocus(webWidget(), true); 668 } 669 670 void WebViewHost::didBlur() 671 { 672 m_shell->setFocus(webWidget(), false); 673 } 674 675 WebScreenInfo WebViewHost::screenInfo() 676 { 677 // We don't need to set actual values. 678 WebScreenInfo info; 679 info.depth = 24; 680 info.depthPerComponent = 8; 681 info.isMonochrome = false; 682 info.rect = WebRect(0, 0, screenWidth, screenHeight); 683 // Use values different from info.rect for testing. 684 info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder, 685 screenWidth - screenUnavailableBorder * 2, 686 screenHeight - screenUnavailableBorder * 2); 687 return info; 688 } 689 690 void WebViewHost::show(WebNavigationPolicy) 691 { 692 m_hasWindow = true; 693 WebSize size = webWidget()->size(); 694 updatePaintRect(WebRect(0, 0, size.width, size.height)); 695 } 696 697 698 699 void WebViewHost::closeWidget() 700 { 701 m_hasWindow = false; 702 m_shell->closeWindow(this); 703 // No more code here, we should be deleted at this point. 704 } 705 706 void WebViewHost::closeWidgetSoon() 707 { 708 postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0); 709 } 710 711 void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo) 712 { 713 if (!hasWindow()) 714 return; 715 m_currentCursor = cursorInfo; 716 } 717 718 WebRect WebViewHost::windowRect() 719 { 720 return m_windowRect; 721 } 722 723 void WebViewHost::setWindowRect(const WebRect& rect) 724 { 725 m_windowRect = rect; 726 const int border2 = TestShell::virtualWindowBorder * 2; 727 if (m_windowRect.width <= border2) 728 m_windowRect.width = 1 + border2; 729 if (m_windowRect.height <= border2) 730 m_windowRect.height = 1 + border2; 731 int width = m_windowRect.width - border2; 732 int height = m_windowRect.height - border2; 733 discardBackingStore(); 734 webWidget()->resize(WebSize(width, height)); 735 updatePaintRect(WebRect(0, 0, width, height)); 736 } 737 738 WebRect WebViewHost::rootWindowRect() 739 { 740 return windowRect(); 741 } 742 743 WebRect WebViewHost::windowResizerRect() 744 { 745 // Not necessary. 746 return WebRect(); 747 } 748 749 void WebViewHost::runModal() 750 { 751 bool oldState = webkit_support::MessageLoopNestableTasksAllowed(); 752 webkit_support::MessageLoopSetNestableTasksAllowed(true); 753 m_inModalLoop = true; 754 webkit_support::RunMessageLoop(); 755 webkit_support::MessageLoopSetNestableTasksAllowed(oldState); 756 } 757 758 // WebFrameClient ------------------------------------------------------------ 759 760 WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params) 761 { 762 return webkit_support::CreateWebPlugin(frame, params); 763 } 764 765 WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*) 766 { 767 return new TestWebWorker(); 768 } 769 770 WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client) 771 { 772 return webkit_support::CreateMediaPlayer(frame, client); 773 } 774 775 WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client) 776 { 777 return webkit_support::CreateApplicationCacheHost(frame, client); 778 } 779 780 bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings) 781 { 782 return enabledPerSettings; 783 } 784 785 bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings) 786 { 787 return enabledPerSettings; 788 } 789 790 void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy) 791 { 792 ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab); 793 WebViewHost* another = m_shell->createNewWindow(request.url()); 794 if (another) 795 another->show(policy); 796 } 797 798 WebNavigationPolicy WebViewHost::decidePolicyForNavigation( 799 WebFrame*, const WebURLRequest& request, 800 WebNavigationType type, const WebNode& originatingNode, 801 WebNavigationPolicy defaultPolicy, bool isRedirect) 802 { 803 WebNavigationPolicy result; 804 if (!m_policyDelegateEnabled) 805 return defaultPolicy; 806 807 printf("Policy delegate: attempt to load %s with navigation type '%s'", 808 URLDescription(request.url()).c_str(), webNavigationTypeToString(type)); 809 if (!originatingNode.isNull()) { 810 fputs(" originating from ", stdout); 811 printNodeDescription(originatingNode, 0); 812 } 813 fputs("\n", stdout); 814 if (m_policyDelegateIsPermissive) 815 result = WebKit::WebNavigationPolicyCurrentTab; 816 else 817 result = WebKit::WebNavigationPolicyIgnore; 818 819 if (m_policyDelegateShouldNotifyDone) 820 layoutTestController()->policyDelegateDone(); 821 return result; 822 } 823 824 bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request) 825 { 826 GURL url = request.url(); 827 // Just reject the scheme used in 828 // LayoutTests/http/tests/misc/redirect-to-external-url.html 829 return !url.SchemeIs("spaceballs"); 830 } 831 832 WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request) 833 { 834 WebURLError error; 835 // A WebKit layout test expects the following values. 836 // unableToImplementPolicyWithError() below prints them. 837 error.domain = WebString::fromUTF8("WebKitErrorDomain"); 838 error.reason = 101; 839 error.unreachableURL = request.url(); 840 return error; 841 } 842 843 WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request) 844 { 845 return webkit_support::CreateCancelledError(request); 846 } 847 848 void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error) 849 { 850 printf("Policy delegate: unable to implement policy with error domain '%s', " 851 "error code %d, in frame '%s'\n", 852 error.domain.utf8().data(), error.reason, frame->name().utf8().data()); 853 } 854 855 void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to, 856 double interval, double fire_time) 857 { 858 if (!m_shell->shouldDumpFrameLoadCallbacks()) 859 return; 860 printFrameDescription(frame); 861 printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data()); 862 } 863 864 void WebViewHost::didCancelClientRedirect(WebFrame* frame) 865 { 866 if (!m_shell->shouldDumpFrameLoadCallbacks()) 867 return; 868 printFrameDescription(frame); 869 fputs(" - didCancelClientRedirectForFrame\n", stdout); 870 } 871 872 void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds) 873 { 874 ds->setExtraData(m_pendingExtraData.leakPtr()); 875 if (!layoutTestController()->deferMainResourceDataLoad()) 876 ds->setDeferMainResourceDataLoad(false); 877 } 878 879 void WebViewHost::didStartProvisionalLoad(WebFrame* frame) 880 { 881 if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks()) 882 printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n"); 883 if (m_shell->shouldDumpFrameLoadCallbacks()) { 884 printFrameDescription(frame); 885 fputs(" - didStartProvisionalLoadForFrame\n", stdout); 886 } 887 888 if (!m_topLoadingFrame) 889 m_topLoadingFrame = frame; 890 891 if (layoutTestController()->stopProvisionalFrameLoads()) { 892 printFrameDescription(frame); 893 fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout); 894 frame->stopLoading(); 895 } 896 updateAddressBar(frame->view()); 897 } 898 899 void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame) 900 { 901 if (m_shell->shouldDumpFrameLoadCallbacks()) { 902 printFrameDescription(frame); 903 fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout); 904 } 905 updateAddressBar(frame->view()); 906 } 907 908 void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error) 909 { 910 if (m_shell->shouldDumpFrameLoadCallbacks()) { 911 printFrameDescription(frame); 912 fputs(" - didFailProvisionalLoadWithError\n", stdout); 913 } 914 915 locationChangeDone(frame); 916 917 // Don't display an error page if we're running layout tests, because 918 // DumpRenderTree doesn't. 919 } 920 921 void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation) 922 { 923 if (m_shell->shouldDumpFrameLoadCallbacks()) { 924 printFrameDescription(frame); 925 fputs(" - didCommitLoadForFrame\n", stdout); 926 } 927 updateForCommittedLoad(frame, isNewNavigation); 928 } 929 930 void WebViewHost::didClearWindowObject(WebFrame* frame) 931 { 932 m_shell->bindJSObjectsToWindow(frame); 933 } 934 935 void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction) 936 { 937 WebCString title8 = title.utf8(); 938 939 if (m_shell->shouldDumpFrameLoadCallbacks()) { 940 printFrameDescription(frame); 941 printf(" - didReceiveTitle: %s\n", title8.data()); 942 } 943 944 if (layoutTestController()->shouldDumpTitleChanges()) 945 printf("TITLE CHANGED: %s\n", title8.data()); 946 947 setPageTitle(title); 948 layoutTestController()->setTitleTextDirection(direction); 949 } 950 951 void WebViewHost::didFinishDocumentLoad(WebFrame* frame) 952 { 953 if (m_shell->shouldDumpFrameLoadCallbacks()) { 954 printFrameDescription(frame); 955 fputs(" - didFinishDocumentLoadForFrame\n", stdout); 956 } else { 957 unsigned pendingUnloadEvents = frame->unloadListenerCount(); 958 if (pendingUnloadEvents) { 959 printFrameDescription(frame); 960 printf(" - has %u onunload handler(s)\n", pendingUnloadEvents); 961 } 962 } 963 } 964 965 void WebViewHost::didHandleOnloadEvents(WebFrame* frame) 966 { 967 if (m_shell->shouldDumpFrameLoadCallbacks()) { 968 printFrameDescription(frame); 969 fputs(" - didHandleOnloadEventsForFrame\n", stdout); 970 } 971 } 972 973 void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error) 974 { 975 if (m_shell->shouldDumpFrameLoadCallbacks()) { 976 printFrameDescription(frame); 977 fputs(" - didFailLoadWithError\n", stdout); 978 } 979 locationChangeDone(frame); 980 } 981 982 void WebViewHost::didFinishLoad(WebFrame* frame) 983 { 984 if (m_shell->shouldDumpFrameLoadCallbacks()) { 985 printFrameDescription(frame); 986 fputs(" - didFinishLoadForFrame\n", stdout); 987 } 988 updateAddressBar(frame->view()); 989 locationChangeDone(frame); 990 } 991 992 void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation) 993 { 994 frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr()); 995 996 updateForCommittedLoad(frame, isNewNavigation); 997 } 998 999 void WebViewHost::didChangeLocationWithinPage(WebFrame* frame) 1000 { 1001 if (m_shell->shouldDumpFrameLoadCallbacks()) { 1002 printFrameDescription(frame); 1003 fputs(" - didChangeLocationWithinPageForFrame\n", stdout); 1004 } 1005 } 1006 1007 void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request) 1008 { 1009 if (!m_shell->shouldDumpResourceLoadCallbacks()) 1010 return; 1011 ASSERT(!m_resourceIdentifierMap.contains(identifier)); 1012 m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec())); 1013 } 1014 1015 void WebViewHost::removeIdentifierForRequest(unsigned identifier) 1016 { 1017 m_resourceIdentifierMap.remove(identifier); 1018 } 1019 1020 void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse) 1021 { 1022 // Need to use GURL for host() and SchemeIs() 1023 GURL url = request.url(); 1024 string requestURL = url.possibly_invalid_spec(); 1025 1026 if (layoutTestController()->shouldDumpResourceLoadCallbacks()) { 1027 GURL mainDocumentURL = request.firstPartyForCookies(); 1028 printResourceDescription(identifier); 1029 printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s," 1030 " http method %s> redirectResponse ", 1031 descriptionSuitableForTestResult(requestURL).c_str(), 1032 URLDescription(mainDocumentURL).c_str(), 1033 request.httpMethod().utf8().data()); 1034 printResponseDescription(redirectResponse); 1035 fputs("\n", stdout); 1036 } 1037 1038 if (!redirectResponse.isNull() && m_blocksRedirects) { 1039 fputs("Returning null for this redirect\n", stdout); 1040 // To block the request, we set its URL to an empty one. 1041 request.setURL(WebURL()); 1042 return; 1043 } 1044 1045 if (m_requestReturnNull) { 1046 // To block the request, we set its URL to an empty one. 1047 request.setURL(WebURL()); 1048 return; 1049 } 1050 1051 string host = url.host(); 1052 // 255.255.255.255 is used in some tests that expect to get back an error. 1053 if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https")) 1054 && host != "127.0.0.1" 1055 && host != "255.255.255.255" 1056 && host != "localhost" 1057 && !m_shell->allowExternalPages()) { 1058 printf("Blocked access to external URL %s\n", requestURL.c_str()); 1059 1060 // To block the request, we set its URL to an empty one. 1061 request.setURL(WebURL()); 1062 return; 1063 } 1064 1065 HashSet<String>::const_iterator end = m_clearHeaders.end(); 1066 for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header) 1067 request.clearHTTPHeaderField(WebString(header->characters(), header->length())); 1068 1069 // Set the new substituted URL. 1070 request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec())); 1071 } 1072 1073 void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response) 1074 { 1075 if (m_shell->shouldDumpResourceLoadCallbacks()) { 1076 printResourceDescription(identifier); 1077 fputs(" - didReceiveResponse ", stdout); 1078 printResponseDescription(response); 1079 fputs("\n", stdout); 1080 } 1081 if (m_shell->shouldDumpResourceResponseMIMETypes()) { 1082 GURL url = response.url(); 1083 WebString mimeType = response.mimeType(); 1084 printf("%s has MIME type %s\n", 1085 url.ExtractFileName().c_str(), 1086 // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream 1087 mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data()); 1088 } 1089 } 1090 1091 void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier) 1092 { 1093 if (m_shell->shouldDumpResourceLoadCallbacks()) { 1094 printResourceDescription(identifier); 1095 fputs(" - didFinishLoading\n", stdout); 1096 } 1097 removeIdentifierForRequest(identifier); 1098 } 1099 1100 void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error) 1101 { 1102 if (m_shell->shouldDumpResourceLoadCallbacks()) { 1103 printResourceDescription(identifier); 1104 fputs(" - didFailLoadingWithError: ", stdout); 1105 fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout); 1106 fputs("\n", stdout); 1107 } 1108 removeIdentifierForRequest(identifier); 1109 } 1110 1111 void WebViewHost::didDisplayInsecureContent(WebFrame*) 1112 { 1113 if (m_shell->shouldDumpFrameLoadCallbacks()) 1114 fputs("didDisplayInsecureContent\n", stdout); 1115 } 1116 1117 void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL) 1118 { 1119 if (m_shell->shouldDumpFrameLoadCallbacks()) 1120 fputs("didRunInsecureContent\n", stdout); 1121 } 1122 1123 bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings) 1124 { 1125 return enabledPerSettings; 1126 } 1127 1128 void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks) 1129 { 1130 webkit_support::OpenFileSystem(frame, type, size, create, callbacks); 1131 } 1132 1133 // Public functions ----------------------------------------------------------- 1134 1135 WebViewHost::WebViewHost(TestShell* shell) 1136 : m_shell(shell) 1137 , m_webWidget(0) 1138 , m_lastRequestedTextCheckingCompletion(0) 1139 { 1140 reset(); 1141 } 1142 1143 WebViewHost::~WebViewHost() 1144 { 1145 // DevTools frontend page is supposed to be navigated only once and 1146 // loading another URL in that Page is an error. 1147 if (m_shell->devToolsWebView() != this) { 1148 // Navigate to an empty page to fire all the destruction logic for the 1149 // current page. 1150 loadURLForFrame(GURL("about:blank"), WebString()); 1151 } 1152 1153 webWidget()->close(); 1154 1155 if (m_inModalLoop) 1156 webkit_support::QuitMessageLoop(); 1157 } 1158 1159 void WebViewHost::setWebWidget(WebKit::WebWidget* widget) 1160 { 1161 m_webWidget = widget; 1162 webView()->setSpellCheckClient(this); 1163 } 1164 1165 WebView* WebViewHost::webView() const 1166 { 1167 ASSERT(m_webWidget); 1168 // DRT does not support popup widgets. So m_webWidget is always a WebView. 1169 return static_cast<WebView*>(m_webWidget); 1170 } 1171 1172 WebWidget* WebViewHost::webWidget() const 1173 { 1174 ASSERT(m_webWidget); 1175 return m_webWidget; 1176 } 1177 1178 void WebViewHost::reset() 1179 { 1180 m_policyDelegateEnabled = false; 1181 m_policyDelegateIsPermissive = false; 1182 m_policyDelegateShouldNotifyDone = false; 1183 m_topLoadingFrame = 0; 1184 m_pageId = -1; 1185 m_lastPageIdUpdated = -1; 1186 m_hasWindow = false; 1187 m_inModalLoop = false; 1188 m_smartInsertDeleteEnabled = true; 1189 #if OS(WINDOWS) 1190 m_selectTrailingWhitespaceEnabled = true; 1191 #else 1192 m_selectTrailingWhitespaceEnabled = false; 1193 #endif 1194 m_blocksRedirects = false; 1195 m_requestReturnNull = false; 1196 m_isPainting = false; 1197 m_canvas.clear(); 1198 1199 m_navigationController.set(new TestNavigationController(this)); 1200 1201 m_pendingExtraData.clear(); 1202 m_resourceIdentifierMap.clear(); 1203 m_clearHeaders.clear(); 1204 m_editCommandName.clear(); 1205 m_editCommandValue.clear(); 1206 1207 if (m_geolocationClientMock.get()) 1208 m_geolocationClientMock->resetMock(); 1209 1210 if (m_speechInputControllerMock.get()) 1211 m_speechInputControllerMock->clearResults(); 1212 1213 m_currentCursor = WebCursorInfo(); 1214 m_windowRect = WebRect(); 1215 m_paintRect = WebRect(); 1216 1217 if (m_webWidget) { 1218 webView()->mainFrame()->setName(WebString()); 1219 webView()->settings()->setMinimumTimerInterval(webkit_support::GetForegroundTabTimerInterval()); 1220 } 1221 } 1222 1223 void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled) 1224 { 1225 m_selectTrailingWhitespaceEnabled = enabled; 1226 // In upstream WebKit, smart insert/delete is mutually exclusive with select 1227 // trailing whitespace, however, we allow both because Chromium on Windows 1228 // allows both. 1229 } 1230 1231 void WebViewHost::setSmartInsertDeleteEnabled(bool enabled) 1232 { 1233 m_smartInsertDeleteEnabled = enabled; 1234 // In upstream WebKit, smart insert/delete is mutually exclusive with select 1235 // trailing whitespace, however, we allow both because Chromium on Windows 1236 // allows both. 1237 } 1238 1239 void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive) 1240 { 1241 m_policyDelegateEnabled = isCustom; 1242 m_policyDelegateIsPermissive = isPermissive; 1243 } 1244 1245 void WebViewHost::waitForPolicyDelegate() 1246 { 1247 m_policyDelegateEnabled = true; 1248 m_policyDelegateShouldNotifyDone = true; 1249 } 1250 1251 void WebViewHost::setEditCommand(const string& name, const string& value) 1252 { 1253 m_editCommandName = name; 1254 m_editCommandValue = value; 1255 } 1256 1257 void WebViewHost::clearEditCommand() 1258 { 1259 m_editCommandName.clear(); 1260 m_editCommandValue.clear(); 1261 } 1262 1263 void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName) 1264 { 1265 if (!url.isValid()) 1266 return; 1267 TestShell::resizeWindowForTest(this, url); 1268 navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), frameName).get()); 1269 } 1270 1271 bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload) 1272 { 1273 // Get the right target frame for the entry. 1274 WebFrame* frame = webView()->mainFrame(); 1275 if (!entry.targetFrame().isEmpty()) 1276 frame = webView()->findFrameByName(entry.targetFrame()); 1277 1278 // TODO(mpcomplete): should we clear the target frame, or should 1279 // back/forward navigations maintain the target frame? 1280 1281 // A navigation resulting from loading a javascript URL should not be 1282 // treated as a browser initiated event. Instead, we want it to look as if 1283 // the page initiated any load resulting from JS execution. 1284 if (!GURL(entry.URL()).SchemeIs("javascript")) 1285 setPendingExtraData(new TestShellExtraData(entry.pageID())); 1286 1287 // If we are reloading, then WebKit will use the state of the current page. 1288 // Otherwise, we give it the state to navigate to. 1289 if (reload) { 1290 frame->reload(false); 1291 } else if (!entry.contentState().isNull()) { 1292 ASSERT(entry.pageID() != -1); 1293 frame->loadHistoryItem(entry.contentState()); 1294 } else { 1295 ASSERT(entry.pageID() == -1); 1296 frame->loadRequest(WebURLRequest(entry.URL())); 1297 } 1298 1299 // In case LoadRequest failed before DidCreateDataSource was called. 1300 setPendingExtraData(0); 1301 1302 // Restore focus to the main frame prior to loading new request. 1303 // This makes sure that we don't have a focused iframe. Otherwise, that 1304 // iframe would keep focus when the SetFocus called immediately after 1305 // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 1306 // for more details). 1307 webView()->setFocusedFrame(frame); 1308 m_shell->setFocus(webView(), true); 1309 1310 return true; 1311 } 1312 1313 // Private functions ---------------------------------------------------------- 1314 1315 LayoutTestController* WebViewHost::layoutTestController() const 1316 { 1317 return m_shell->layoutTestController(); 1318 } 1319 1320 void WebViewHost::updateAddressBar(WebView* webView) 1321 { 1322 WebFrame* mainFrame = webView->mainFrame(); 1323 WebDataSource* dataSource = mainFrame->dataSource(); 1324 if (!dataSource) 1325 dataSource = mainFrame->provisionalDataSource(); 1326 if (!dataSource) 1327 return; 1328 1329 setAddressBarURL(dataSource->request().url()); 1330 } 1331 1332 void WebViewHost::locationChangeDone(WebFrame* frame) 1333 { 1334 if (frame != m_topLoadingFrame) 1335 return; 1336 m_topLoadingFrame = 0; 1337 layoutTestController()->locationChangeDone(); 1338 } 1339 1340 void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation) 1341 { 1342 // Code duplicated from RenderView::DidCommitLoadForFrame. 1343 TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData()); 1344 1345 if (isNewNavigation) { 1346 // New navigation. 1347 updateSessionHistory(frame); 1348 m_pageId = nextPageID++; 1349 } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) { 1350 // This is a successful session history navigation! 1351 updateSessionHistory(frame); 1352 m_pageId = extraData->pendingPageID; 1353 } 1354 1355 // Don't update session history multiple times. 1356 if (extraData) 1357 extraData->requestCommitted = true; 1358 1359 updateURL(frame); 1360 } 1361 1362 void WebViewHost::updateURL(WebFrame* frame) 1363 { 1364 WebDataSource* ds = frame->dataSource(); 1365 ASSERT(ds); 1366 const WebURLRequest& request = ds->request(); 1367 RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create()); 1368 1369 // The referrer will be empty on https->http transitions. It 1370 // would be nice if we could get the real referrer from somewhere. 1371 entry->setPageID(m_pageId); 1372 if (ds->hasUnreachableURL()) 1373 entry->setURL(ds->unreachableURL()); 1374 else 1375 entry->setURL(request.url()); 1376 1377 const WebHistoryItem& historyItem = frame->currentHistoryItem(); 1378 if (!historyItem.isNull()) 1379 entry->setContentState(historyItem); 1380 1381 navigationController()->didNavigateToEntry(entry.get()); 1382 updateAddressBar(frame->view()); 1383 m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId); 1384 } 1385 1386 void WebViewHost::updateSessionHistory(WebFrame* frame) 1387 { 1388 // If we have a valid page ID at this point, then it corresponds to the page 1389 // we are navigating away from. Otherwise, this is the first navigation, so 1390 // there is no past session history to record. 1391 if (m_pageId == -1) 1392 return; 1393 1394 TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId); 1395 if (!entry) 1396 return; 1397 1398 const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem(); 1399 if (historyItem.isNull()) 1400 return; 1401 1402 entry->setContentState(historyItem); 1403 } 1404 1405 void WebViewHost::printFrameDescription(WebFrame* webframe) 1406 { 1407 string name8 = webframe->name().utf8(); 1408 if (webframe == webView()->mainFrame()) { 1409 if (!name8.length()) { 1410 fputs("main frame", stdout); 1411 return; 1412 } 1413 printf("main frame \"%s\"", name8.c_str()); 1414 return; 1415 } 1416 if (!name8.length()) { 1417 fputs("frame (anonymous)", stdout); 1418 return; 1419 } 1420 printf("frame \"%s\"", name8.c_str()); 1421 } 1422 1423 void WebViewHost::printFrameUserGestureStatus(WebFrame* webframe, const char* msg) 1424 { 1425 bool isUserGesture = webframe->isProcessingUserGesture(); 1426 printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg); 1427 } 1428 1429 void WebViewHost::printResourceDescription(unsigned identifier) 1430 { 1431 ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier); 1432 printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>"); 1433 } 1434 1435 void WebViewHost::setPendingExtraData(TestShellExtraData* extraData) 1436 { 1437 m_pendingExtraData.set(extraData); 1438 } 1439 1440 void WebViewHost::setPageTitle(const WebString&) 1441 { 1442 // Nothing to do in layout test. 1443 } 1444 1445 void WebViewHost::setAddressBarURL(const WebURL&) 1446 { 1447 // Nothing to do in layout test. 1448 } 1449 1450 // Painting functions --------------------------------------------------------- 1451 1452 void WebViewHost::updatePaintRect(const WebRect& rect) 1453 { 1454 // m_paintRect = m_paintRect U rect 1455 if (rect.isEmpty()) 1456 return; 1457 if (m_paintRect.isEmpty()) { 1458 m_paintRect = rect; 1459 return; 1460 } 1461 int left = min(m_paintRect.x, rect.x); 1462 int top = min(m_paintRect.y, rect.y); 1463 int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width); 1464 int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height); 1465 m_paintRect = WebRect(left, top, right - left, bottom - top); 1466 } 1467 1468 void WebViewHost::paintRect(const WebRect& rect) 1469 { 1470 ASSERT(!m_isPainting); 1471 ASSERT(canvas()); 1472 m_isPainting = true; 1473 #if USE(CG) 1474 webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect); 1475 skia::EndPlatformPaint(canvas()); 1476 #else 1477 webWidget()->paint(canvas(), rect); 1478 #endif 1479 m_isPainting = false; 1480 } 1481 1482 void WebViewHost::paintInvalidatedRegion() 1483 { 1484 #if ENABLE(REQUEST_ANIMATION_FRAME) 1485 webWidget()->animate(); 1486 #endif 1487 webWidget()->layout(); 1488 WebSize widgetSize = webWidget()->size(); 1489 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); 1490 1491 // Paint the canvas if necessary. Allow painting to generate extra rects 1492 // for the first two calls. This is necessary because some WebCore rendering 1493 // objects update their layout only when painted. 1494 // Store the total area painted in total_paint. Then tell the gdk window 1495 // to update that area after we're done painting it. 1496 for (int i = 0; i < 3; ++i) { 1497 // m_paintRect = intersect(m_paintRect , clientRect) 1498 int left = max(m_paintRect.x, clientRect.x); 1499 int top = max(m_paintRect.y, clientRect.y); 1500 int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width); 1501 int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height); 1502 if (left >= right || top >= bottom) 1503 m_paintRect = WebRect(); 1504 else 1505 m_paintRect = WebRect(left, top, right - left, bottom - top); 1506 1507 if (m_paintRect.isEmpty()) 1508 continue; 1509 WebRect rect(m_paintRect); 1510 m_paintRect = WebRect(); 1511 paintRect(rect); 1512 } 1513 ASSERT(m_paintRect.isEmpty()); 1514 } 1515 1516 SkCanvas* WebViewHost::canvas() 1517 { 1518 if (m_canvas) 1519 return m_canvas.get(); 1520 WebSize widgetSize = webWidget()->size(); 1521 resetScrollRect(); 1522 m_canvas.set(skia::CreateBitmapCanvas( 1523 widgetSize.width, widgetSize.height, true)); 1524 return m_canvas.get(); 1525 } 1526 1527 void WebViewHost::resetScrollRect() 1528 { 1529 } 1530 1531 void WebViewHost::discardBackingStore() 1532 { 1533 m_canvas.clear(); 1534 } 1535 1536 // Paints the entire canvas a semi-transparent black (grayish). This is used 1537 // by the layout tests in fast/repaint. The alpha value matches upstream. 1538 void WebViewHost::displayRepaintMask() 1539 { 1540 canvas()->drawARGB(167, 0, 0, 0); 1541 } 1542