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