1/* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#import "WebChromeClient.h" 31 32#import "DOMElementInternal.h" 33#import "DOMNodeInternal.h" 34#import "PopupMenuMac.h" 35#import "SearchPopupMenuMac.h" 36#import "WebBasePluginPackage.h" 37#import "WebDefaultUIDelegate.h" 38#import "WebDelegateImplementationCaching.h" 39#import "WebElementDictionary.h" 40#import "WebFrameInternal.h" 41#import "WebFrameView.h" 42#import "WebHTMLViewInternal.h" 43#import "WebHistoryInternal.h" 44#import "WebKitFullScreenListener.h" 45#import "WebKitPrefix.h" 46#import "WebKitSystemInterface.h" 47#import "WebNSURLRequestExtras.h" 48#import "WebOpenPanelResultListener.h" 49#import "WebPlugin.h" 50#import "WebQuotaManager.h" 51#import "WebSecurityOriginInternal.h" 52#import "WebUIDelegatePrivate.h" 53#import "WebView.h" 54#import "WebViewInternal.h" 55#import <Foundation/Foundation.h> 56#import <WebCore/BlockExceptions.h> 57#import <WebCore/ColorChooser.h> 58#import <WebCore/ContextMenu.h> 59#import <WebCore/ContextMenuController.h> 60#import <WebCore/Cursor.h> 61#import <WebCore/Element.h> 62#import <WebCore/FileChooser.h> 63#import <WebCore/FileIconLoader.h> 64#import <WebCore/FloatRect.h> 65#import <WebCore/Frame.h> 66#import <WebCore/FrameLoadRequest.h> 67#import <WebCore/FrameView.h> 68#import <WebCore/GraphicsLayer.h> 69#import <WebCore/HTMLInputElement.h> 70#import <WebCore/HTMLNames.h> 71#import <WebCore/HTMLPlugInImageElement.h> 72#import <WebCore/HitTestResult.h> 73#import <WebCore/Icon.h> 74#import <WebCore/IntPoint.h> 75#import <WebCore/IntRect.h> 76#import <WebCore/NavigationAction.h> 77#import <WebCore/NotImplemented.h> 78#import <WebCore/Page.h> 79#import <WebCore/PlatformScreen.h> 80#import <WebCore/ResourceRequest.h> 81#import <WebCore/SerializedCryptoKeyWrap.h> 82#import <WebCore/Widget.h> 83#import <WebCore/WindowFeatures.h> 84#import <wtf/PassRefPtr.h> 85#import <wtf/Vector.h> 86#import <wtf/text/WTFString.h> 87 88#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 89#import "NetscapePluginHostManager.h" 90#endif 91 92#if PLATFORM(IOS) && ENABLE(GEOLOCATION) 93#import <WebCore/Geolocation.h> 94#endif 95 96#if PLATFORM(IOS) 97#import <WebCore/WAKClipView.h> 98#import <WebCore/WAKWindow.h> 99#import <WebCore/WebCoreThreadMessage.h> 100#endif 101 102NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource"; 103NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource"; 104NSString *WebConsoleMessageNetworkMessageSource = @"NetworkMessageSource"; 105NSString *WebConsoleMessageConsoleAPIMessageSource = @"ConsoleAPIMessageSource"; 106NSString *WebConsoleMessageStorageMessageSource = @"StorageMessageSource"; 107NSString *WebConsoleMessageAppCacheMessageSource = @"AppCacheMessageSource"; 108NSString *WebConsoleMessageRenderingMessageSource = @"RenderingMessageSource"; 109NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource"; 110NSString *WebConsoleMessageSecurityMessageSource = @"SecurityMessageSource"; 111NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource"; 112 113NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel"; 114NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel"; 115NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel"; 116NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel"; 117 118 119#if !PLATFORM(IOS) 120@interface NSApplication (WebNSApplicationDetails) 121- (NSCursor *)_cursorRectCursor; 122@end 123#endif 124 125@interface NSView (WebNSViewDetails) 126- (NSView *)_findLastViewInKeyViewLoop; 127@end 128 129// For compatibility with old SPI. 130@interface NSView (WebOldWebKitPlugInDetails) 131- (void)setIsSelected:(BOOL)isSelected; 132@end 133 134#if !PLATFORM(IOS) 135@interface NSWindow (AppKitSecretsIKnowAbout) 136- (NSRect)_growBoxRect; 137@end 138#endif 139 140using namespace WebCore; 141using namespace HTMLNames; 142 143WebChromeClient::WebChromeClient(WebView *webView) 144 : m_webView(webView) 145{ 146} 147 148void WebChromeClient::chromeDestroyed() 149{ 150 delete this; 151} 152 153// These functions scale between window and WebView coordinates because JavaScript/DOM operations 154// assume that the WebView and the window share the same coordinate system. 155 156void WebChromeClient::setWindowRect(const FloatRect& rect) 157{ 158#if !PLATFORM(IOS) 159 NSRect windowRect = toDeviceSpace(rect, [m_webView window]); 160 [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect]; 161#endif 162} 163 164FloatRect WebChromeClient::windowRect() 165{ 166#if !PLATFORM(IOS) 167 NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView]; 168 return toUserSpace(windowRect, [m_webView window]); 169#else 170 return FloatRect(); 171#endif 172} 173 174// FIXME: We need to add API for setting and getting this. 175FloatRect WebChromeClient::pageRect() 176{ 177 return [m_webView frame]; 178} 179 180void WebChromeClient::focus() 181{ 182 [[m_webView _UIDelegateForwarder] webViewFocus:m_webView]; 183} 184 185void WebChromeClient::unfocus() 186{ 187 [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView]; 188} 189 190bool WebChromeClient::canTakeFocus(FocusDirection) 191{ 192 // There's unfortunately no way to determine if we will become first responder again 193 // once we give it up, so we just have to guess that we won't. 194 return true; 195} 196 197void WebChromeClient::takeFocus(FocusDirection direction) 198{ 199#if !PLATFORM(IOS) 200 if (direction == FocusDirectionForward) { 201 // Since we're trying to move focus out of m_webView, and because 202 // m_webView may contain subviews within it, we ask it for the next key 203 // view of the last view in its key view loop. This makes m_webView 204 // behave as if it had no subviews, which is the behavior we want. 205 NSView *lastView = [m_webView _findLastViewInKeyViewLoop]; 206 // avoid triggering assertions if the WebView is the only thing in the key loop 207 if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView]) 208 return; 209 [[m_webView window] selectKeyViewFollowingView:lastView]; 210 } else { 211 // avoid triggering assertions if the WebView is the only thing in the key loop 212 if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView]) 213 return; 214 [[m_webView window] selectKeyViewPrecedingView:m_webView]; 215 } 216#endif 217} 218 219void WebChromeClient::focusedElementChanged(Element* element) 220{ 221 if (!element) 222 return; 223 if (!isHTMLInputElement(element)) 224 return; 225 226 HTMLInputElement* inputElement = toHTMLInputElement(element); 227 if (!inputElement->isText()) 228 return; 229 230 CallFormDelegate(m_webView, @selector(didFocusTextField:inFrame:), kit(inputElement), kit(inputElement->document().frame())); 231} 232 233void WebChromeClient::focusedFrameChanged(Frame*) 234{ 235} 236 237Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&) 238{ 239 id delegate = [m_webView UIDelegate]; 240 WebView *newWebView; 241 242#if ENABLE(FULLSCREEN_API) 243 if (frame->document() && frame->document()->webkitCurrentFullScreenElement()) 244 frame->document()->webkitCancelFullScreen(); 245#endif 246 247 if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) { 248 NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil; 249 NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil; 250 NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil; 251 NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil; 252 NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible]; 253 NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible]; 254 NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible]; 255 NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible]; 256 NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable]; 257 NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen]; 258 NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog]; 259 260 NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 261 menuBarVisible, @"menuBarVisible", 262 statusBarVisible, @"statusBarVisible", 263 toolBarVisible, @"toolBarVisible", 264 scrollbarsVisible, @"scrollbarsVisible", 265 resizable, @"resizable", 266 fullscreen, @"fullscreen", 267 dialog, @"dialog", 268 nil]; 269 270 if (x) 271 [dictFeatures setObject:x forKey:@"x"]; 272 if (y) 273 [dictFeatures setObject:y forKey:@"y"]; 274 if (width) 275 [dictFeatures setObject:width forKey:@"width"]; 276 if (height) 277 [dictFeatures setObject:height forKey:@"height"]; 278 279 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), nil, dictFeatures); 280 281 [dictFeatures release]; 282 [x release]; 283 [y release]; 284 [width release]; 285 [height release]; 286 [menuBarVisible release]; 287 [statusBarVisible release]; 288 [toolBarVisible release]; 289 [scrollbarsVisible release]; 290 [resizable release]; 291 [fullscreen release]; 292 [dialog release]; 293 } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) { 294 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), nil); 295 } else { 296 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), nil); 297 } 298 299#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 300 if (newWebView) 301 WebKit::NetscapePluginHostManager::shared().didCreateWindow(); 302#endif 303 304 return core(newWebView); 305} 306 307void WebChromeClient::show() 308{ 309 [[m_webView _UIDelegateForwarder] webViewShow:m_webView]; 310} 311 312bool WebChromeClient::canRunModal() 313{ 314 return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)]; 315} 316 317void WebChromeClient::runModal() 318{ 319 CallUIDelegate(m_webView, @selector(webViewRunModal:)); 320} 321 322void WebChromeClient::setToolbarsVisible(bool b) 323{ 324 [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b]; 325} 326 327bool WebChromeClient::toolbarsVisible() 328{ 329 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:)); 330} 331 332void WebChromeClient::setStatusbarVisible(bool b) 333{ 334 [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b]; 335} 336 337bool WebChromeClient::statusbarVisible() 338{ 339 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:)); 340} 341 342void WebChromeClient::setScrollbarsVisible(bool b) 343{ 344 [[[m_webView mainFrame] frameView] setAllowsScrolling:b]; 345} 346 347bool WebChromeClient::scrollbarsVisible() 348{ 349 return [[[m_webView mainFrame] frameView] allowsScrolling]; 350} 351 352void WebChromeClient::setMenubarVisible(bool) 353{ 354 // The menubar is always visible in Mac OS X. 355 return; 356} 357 358bool WebChromeClient::menubarVisible() 359{ 360 // The menubar is always visible in Mac OS X. 361 return true; 362} 363 364void WebChromeClient::setResizable(bool b) 365{ 366 [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b]; 367} 368 369inline static NSString *stringForMessageSource(MessageSource source) 370{ 371 switch (source) { 372 case MessageSource::XML: 373 return WebConsoleMessageXMLMessageSource; 374 case MessageSource::JS: 375 return WebConsoleMessageJSMessageSource; 376 case MessageSource::Network: 377 return WebConsoleMessageNetworkMessageSource; 378 case MessageSource::ConsoleAPI: 379 return WebConsoleMessageConsoleAPIMessageSource; 380 case MessageSource::Storage: 381 return WebConsoleMessageStorageMessageSource; 382 case MessageSource::AppCache: 383 return WebConsoleMessageAppCacheMessageSource; 384 case MessageSource::Rendering: 385 return WebConsoleMessageRenderingMessageSource; 386 case MessageSource::CSS: 387 return WebConsoleMessageCSSMessageSource; 388 case MessageSource::Security: 389 return WebConsoleMessageSecurityMessageSource; 390 case MessageSource::Other: 391 return WebConsoleMessageOtherMessageSource; 392 } 393 ASSERT_NOT_REACHED(); 394 return @""; 395} 396 397inline static NSString *stringForMessageLevel(MessageLevel level) 398{ 399 switch (level) { 400 case MessageLevel::Debug: 401 return WebConsoleMessageDebugMessageLevel; 402 case MessageLevel::Log: 403 return WebConsoleMessageLogMessageLevel; 404 case MessageLevel::Warning: 405 return WebConsoleMessageWarningMessageLevel; 406 case MessageLevel::Error: 407 return WebConsoleMessageErrorMessageLevel; 408 } 409 ASSERT_NOT_REACHED(); 410 return @""; 411} 412 413void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceURL) 414{ 415#if !PLATFORM(IOS) 416 id delegate = [m_webView UIDelegate]; 417#else 418 if (![m_webView _allowsMessaging]) 419 return; 420 421 id delegate = [m_webView _UIKitDelegate]; 422 // No delegate means nothing to send this data to so bail. 423 if (!delegate) 424 return; 425#endif 426 427 BOOL respondsToNewSelector = NO; 428 429 SEL selector = @selector(webView:addMessageToConsole:withSource:); 430 if ([delegate respondsToSelector:selector]) 431 respondsToNewSelector = YES; 432 else { 433 // The old selector only takes JSMessageSource messages. 434 if (source != MessageSource::JS) 435 return; 436 selector = @selector(webView:addMessageToConsole:); 437 if (![delegate respondsToSelector:selector]) 438 return; 439 } 440 441 NSString *messageSource = stringForMessageSource(source); 442 NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: 443 (NSString *)message, @"message", 444 [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber", 445 [NSNumber numberWithUnsignedInt:columnNumber], @"columnNumber", 446 (NSString *)sourceURL, @"sourceURL", 447 messageSource, @"MessageSource", 448 stringForMessageLevel(level), @"MessageLevel", 449 NULL]; 450 451#if PLATFORM(IOS) 452 [[[m_webView _UIKitDelegateForwarder] asyncForwarder] webView:m_webView addMessageToConsole:dictionary withSource:messageSource]; 453#else 454 if (respondsToNewSelector) 455 CallUIDelegate(m_webView, selector, dictionary, messageSource); 456 else 457 CallUIDelegate(m_webView, selector, dictionary); 458#endif 459 460 [dictionary release]; 461} 462 463bool WebChromeClient::canRunBeforeUnloadConfirmPanel() 464{ 465 return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)]; 466} 467 468bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 469{ 470 return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame)); 471} 472 473void WebChromeClient::closeWindowSoon() 474{ 475 // We need to remove the parent WebView from WebViewSets here, before it actually 476 // closes, to make sure that JavaScript code that executes before it closes 477 // can't find it. Otherwise, window.open will select a closed WebView instead of 478 // opening a new one <rdar://problem/3572585>. 479 480 // We also need to stop the load to prevent further parsing or JavaScript execution 481 // after the window has torn down <rdar://problem/4161660>. 482 483 // FIXME: This code assumes that the UI delegate will respond to a webViewClose 484 // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not. 485 // This approach is an inherent limitation of not making a close execute immediately 486 // after a call to window.close. 487 488 [m_webView setGroupName:nil]; 489 [m_webView stopLoading:nil]; 490 [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0]; 491} 492 493void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message) 494{ 495 id delegate = [m_webView UIDelegate]; 496 SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:); 497 if ([delegate respondsToSelector:selector]) { 498 CallUIDelegate(m_webView, selector, message, kit(frame)); 499 return; 500 } 501 502 // Call the old version of the delegate method if it is implemented. 503 selector = @selector(webView:runJavaScriptAlertPanelWithMessage:); 504 if ([delegate respondsToSelector:selector]) { 505 CallUIDelegate(m_webView, selector, message); 506 return; 507 } 508} 509 510bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message) 511{ 512 id delegate = [m_webView UIDelegate]; 513 SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:); 514 if ([delegate respondsToSelector:selector]) 515 return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame)); 516 517 // Call the old version of the delegate method if it is implemented. 518 selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:); 519 if ([delegate respondsToSelector:selector]) 520 return CallUIDelegateReturningBoolean(NO, m_webView, selector, message); 521 522 return NO; 523} 524 525bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result) 526{ 527 id delegate = [m_webView UIDelegate]; 528 SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:); 529 NSString *defaultString = defaultText; 530 if ([delegate respondsToSelector:selector]) { 531 result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString, kit(frame)); 532 return !result.isNull(); 533 } 534 535 // Call the old version of the delegate method if it is implemented. 536 selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:); 537 if ([delegate respondsToSelector:selector]) { 538 result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString); 539 return !result.isNull(); 540 } 541 542 result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultString initiatedByFrame:kit(frame)]; 543 return !result.isNull(); 544} 545 546bool WebChromeClient::shouldInterruptJavaScript() 547{ 548 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewShouldInterruptJavaScript:)); 549} 550 551void WebChromeClient::setStatusbarText(const String& status) 552{ 553 // We want the temporaries allocated here to be released even before returning to the 554 // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>. 555 NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; 556 CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status); 557 [localPool drain]; 558} 559 560IntRect WebChromeClient::windowResizerRect() const 561{ 562#if !PLATFORM(IOS) 563 return enclosingIntRect([[m_webView window] _growBoxRect]); 564#else 565 return IntRect(); 566#endif 567} 568 569bool WebChromeClient::supportsImmediateInvalidation() 570{ 571 return true; 572} 573 574void WebChromeClient::invalidateRootView(const IntRect&) 575{ 576} 577 578void WebChromeClient::invalidateContentsAndRootView(const IntRect& rect) 579{ 580} 581 582void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect) 583{ 584 invalidateContentsAndRootView(rect); 585} 586 587void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&) 588{ 589} 590 591IntPoint WebChromeClient::screenToRootView(const IntPoint& p) const 592{ 593 // FIXME: Implement this. 594 return p; 595} 596 597IntRect WebChromeClient::rootViewToScreen(const IntRect& r) const 598{ 599 // FIXME: Implement this. 600 return r; 601} 602 603#if PLATFORM(IOS) 604IntPoint WebChromeClient::accessibilityScreenToRootView(const IntPoint& p) const 605{ 606 return p; 607} 608 609IntRect WebChromeClient::rootViewToAccessibilityScreen(const IntRect& r) const 610{ 611 return r; 612} 613#endif 614 615PlatformPageClient WebChromeClient::platformPageClient() const 616{ 617 return 0; 618} 619 620void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 621{ 622} 623 624void WebChromeClient::scrollRectIntoView(const IntRect& r) const 625{ 626 // FIXME: This scrolling behavior should be under the control of the embedding client, 627 // perhaps in a delegate method, rather than something WebKit does unconditionally. 628 NSView *coordinateView = [[[m_webView mainFrame] frameView] documentView]; 629 NSRect rect = r; 630 for (NSView *view = m_webView; view; view = [view superview]) { 631 if ([view isKindOfClass:[NSClipView class]]) { 632 NSClipView *clipView = (NSClipView *)view; 633 NSView *documentView = [clipView documentView]; 634 [documentView scrollRectToVisible:[documentView convertRect:rect fromView:coordinateView]]; 635 } 636 } 637} 638 639// End host window methods. 640 641bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const 642{ 643 if (pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing) 644 return [[m_webView UIDelegate] respondsToSelector:@selector(webView:didPressMissingPluginButton:)]; 645 646 return false; 647} 648 649void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const 650{ 651 ASSERT(element->hasTagName(objectTag) || element->hasTagName(embedTag) || element->hasTagName(appletTag)); 652 653 ASSERT(pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing); 654 CallUIDelegate(m_webView, @selector(webView:didPressMissingPluginButton:), kit(element)); 655} 656 657void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 658{ 659 WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result]; 660 [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags]; 661 [element release]; 662} 663 664void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 665{ 666 NSView<WebDocumentView> *documentView = [[[m_webView _selectedOrMainFrame] frameView] documentView]; 667 if ([documentView isKindOfClass:[WebHTMLView class]]) 668 [(WebHTMLView *)documentView _setToolTip:toolTip]; 669} 670 671void WebChromeClient::print(Frame* frame) 672{ 673 WebFrame *webFrame = kit(frame); 674 if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)]) 675 CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame); 676 else 677 CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]); 678} 679 680#if ENABLE(SQL_DATABASE) 681 682void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName, DatabaseDetails) 683{ 684 BEGIN_BLOCK_OBJC_EXCEPTIONS; 685 686 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()]; 687 CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName); 688 [webOrigin release]; 689 690 END_BLOCK_OBJC_EXCEPTIONS; 691} 692 693#endif 694 695void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 696{ 697 // FIXME: Free some space. 698} 699 700void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin* origin, int64_t totalSpaceNeeded) 701{ 702 BEGIN_BLOCK_OBJC_EXCEPTIONS; 703 704 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin]; 705 CallUIDelegate(m_webView, @selector(webView:exceededApplicationCacheOriginQuotaForSecurityOrigin:totalSpaceNeeded:), webOrigin, static_cast<NSUInteger>(totalSpaceNeeded)); 706 [webOrigin release]; 707 708 END_BLOCK_OBJC_EXCEPTIONS; 709} 710 711void WebChromeClient::populateVisitedLinks() 712{ 713 if ([m_webView historyDelegate]) { 714 WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView); 715 716 if (implementations->populateVisitedLinksFunc) 717 CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:)); 718 719 return; 720 } 721 722 BEGIN_BLOCK_OBJC_EXCEPTIONS; 723 [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()]; 724 END_BLOCK_OBJC_EXCEPTIONS; 725} 726 727#if ENABLE(DASHBOARD_SUPPORT) 728 729void WebChromeClient::annotatedRegionsChanged() 730{ 731 BEGIN_BLOCK_OBJC_EXCEPTIONS; 732 CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), [m_webView _dashboardRegions]); 733 END_BLOCK_OBJC_EXCEPTIONS; 734} 735 736#endif 737 738#if ENABLE(INPUT_TYPE_COLOR) 739PassOwnPtr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient* client, const Color& initialColor) 740{ 741 // FIXME: Implement <input type='color'> for WK1 (Bug 119094). 742 ASSERT_NOT_REACHED(); 743 return nullptr; 744} 745#endif 746 747void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser) 748{ 749 BEGIN_BLOCK_OBJC_EXCEPTIONS; 750 BOOL allowMultipleFiles = chooser->settings().allowsMultipleFiles; 751 WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser]; 752 id delegate = [m_webView UIDelegate]; 753 if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)]) 754 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles); 755 else if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:)]) 756 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener); 757 else 758 [listener cancel]; 759 [listener release]; 760 END_BLOCK_OBJC_EXCEPTIONS; 761} 762 763void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader* iconLoader) 764{ 765 iconLoader->notifyFinished(Icon::createIconForFiles(filenames)); 766} 767 768#if !PLATFORM(IOS) 769 770void WebChromeClient::setCursor(const WebCore::Cursor& cursor) 771{ 772 // FIXME: Would be nice to share this code with WebKit2's PageClientImpl. 773 774 if ([NSApp _cursorRectCursor]) 775 return; 776 777 if (!m_webView) 778 return; 779 780 NSWindow *window = [m_webView window]; 781 if (!window) 782 return; 783 784 if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0]) 785 return; 786 787 NSCursor *platformCursor = cursor.platformCursor(); 788 if ([NSCursor currentCursor] == platformCursor) 789 return; 790 791 [platformCursor set]; 792} 793 794void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves) 795{ 796 [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves]; 797} 798 799#endif 800 801KeyboardUIMode WebChromeClient::keyboardUIMode() 802{ 803 BEGIN_BLOCK_OBJC_EXCEPTIONS; 804 return [m_webView _keyboardUIMode]; 805 END_BLOCK_OBJC_EXCEPTIONS; 806 return KeyboardAccessDefault; 807} 808 809NSResponder *WebChromeClient::firstResponder() 810{ 811 BEGIN_BLOCK_OBJC_EXCEPTIONS; 812 return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView]; 813 END_BLOCK_OBJC_EXCEPTIONS; 814 return nil; 815} 816 817void WebChromeClient::makeFirstResponder(NSResponder *responder) 818{ 819 BEGIN_BLOCK_OBJC_EXCEPTIONS; 820 [m_webView _pushPerformingProgrammaticFocus]; 821 [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder]; 822 [m_webView _popPerformingProgrammaticFocus]; 823 END_BLOCK_OBJC_EXCEPTIONS; 824} 825 826void WebChromeClient::enableSuddenTermination() 827{ 828#if !PLATFORM(IOS) 829 [[NSProcessInfo processInfo] enableSuddenTermination]; 830#endif 831} 832 833void WebChromeClient::disableSuddenTermination() 834{ 835#if !PLATFORM(IOS) 836 [[NSProcessInfo processInfo] disableSuddenTermination]; 837#endif 838} 839 840bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename) 841{ 842 NSString* filename; 843 if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename]) 844 return false; 845 generatedFilename = filename; 846 return true; 847} 848 849String WebChromeClient::generateReplacementFile(const String& path) 850{ 851 return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path]; 852} 853 854void WebChromeClient::elementDidFocus(const WebCore::Node* node) 855{ 856 CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node))); 857} 858 859void WebChromeClient::elementDidBlur(const WebCore::Node* node) 860{ 861 CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node))); 862} 863 864bool WebChromeClient::selectItemWritingDirectionIsNatural() 865{ 866 return false; 867} 868 869bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection() 870{ 871 return true; 872} 873 874bool WebChromeClient::hasOpenedPopup() const 875{ 876 notImplemented(); 877 return false; 878} 879 880PassRefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const 881{ 882#if !PLATFORM(IOS) 883 return adoptRef(new PopupMenuMac(client)); 884#else 885 return nullptr; 886#endif 887} 888 889PassRefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const 890{ 891#if !PLATFORM(IOS) 892 return adoptRef(new SearchPopupMenuMac(client)); 893#else 894 return nullptr; 895#endif 896} 897 898bool WebChromeClient::shouldPaintEntireContents() const 899{ 900#if PLATFORM(IOS) 901 return false; 902#else 903 NSView *documentView = [[[m_webView mainFrame] frameView] documentView]; 904 return [documentView layer]; 905#endif 906} 907 908void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 909{ 910 BEGIN_BLOCK_OBJC_EXCEPTIONS; 911 912 NSView *documentView = [[kit(frame) frameView] documentView]; 913 if (![documentView isKindOfClass:[WebHTMLView class]]) { 914 // We should never be attaching when we don't have a WebHTMLView. 915 ASSERT(!graphicsLayer); 916 return; 917 } 918 919 WebHTMLView *webHTMLView = (WebHTMLView *)documentView; 920 if (graphicsLayer) 921 [webHTMLView attachRootLayer:graphicsLayer->platformLayer()]; 922 else 923 [webHTMLView detachRootLayer]; 924 END_BLOCK_OBJC_EXCEPTIONS; 925} 926 927void WebChromeClient::setNeedsOneShotDrawingSynchronization() 928{ 929 BEGIN_BLOCK_OBJC_EXCEPTIONS; 930 [m_webView _setNeedsOneShotDrawingSynchronization:YES]; 931 END_BLOCK_OBJC_EXCEPTIONS; 932} 933 934void WebChromeClient::scheduleCompositingLayerFlush() 935{ 936 BEGIN_BLOCK_OBJC_EXCEPTIONS; 937 [m_webView _scheduleCompositingLayerFlush]; 938 END_BLOCK_OBJC_EXCEPTIONS; 939} 940 941#if ENABLE(VIDEO) 942 943bool WebChromeClient::supportsFullscreenForNode(const Node* node) 944{ 945#if PLATFORM(IOS) 946 if (!Settings::avKitEnabled()) 947 return false; 948#endif 949 return isHTMLVideoElement(node); 950} 951 952void WebChromeClient::enterFullscreenForNode(Node* node) 953{ 954 BEGIN_BLOCK_OBJC_EXCEPTIONS; 955 [m_webView _enterFullscreenForNode:node]; 956 END_BLOCK_OBJC_EXCEPTIONS; 957} 958 959void WebChromeClient::exitFullscreenForNode(Node*) 960{ 961 BEGIN_BLOCK_OBJC_EXCEPTIONS; 962 [m_webView _exitFullscreen]; 963 END_BLOCK_OBJC_EXCEPTIONS; 964} 965 966#endif 967 968#if ENABLE(FULLSCREEN_API) 969 970bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool withKeyboard) 971{ 972 SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:); 973 if ([[m_webView UIDelegate] respondsToSelector:selector]) 974 return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(element)), withKeyboard); 975#if !PLATFORM(IOS) 976 return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(element) withKeyboard:withKeyboard]; 977#else 978 return NO; 979#endif 980} 981 982void WebChromeClient::enterFullScreenForElement(Element* element) 983{ 984 SEL selector = @selector(webView:enterFullScreenForElement:listener:); 985 if ([[m_webView UIDelegate] respondsToSelector:selector]) { 986 WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element]; 987 CallUIDelegate(m_webView, selector, kit(element), listener); 988 [listener release]; 989 } 990#if !PLATFORM(IOS) 991 else 992 [m_webView _enterFullScreenForElement:element]; 993#endif 994} 995 996void WebChromeClient::exitFullScreenForElement(Element* element) 997{ 998 SEL selector = @selector(webView:exitFullScreenForElement:listener:); 999 if ([[m_webView UIDelegate] respondsToSelector:selector]) { 1000 WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element]; 1001 CallUIDelegate(m_webView, selector, kit(element), listener); 1002 [listener release]; 1003 } 1004#if !PLATFORM(IOS) 1005 else 1006 [m_webView _exitFullScreenForElement:element]; 1007#endif 1008} 1009 1010#endif // ENABLE(FULLSCREEN_API) 1011 1012#if ENABLE(SUBTLE_CRYPTO) 1013bool WebChromeClient::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) const 1014{ 1015 Vector<uint8_t> masterKey; 1016 SEL selector = @selector(webCryptoMasterKeyForWebView:); 1017 if ([[m_webView UIDelegate] respondsToSelector:selector]) { 1018 NSData *keyData = CallUIDelegate(m_webView, selector); 1019 masterKey.append((uint8_t*)[keyData bytes], [keyData length]); 1020 } else if (!getDefaultWebCryptoMasterKey(masterKey)) 1021 return false; 1022 1023 return wrapSerializedCryptoKey(masterKey, key, wrappedKey); 1024} 1025 1026bool WebChromeClient::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) const 1027{ 1028 Vector<uint8_t> masterKey; 1029 SEL selector = @selector(webCryptoMasterKeyForWebView:); 1030 if ([[m_webView UIDelegate] respondsToSelector:selector]) { 1031 NSData *keyData = CallUIDelegate(m_webView, selector); 1032 masterKey.append((uint8_t*)[keyData bytes], [keyData length]); 1033 } else if (!getDefaultWebCryptoMasterKey(masterKey)) 1034 return false; 1035 1036 return unwrapSerializedCryptoKey(masterKey, wrappedKey, key); 1037} 1038#endif 1039