1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 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 Computer, 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 "DOMNodeInternal.h" 33 #import "WebDefaultUIDelegate.h" 34 #import "WebDelegateImplementationCaching.h" 35 #import "WebElementDictionary.h" 36 #import "WebFrameInternal.h" 37 #import "WebFrameView.h" 38 #import "WebHTMLViewInternal.h" 39 #import "WebHistoryInternal.h" 40 #import "WebKitPrefix.h" 41 #import "WebKitSystemInterface.h" 42 #import "WebNSURLRequestExtras.h" 43 #import "WebPlugin.h" 44 #import "WebSecurityOriginInternal.h" 45 #import "WebUIDelegatePrivate.h" 46 #import "WebView.h" 47 #import "WebViewInternal.h" 48 #import <Foundation/Foundation.h> 49 #import <WebCore/BlockExceptions.h> 50 #import <WebCore/Console.h> 51 #import <WebCore/Element.h> 52 #import <WebCore/FileChooser.h> 53 #import <WebCore/FloatRect.h> 54 #import <WebCore/Frame.h> 55 #import <WebCore/FrameLoadRequest.h> 56 #import <WebCore/Geolocation.h> 57 #import <WebCore/HitTestResult.h> 58 #import <WebCore/HTMLNames.h> 59 #import <WebCore/IntRect.h> 60 #import <WebCore/Page.h> 61 #import <WebCore/PlatformScreen.h> 62 #import <WebCore/PlatformString.h> 63 #import <WebCore/ResourceRequest.h> 64 #import <WebCore/ScrollView.h> 65 #import <WebCore/Widget.h> 66 #import <WebCore/WindowFeatures.h> 67 #import <wtf/PassRefPtr.h> 68 #import <wtf/Vector.h> 69 70 #if USE(ACCELERATED_COMPOSITING) 71 #import <WebCore/GraphicsLayer.h> 72 #endif 73 74 #if USE(PLUGIN_HOST_PROCESS) 75 #import "NetscapePluginHostManager.h" 76 #endif 77 78 @interface NSView (WebNSViewDetails) 79 - (NSView *)_findLastViewInKeyViewLoop; 80 @end 81 82 // For compatibility with old SPI. 83 @interface NSView (WebOldWebKitPlugInDetails) 84 - (void)setIsSelected:(BOOL)isSelected; 85 @end 86 87 @interface NSWindow (AppKitSecretsIKnowAbout) 88 - (NSRect)_growBoxRect; 89 @end 90 91 using namespace WebCore; 92 93 @interface WebOpenPanelResultListener : NSObject <WebOpenPanelResultListener> 94 { 95 FileChooser* _chooser; 96 } 97 - (id)initWithChooser:(PassRefPtr<FileChooser>)chooser; 98 @end 99 100 @interface WebGeolocationPolicyListener : NSObject <WebGeolocationPolicyListener> 101 { 102 RefPtr<Geolocation> _geolocation; 103 } 104 - (id)initWithGeolocation:(Geolocation*)geolocation; 105 @end 106 107 WebChromeClient::WebChromeClient(WebView *webView) 108 : m_webView(webView) 109 { 110 } 111 112 void WebChromeClient::chromeDestroyed() 113 { 114 delete this; 115 } 116 117 // These functions scale between window and WebView coordinates because JavaScript/DOM operations 118 // assume that the WebView and the window share the same coordinate system. 119 120 void WebChromeClient::setWindowRect(const FloatRect& rect) 121 { 122 NSRect windowRect = toDeviceSpace(rect, [m_webView window]); 123 [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect]; 124 } 125 126 FloatRect WebChromeClient::windowRect() 127 { 128 NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView]; 129 return toUserSpace(windowRect, [m_webView window]); 130 } 131 132 // FIXME: We need to add API for setting and getting this. 133 FloatRect WebChromeClient::pageRect() 134 { 135 return [m_webView frame]; 136 } 137 138 float WebChromeClient::scaleFactor() 139 { 140 if (NSWindow *window = [m_webView window]) 141 return [window userSpaceScaleFactor]; 142 return [[NSScreen mainScreen] userSpaceScaleFactor]; 143 } 144 145 void WebChromeClient::focus() 146 { 147 [[m_webView _UIDelegateForwarder] webViewFocus:m_webView]; 148 } 149 150 void WebChromeClient::unfocus() 151 { 152 [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView]; 153 } 154 155 bool WebChromeClient::canTakeFocus(FocusDirection) 156 { 157 // There's unfortunately no way to determine if we will become first responder again 158 // once we give it up, so we just have to guess that we won't. 159 return true; 160 } 161 162 void WebChromeClient::takeFocus(FocusDirection direction) 163 { 164 if (direction == FocusDirectionForward) { 165 // Since we're trying to move focus out of m_webView, and because 166 // m_webView may contain subviews within it, we ask it for the next key 167 // view of the last view in its key view loop. This makes m_webView 168 // behave as if it had no subviews, which is the behavior we want. 169 NSView *lastView = [m_webView _findLastViewInKeyViewLoop]; 170 // avoid triggering assertions if the WebView is the only thing in the key loop 171 if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView]) 172 return; 173 [[m_webView window] selectKeyViewFollowingView:lastView]; 174 } else { 175 // avoid triggering assertions if the WebView is the only thing in the key loop 176 if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView]) 177 return; 178 [[m_webView window] selectKeyViewPrecedingView:m_webView]; 179 } 180 } 181 182 void WebChromeClient::focusedNodeChanged(Node*) 183 { 184 } 185 186 Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) 187 { 188 NSURLRequest *URLRequest = nil; 189 if (!request.isEmpty()) 190 URLRequest = request.resourceRequest().nsURLRequest(); 191 192 id delegate = [m_webView UIDelegate]; 193 WebView *newWebView; 194 195 if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) { 196 NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil; 197 NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil; 198 NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil; 199 NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil; 200 NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible]; 201 NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible]; 202 NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible]; 203 NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible]; 204 NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable]; 205 NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen]; 206 NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog]; 207 208 NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 209 menuBarVisible, @"menuBarVisible", 210 statusBarVisible, @"statusBarVisible", 211 toolBarVisible, @"toolBarVisible", 212 scrollbarsVisible, @"scrollbarsVisible", 213 resizable, @"resizable", 214 fullscreen, @"fullscreen", 215 dialog, @"dialog", 216 nil]; 217 218 if (x) 219 [dictFeatures setObject:x forKey:@"x"]; 220 if (y) 221 [dictFeatures setObject:y forKey:@"y"]; 222 if (width) 223 [dictFeatures setObject:width forKey:@"width"]; 224 if (height) 225 [dictFeatures setObject:height forKey:@"height"]; 226 227 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), URLRequest, dictFeatures); 228 229 [dictFeatures release]; 230 [x release]; 231 [y release]; 232 [width release]; 233 [height release]; 234 [menuBarVisible release]; 235 [statusBarVisible release]; 236 [toolBarVisible release]; 237 [scrollbarsVisible release]; 238 [resizable release]; 239 [fullscreen release]; 240 [dialog release]; 241 } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) { 242 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), URLRequest); 243 } else { 244 newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), URLRequest); 245 } 246 247 #if USE(PLUGIN_HOST_PROCESS) 248 if (newWebView) 249 WebKit::NetscapePluginHostManager::shared().didCreateWindow(); 250 #endif 251 252 return core(newWebView); 253 } 254 255 void WebChromeClient::show() 256 { 257 [[m_webView _UIDelegateForwarder] webViewShow:m_webView]; 258 } 259 260 bool WebChromeClient::canRunModal() 261 { 262 return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)]; 263 } 264 265 void WebChromeClient::runModal() 266 { 267 CallUIDelegate(m_webView, @selector(webViewRunModal:)); 268 } 269 270 void WebChromeClient::setToolbarsVisible(bool b) 271 { 272 [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b]; 273 } 274 275 bool WebChromeClient::toolbarsVisible() 276 { 277 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:)); 278 } 279 280 void WebChromeClient::setStatusbarVisible(bool b) 281 { 282 [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b]; 283 } 284 285 bool WebChromeClient::statusbarVisible() 286 { 287 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:)); 288 } 289 290 void WebChromeClient::setScrollbarsVisible(bool b) 291 { 292 [[[m_webView mainFrame] frameView] setAllowsScrolling:b]; 293 } 294 295 bool WebChromeClient::scrollbarsVisible() 296 { 297 return [[[m_webView mainFrame] frameView] allowsScrolling]; 298 } 299 300 void WebChromeClient::setMenubarVisible(bool) 301 { 302 // The menubar is always visible in Mac OS X. 303 return; 304 } 305 306 bool WebChromeClient::menubarVisible() 307 { 308 // The menubar is always visible in Mac OS X. 309 return true; 310 } 311 312 void WebChromeClient::setResizable(bool b) 313 { 314 [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b]; 315 } 316 317 void WebChromeClient::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned int lineNumber, const String& sourceURL) 318 { 319 id delegate = [m_webView UIDelegate]; 320 SEL selector = @selector(webView:addMessageToConsole:); 321 if (![delegate respondsToSelector:selector]) 322 return; 323 324 NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: 325 (NSString *)message, @"message", [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber", 326 (NSString *)sourceURL, @"sourceURL", NULL]; 327 328 CallUIDelegate(m_webView, selector, dictionary); 329 330 [dictionary release]; 331 } 332 333 bool WebChromeClient::canRunBeforeUnloadConfirmPanel() 334 { 335 return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)]; 336 } 337 338 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 339 { 340 return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame)); 341 } 342 343 void WebChromeClient::closeWindowSoon() 344 { 345 // We need to remove the parent WebView from WebViewSets here, before it actually 346 // closes, to make sure that JavaScript code that executes before it closes 347 // can't find it. Otherwise, window.open will select a closed WebView instead of 348 // opening a new one <rdar://problem/3572585>. 349 350 // We also need to stop the load to prevent further parsing or JavaScript execution 351 // after the window has torn down <rdar://problem/4161660>. 352 353 // FIXME: This code assumes that the UI delegate will respond to a webViewClose 354 // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not. 355 // This approach is an inherent limitation of not making a close execute immediately 356 // after a call to window.close. 357 358 [m_webView setGroupName:nil]; 359 [m_webView stopLoading:nil]; 360 [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0]; 361 } 362 363 void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message) 364 { 365 id delegate = [m_webView UIDelegate]; 366 SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:); 367 if ([delegate respondsToSelector:selector]) { 368 CallUIDelegate(m_webView, selector, message, kit(frame)); 369 return; 370 } 371 372 // Call the old version of the delegate method if it is implemented. 373 selector = @selector(webView:runJavaScriptAlertPanelWithMessage:); 374 if ([delegate respondsToSelector:selector]) { 375 CallUIDelegate(m_webView, selector, message); 376 return; 377 } 378 } 379 380 bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message) 381 { 382 id delegate = [m_webView UIDelegate]; 383 SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:); 384 if ([delegate respondsToSelector:selector]) 385 return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame)); 386 387 // Call the old version of the delegate method if it is implemented. 388 selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:); 389 if ([delegate respondsToSelector:selector]) 390 return CallUIDelegateReturningBoolean(NO, m_webView, selector, message); 391 392 return NO; 393 } 394 395 bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result) 396 { 397 id delegate = [m_webView UIDelegate]; 398 SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:); 399 if ([delegate respondsToSelector:selector]) { 400 result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultText, kit(frame)); 401 return !result.isNull(); 402 } 403 404 // Call the old version of the delegate method if it is implemented. 405 selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:); 406 if ([delegate respondsToSelector:selector]) { 407 result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultText); 408 return !result.isNull(); 409 } 410 411 result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(frame)]; 412 return !result.isNull(); 413 } 414 415 bool WebChromeClient::shouldInterruptJavaScript() 416 { 417 return CallUIDelegate(m_webView, @selector(webViewShouldInterruptJavaScript:)); 418 } 419 420 void WebChromeClient::setStatusbarText(const String& status) 421 { 422 // We want the temporaries allocated here to be released even before returning to the 423 // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>. 424 NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; 425 CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status); 426 [localPool drain]; 427 } 428 429 bool WebChromeClient::tabsToLinks() const 430 { 431 return [[m_webView preferences] tabsToLinks]; 432 } 433 434 IntRect WebChromeClient::windowResizerRect() const 435 { 436 NSRect rect = [[m_webView window] _growBoxRect]; 437 if ([m_webView _usesDocumentViews]) 438 return enclosingIntRect(rect); 439 return enclosingIntRect([m_webView convertRect:rect fromView:nil]); 440 } 441 442 void WebChromeClient::repaint(const IntRect& rect, bool contentChanged, bool immediate, bool repaintContentOnly) 443 { 444 if ([m_webView _usesDocumentViews]) 445 return; 446 447 if (contentChanged) 448 [m_webView setNeedsDisplayInRect:rect]; 449 450 if (immediate) { 451 [[m_webView window] displayIfNeeded]; 452 [[m_webView window] flushWindowIfNeeded]; 453 } 454 } 455 456 void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&) 457 { 458 } 459 460 IntPoint WebChromeClient::screenToWindow(const IntPoint& p) const 461 { 462 if ([m_webView _usesDocumentViews]) 463 return p; 464 NSPoint windowCoord = [[m_webView window] convertScreenToBase:p]; 465 return IntPoint([m_webView convertPoint:windowCoord fromView:nil]); 466 } 467 468 IntRect WebChromeClient::windowToScreen(const IntRect& r) const 469 { 470 if ([m_webView _usesDocumentViews]) 471 return r; 472 NSRect tempRect = r; 473 tempRect = [m_webView convertRect:tempRect toView:nil]; 474 tempRect.origin = [[m_webView window] convertBaseToScreen:tempRect.origin]; 475 return enclosingIntRect(tempRect); 476 } 477 478 PlatformPageClient WebChromeClient::platformPageClient() const 479 { 480 if ([m_webView _usesDocumentViews]) 481 return 0; 482 return m_webView; 483 } 484 485 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 486 { 487 } 488 489 void WebChromeClient::scrollRectIntoView(const IntRect& r, const ScrollView* scrollView) const 490 { 491 // FIXME: This scrolling behavior should be under the control of the embedding client (rather than something 492 // we just do ourselves). 493 494 NSRect rect = r; 495 for (NSView *view = m_webView; view; view = [view superview]) { 496 if ([view isKindOfClass:[NSClipView class]]) { 497 NSClipView *clipView = (NSClipView *)view; 498 NSView *documentView = [clipView documentView]; 499 [documentView scrollRectToVisible:[documentView convertRect:rect fromView:m_webView]]; 500 } 501 } 502 } 503 504 // End host window methods. 505 506 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 507 { 508 WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result]; 509 [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags]; 510 [element release]; 511 } 512 513 void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 514 { 515 [m_webView _setToolTip:toolTip]; 516 } 517 518 void WebChromeClient::print(Frame* frame) 519 { 520 WebFrame *webFrame = kit(frame); 521 if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)]) 522 CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame); 523 else if ([m_webView _usesDocumentViews]) 524 CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]); 525 } 526 527 #if ENABLE(DATABASE) 528 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName) 529 { 530 BEGIN_BLOCK_OBJC_EXCEPTIONS; 531 532 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()]; 533 // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented. 534 if (WKAppVersionCheckLessThan(@"com.apple.Safari", -1, 3.1)) { 535 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support. 536 [webOrigin setQuota:defaultQuota]; 537 } else 538 CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName); 539 [webOrigin release]; 540 541 END_BLOCK_OBJC_EXCEPTIONS; 542 } 543 #endif 544 545 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 546 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 547 { 548 // FIXME: Free some space. 549 } 550 #endif 551 552 void WebChromeClient::populateVisitedLinks() 553 { 554 if ([m_webView historyDelegate]) { 555 WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView); 556 557 if (implementations->populateVisitedLinksFunc) 558 CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:)); 559 560 return; 561 } 562 563 BEGIN_BLOCK_OBJC_EXCEPTIONS; 564 [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()]; 565 END_BLOCK_OBJC_EXCEPTIONS; 566 } 567 568 #if ENABLE(DASHBOARD_SUPPORT) 569 void WebChromeClient::dashboardRegionsChanged() 570 { 571 BEGIN_BLOCK_OBJC_EXCEPTIONS; 572 573 NSMutableDictionary *regions = core([m_webView mainFrame])->dashboardRegionsDictionary(); 574 [m_webView _addScrollerDashboardRegions:regions]; 575 576 CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), regions); 577 578 END_BLOCK_OBJC_EXCEPTIONS; 579 } 580 #endif 581 582 FloatRect WebChromeClient::customHighlightRect(Node* node, const AtomicString& type, const FloatRect& lineRect) 583 { 584 BEGIN_BLOCK_OBJC_EXCEPTIONS; 585 586 NSView *documentView = [[kit(node->document()->frame()) frameView] documentView]; 587 if (![documentView isKindOfClass:[WebHTMLView class]]) 588 return NSZeroRect; 589 590 WebHTMLView *webHTMLView = (WebHTMLView *)documentView; 591 id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type]; 592 if ([(NSObject *)highlighter respondsToSelector:@selector(highlightRectForLine:representedNode:)]) 593 return [highlighter highlightRectForLine:lineRect representedNode:kit(node)]; 594 return [highlighter highlightRectForLine:lineRect]; 595 596 END_BLOCK_OBJC_EXCEPTIONS; 597 598 return NSZeroRect; 599 } 600 601 void WebChromeClient::paintCustomHighlight(Node* node, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, 602 bool behindText, bool entireLine) 603 { 604 BEGIN_BLOCK_OBJC_EXCEPTIONS; 605 606 NSView *documentView = [[kit(node->document()->frame()) frameView] documentView]; 607 if (![documentView isKindOfClass:[WebHTMLView class]]) 608 return; 609 610 WebHTMLView *webHTMLView = (WebHTMLView *)documentView; 611 id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type]; 612 if ([(NSObject *)highlighter respondsToSelector:@selector(paintHighlightForBox:onLine:behindText:entireLine:representedNode:)]) 613 [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine representedNode:kit(node)]; 614 else 615 [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine]; 616 617 END_BLOCK_OBJC_EXCEPTIONS; 618 } 619 620 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser) 621 { 622 BEGIN_BLOCK_OBJC_EXCEPTIONS; 623 BOOL allowMultipleFiles = chooser->allowsMultipleFiles(); 624 WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser]; 625 id delegate = [m_webView UIDelegate]; 626 if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)]) 627 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles); 628 else 629 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener); 630 [listener release]; 631 END_BLOCK_OBJC_EXCEPTIONS; 632 } 633 634 KeyboardUIMode WebChromeClient::keyboardUIMode() 635 { 636 BEGIN_BLOCK_OBJC_EXCEPTIONS; 637 return [m_webView _keyboardUIMode]; 638 END_BLOCK_OBJC_EXCEPTIONS; 639 return KeyboardAccessDefault; 640 } 641 642 NSResponder *WebChromeClient::firstResponder() 643 { 644 BEGIN_BLOCK_OBJC_EXCEPTIONS; 645 return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView]; 646 END_BLOCK_OBJC_EXCEPTIONS; 647 return nil; 648 } 649 650 void WebChromeClient::makeFirstResponder(NSResponder *responder) 651 { 652 BEGIN_BLOCK_OBJC_EXCEPTIONS; 653 [m_webView _pushPerformingProgrammaticFocus]; 654 [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder]; 655 [m_webView _popPerformingProgrammaticFocus]; 656 END_BLOCK_OBJC_EXCEPTIONS; 657 } 658 659 void WebChromeClient::willPopUpMenu(NSMenu *menu) 660 { 661 BEGIN_BLOCK_OBJC_EXCEPTIONS; 662 CallUIDelegate(m_webView, @selector(webView:willPopupMenu:), menu); 663 END_BLOCK_OBJC_EXCEPTIONS; 664 } 665 666 bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename) 667 { 668 NSString* filename; 669 if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename]) 670 return false; 671 generatedFilename = filename; 672 return true; 673 } 674 675 String WebChromeClient::generateReplacementFile(const String& path) 676 { 677 return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path]; 678 } 679 680 void WebChromeClient::formStateDidChange(const WebCore::Node* node) 681 { 682 CallUIDelegate(m_webView, @selector(webView:formStateDidChangeForNode:), kit(const_cast<WebCore::Node*>(node))); 683 } 684 685 void WebChromeClient::formDidFocus(const WebCore::Node* node) 686 { 687 CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node))); 688 } 689 690 void WebChromeClient::formDidBlur(const WebCore::Node* node) 691 { 692 CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node))); 693 } 694 695 #if USE(ACCELERATED_COMPOSITING) 696 697 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 698 { 699 BEGIN_BLOCK_OBJC_EXCEPTIONS; 700 701 NSView *documentView = [[kit(frame) frameView] documentView]; 702 if (![documentView isKindOfClass:[WebHTMLView class]]) { 703 // We should never be attaching when we don't have a WebHTMLView. 704 ASSERT(!graphicsLayer); 705 return; 706 } 707 708 WebHTMLView *webHTMLView = (WebHTMLView *)documentView; 709 if (graphicsLayer) 710 [webHTMLView attachRootLayer:graphicsLayer->nativeLayer()]; 711 else 712 [webHTMLView detachRootLayer]; 713 END_BLOCK_OBJC_EXCEPTIONS; 714 } 715 716 void WebChromeClient::setNeedsOneShotDrawingSynchronization() 717 { 718 BEGIN_BLOCK_OBJC_EXCEPTIONS; 719 [m_webView _setNeedsOneShotDrawingSynchronization:YES]; 720 END_BLOCK_OBJC_EXCEPTIONS; 721 } 722 723 void WebChromeClient::scheduleCompositingLayerSync() 724 { 725 BEGIN_BLOCK_OBJC_EXCEPTIONS; 726 [m_webView _scheduleCompositingLayerSync]; 727 END_BLOCK_OBJC_EXCEPTIONS; 728 } 729 730 #endif 731 732 #if ENABLE(VIDEO) 733 734 bool WebChromeClient::supportsFullscreenForNode(const Node* node) 735 { 736 return node->hasTagName(WebCore::HTMLNames::videoTag); 737 } 738 739 void WebChromeClient::enterFullscreenForNode(Node* node) 740 { 741 BEGIN_BLOCK_OBJC_EXCEPTIONS; 742 [m_webView _enterFullscreenForNode:node]; 743 END_BLOCK_OBJC_EXCEPTIONS; 744 } 745 746 void WebChromeClient::exitFullscreenForNode(Node*) 747 { 748 BEGIN_BLOCK_OBJC_EXCEPTIONS; 749 [m_webView _exitFullscreen]; 750 END_BLOCK_OBJC_EXCEPTIONS; 751 } 752 753 #endif 754 755 void WebChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) 756 { 757 BEGIN_BLOCK_OBJC_EXCEPTIONS; 758 759 SEL selector = @selector(webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:); 760 if (![[m_webView UIDelegate] respondsToSelector:selector]) { 761 geolocation->setIsAllowed(false); 762 return; 763 } 764 765 WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()]; 766 WebGeolocationPolicyListener* listener = [[WebGeolocationPolicyListener alloc] initWithGeolocation:geolocation]; 767 768 CallUIDelegate(m_webView, selector, webOrigin, kit(frame), listener); 769 770 [webOrigin release]; 771 [listener release]; 772 773 END_BLOCK_OBJC_EXCEPTIONS; 774 } 775 776 @implementation WebOpenPanelResultListener 777 778 - (id)initWithChooser:(PassRefPtr<FileChooser>)chooser 779 { 780 self = [super init]; 781 if (!self) 782 return nil; 783 _chooser = chooser.releaseRef(); 784 return self; 785 } 786 787 #ifndef NDEBUG 788 789 - (void)dealloc 790 { 791 ASSERT(!_chooser); 792 [super dealloc]; 793 } 794 795 - (void)finalize 796 { 797 ASSERT(!_chooser); 798 [super finalize]; 799 } 800 801 #endif 802 803 - (void)cancel 804 { 805 ASSERT(_chooser); 806 if (!_chooser) 807 return; 808 _chooser->deref(); 809 _chooser = 0; 810 } 811 812 - (void)chooseFilename:(NSString *)filename 813 { 814 ASSERT(_chooser); 815 if (!_chooser) 816 return; 817 _chooser->chooseFile(filename); 818 _chooser->deref(); 819 _chooser = 0; 820 } 821 822 - (void)chooseFilenames:(NSArray *)filenames 823 { 824 ASSERT(_chooser); 825 if (!_chooser) 826 return; 827 int count = [filenames count]; 828 Vector<String> names(count); 829 for (int i = 0; i < count; i++) 830 names[i] = [filenames objectAtIndex:i]; 831 _chooser->chooseFiles(names); 832 _chooser->deref(); 833 _chooser = 0; 834 } 835 836 @end 837 838 @implementation WebGeolocationPolicyListener 839 840 - (id)initWithGeolocation:(Geolocation*)geolocation 841 { 842 if (!(self = [super init])) 843 return nil; 844 _geolocation = geolocation; 845 return self; 846 } 847 848 - (void)allow 849 { 850 _geolocation->setIsAllowed(true); 851 } 852 853 - (void)deny 854 { 855 _geolocation->setIsAllowed(false); 856 } 857 858 @end 859