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 91using 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 107WebChromeClient::WebChromeClient(WebView *webView) 108 : m_webView(webView) 109{ 110} 111 112void 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 120void 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 126FloatRect 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. 133FloatRect WebChromeClient::pageRect() 134{ 135 return [m_webView frame]; 136} 137 138float WebChromeClient::scaleFactor() 139{ 140 if (NSWindow *window = [m_webView window]) 141 return [window userSpaceScaleFactor]; 142 return [[NSScreen mainScreen] userSpaceScaleFactor]; 143} 144 145void WebChromeClient::focus() 146{ 147 [[m_webView _UIDelegateForwarder] webViewFocus:m_webView]; 148} 149 150void WebChromeClient::unfocus() 151{ 152 [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView]; 153} 154 155bool 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 162void 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 182void WebChromeClient::focusedNodeChanged(Node*) 183{ 184} 185 186Page* 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 255void WebChromeClient::show() 256{ 257 [[m_webView _UIDelegateForwarder] webViewShow:m_webView]; 258} 259 260bool WebChromeClient::canRunModal() 261{ 262 return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)]; 263} 264 265void WebChromeClient::runModal() 266{ 267 CallUIDelegate(m_webView, @selector(webViewRunModal:)); 268} 269 270void WebChromeClient::setToolbarsVisible(bool b) 271{ 272 [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b]; 273} 274 275bool WebChromeClient::toolbarsVisible() 276{ 277 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:)); 278} 279 280void WebChromeClient::setStatusbarVisible(bool b) 281{ 282 [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b]; 283} 284 285bool WebChromeClient::statusbarVisible() 286{ 287 return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:)); 288} 289 290void WebChromeClient::setScrollbarsVisible(bool b) 291{ 292 [[[m_webView mainFrame] frameView] setAllowsScrolling:b]; 293} 294 295bool WebChromeClient::scrollbarsVisible() 296{ 297 return [[[m_webView mainFrame] frameView] allowsScrolling]; 298} 299 300void WebChromeClient::setMenubarVisible(bool) 301{ 302 // The menubar is always visible in Mac OS X. 303 return; 304} 305 306bool WebChromeClient::menubarVisible() 307{ 308 // The menubar is always visible in Mac OS X. 309 return true; 310} 311 312void WebChromeClient::setResizable(bool b) 313{ 314 [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b]; 315} 316 317void 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 333bool WebChromeClient::canRunBeforeUnloadConfirmPanel() 334{ 335 return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)]; 336} 337 338bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 339{ 340 return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame)); 341} 342 343void 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 363void 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 380bool 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 395bool 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 415bool WebChromeClient::shouldInterruptJavaScript() 416{ 417 return CallUIDelegate(m_webView, @selector(webViewShouldInterruptJavaScript:)); 418} 419 420void 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 429bool WebChromeClient::tabsToLinks() const 430{ 431 return [[m_webView preferences] tabsToLinks]; 432} 433 434IntRect 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 442void 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 456void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&) 457{ 458} 459 460IntPoint 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 468IntRect 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 478PlatformPageClient WebChromeClient::platformPageClient() const 479{ 480 if ([m_webView _usesDocumentViews]) 481 return 0; 482 return m_webView; 483} 484 485void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 486{ 487} 488 489void 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 506void 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 513void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 514{ 515 [m_webView _setToolTip:toolTip]; 516} 517 518void 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) 528void 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) 546void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 547{ 548 // FIXME: Free some space. 549} 550#endif 551 552void 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) 569void 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 582FloatRect 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 601void 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 620void 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 634KeyboardUIMode WebChromeClient::keyboardUIMode() 635{ 636 BEGIN_BLOCK_OBJC_EXCEPTIONS; 637 return [m_webView _keyboardUIMode]; 638 END_BLOCK_OBJC_EXCEPTIONS; 639 return KeyboardAccessDefault; 640} 641 642NSResponder *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 650void 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 659void 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 666bool 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 675String WebChromeClient::generateReplacementFile(const String& path) 676{ 677 return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path]; 678} 679 680void WebChromeClient::formStateDidChange(const WebCore::Node* node) 681{ 682 CallUIDelegate(m_webView, @selector(webView:formStateDidChangeForNode:), kit(const_cast<WebCore::Node*>(node))); 683} 684 685void WebChromeClient::formDidFocus(const WebCore::Node* node) 686{ 687 CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node))); 688} 689 690void 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 697void 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 716void WebChromeClient::setNeedsOneShotDrawingSynchronization() 717{ 718 BEGIN_BLOCK_OBJC_EXCEPTIONS; 719 [m_webView _setNeedsOneShotDrawingSynchronization:YES]; 720 END_BLOCK_OBJC_EXCEPTIONS; 721} 722 723void 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 734bool WebChromeClient::supportsFullscreenForNode(const Node* node) 735{ 736 return node->hasTagName(WebCore::HTMLNames::videoTag); 737} 738 739void WebChromeClient::enterFullscreenForNode(Node* node) 740{ 741 BEGIN_BLOCK_OBJC_EXCEPTIONS; 742 [m_webView _enterFullscreenForNode:node]; 743 END_BLOCK_OBJC_EXCEPTIONS; 744} 745 746void WebChromeClient::exitFullscreenForNode(Node*) 747{ 748 BEGIN_BLOCK_OBJC_EXCEPTIONS; 749 [m_webView _exitFullscreen]; 750 END_BLOCK_OBJC_EXCEPTIONS; 751} 752 753#endif 754 755void 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