Home | History | Annotate | Download | only in WebCoreSupport
      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 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 "DOMElementInternal.h"
     33 #import "DOMNodeInternal.h"
     34 #import "WebDefaultUIDelegate.h"
     35 #import "WebDelegateImplementationCaching.h"
     36 #import "WebElementDictionary.h"
     37 #import "WebFrameInternal.h"
     38 #import "WebFrameView.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 "WebQuotaManager.h"
     46 #import "WebSecurityOriginInternal.h"
     47 #import "WebUIDelegatePrivate.h"
     48 #import "WebView.h"
     49 #import "WebViewInternal.h"
     50 #import <Foundation/Foundation.h>
     51 #import <WebCore/BlockExceptions.h>
     52 #import <WebCore/Console.h>
     53 #import <WebCore/Cursor.h>
     54 #import <WebCore/ContextMenu.h>
     55 #import <WebCore/ContextMenuController.h>
     56 #import <WebCore/Element.h>
     57 #import <WebCore/FileChooser.h>
     58 #import <WebCore/FloatRect.h>
     59 #import <WebCore/Frame.h>
     60 #import <WebCore/FrameLoadRequest.h>
     61 #import <WebCore/FrameView.h>
     62 #import <WebCore/HTMLNames.h>
     63 #import <WebCore/HitTestResult.h>
     64 #import <WebCore/Icon.h>
     65 #import <WebCore/IntPoint.h>
     66 #import <WebCore/IntRect.h>
     67 #import <WebCore/NavigationAction.h>
     68 #import <WebCore/Page.h>
     69 #import <WebCore/PlatformScreen.h>
     70 #import <WebCore/PlatformString.h>
     71 #import <WebCore/PopupMenuMac.h>
     72 #import <WebCore/ResourceRequest.h>
     73 #import <WebCore/SearchPopupMenuMac.h>
     74 #import <WebCore/Widget.h>
     75 #import <WebCore/WindowFeatures.h>
     76 #import <wtf/PassRefPtr.h>
     77 #import <wtf/Vector.h>
     78 
     79 #if USE(ACCELERATED_COMPOSITING)
     80 #import <WebCore/GraphicsLayer.h>
     81 #endif
     82 
     83 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
     84 #import "NetscapePluginHostManager.h"
     85 #endif
     86 
     87 NSString *WebConsoleMessageHTMLMessageSource = @"HTMLMessageSource";
     88 NSString *WebConsoleMessageWMLMessageSource = @"WMLMessageSource";
     89 NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource";
     90 NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource";
     91 NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource";
     92 NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource";
     93 
     94 NSString *WebConsoleMessageLogMessageType = @"LogMessageType";
     95 NSString *WebConsoleMessageObjectMessageType = @"ObjectMessageType";
     96 NSString *WebConsoleMessageTraceMessageType = @"TraceMessageType";
     97 NSString *WebConsoleMessageStartGroupMessageType = @"StartGroupMessageType";
     98 NSString *WebConsoleMessageStartGroupCollapsedMessageType = @"StartGroupCollapsedMessageType";
     99 NSString *WebConsoleMessageEndGroupMessageType = @"EndGroupMessageType";
    100 NSString *WebConsoleMessageAssertMessageType = @"AssertMessageType";
    101 NSString *WebConsoleMessageUncaughtExceptionMessageType = @"UncaughtExceptionMessageType";
    102 NSString *WebConsoleMessageNetworkErrorMessageType = @"NetworkErrorMessageType";
    103 
    104 NSString *WebConsoleMessageTipMessageLevel = @"TipMessageLevel";
    105 NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel";
    106 NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel";
    107 NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel";
    108 NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel";
    109 
    110 @interface NSApplication (WebNSApplicationDetails)
    111 - (NSCursor *)_cursorRectCursor;
    112 @end
    113 
    114 @interface NSView (WebNSViewDetails)
    115 - (NSView *)_findLastViewInKeyViewLoop;
    116 @end
    117 
    118 // For compatibility with old SPI.
    119 @interface NSView (WebOldWebKitPlugInDetails)
    120 - (void)setIsSelected:(BOOL)isSelected;
    121 @end
    122 
    123 @interface NSWindow (AppKitSecretsIKnowAbout)
    124 - (NSRect)_growBoxRect;
    125 @end
    126 
    127 using namespace WebCore;
    128 
    129 @interface WebOpenPanelResultListener : NSObject <WebOpenPanelResultListener>
    130 {
    131     FileChooser* _chooser;
    132 }
    133 - (id)initWithChooser:(PassRefPtr<FileChooser>)chooser;
    134 @end
    135 
    136 #if ENABLE(FULLSCREEN_API)
    137 
    138 @interface WebKitFullScreenListener : NSObject <WebKitFullScreenListener>
    139 {
    140     RefPtr<Element> _element;
    141 }
    142 
    143 - (id)initWithElement:(Element*)element;
    144 @end
    145 
    146 #endif
    147 
    148 WebChromeClient::WebChromeClient(WebView *webView)
    149     : m_webView(webView)
    150 {
    151 }
    152 
    153 void WebChromeClient::chromeDestroyed()
    154 {
    155     delete this;
    156 }
    157 
    158 // These functions scale between window and WebView coordinates because JavaScript/DOM operations
    159 // assume that the WebView and the window share the same coordinate system.
    160 
    161 void WebChromeClient::setWindowRect(const FloatRect& rect)
    162 {
    163     NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
    164     [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
    165 }
    166 
    167 FloatRect WebChromeClient::windowRect()
    168 {
    169     NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
    170     return toUserSpace(windowRect, [m_webView window]);
    171 }
    172 
    173 // FIXME: We need to add API for setting and getting this.
    174 FloatRect WebChromeClient::pageRect()
    175 {
    176     return [m_webView frame];
    177 }
    178 
    179 float WebChromeClient::scaleFactor()
    180 {
    181     NSWindow *window = [m_webView window];
    182 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
    183     if (window)
    184         return [window backingScaleFactor];
    185     return [[NSScreen mainScreen] backingScaleFactor];
    186 #else
    187     if (window)
    188         return [window userSpaceScaleFactor];
    189     return [[NSScreen mainScreen] userSpaceScaleFactor];
    190 #endif
    191 }
    192 
    193 void WebChromeClient::focus()
    194 {
    195     [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
    196 }
    197 
    198 void WebChromeClient::unfocus()
    199 {
    200     [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
    201 }
    202 
    203 bool WebChromeClient::canTakeFocus(FocusDirection)
    204 {
    205     // There's unfortunately no way to determine if we will become first responder again
    206     // once we give it up, so we just have to guess that we won't.
    207     return true;
    208 }
    209 
    210 void WebChromeClient::takeFocus(FocusDirection direction)
    211 {
    212     if (direction == FocusDirectionForward) {
    213         // Since we're trying to move focus out of m_webView, and because
    214         // m_webView may contain subviews within it, we ask it for the next key
    215         // view of the last view in its key view loop. This makes m_webView
    216         // behave as if it had no subviews, which is the behavior we want.
    217         NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
    218         // avoid triggering assertions if the WebView is the only thing in the key loop
    219         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
    220             return;
    221         [[m_webView window] selectKeyViewFollowingView:lastView];
    222     } else {
    223         // avoid triggering assertions if the WebView is the only thing in the key loop
    224         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
    225             return;
    226         [[m_webView window] selectKeyViewPrecedingView:m_webView];
    227     }
    228 }
    229 
    230 void WebChromeClient::focusedNodeChanged(Node*)
    231 {
    232 }
    233 
    234 void WebChromeClient::focusedFrameChanged(Frame*)
    235 {
    236 }
    237 
    238 Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
    239 {
    240     id delegate = [m_webView UIDelegate];
    241     WebView *newWebView;
    242 
    243     if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) {
    244         NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil;
    245         NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil;
    246         NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil;
    247         NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil;
    248         NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible];
    249         NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible];
    250         NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible];
    251         NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible];
    252         NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable];
    253         NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen];
    254         NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog];
    255 
    256         NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
    257                                              menuBarVisible, @"menuBarVisible",
    258                                              statusBarVisible, @"statusBarVisible",
    259                                              toolBarVisible, @"toolBarVisible",
    260                                              scrollbarsVisible, @"scrollbarsVisible",
    261                                              resizable, @"resizable",
    262                                              fullscreen, @"fullscreen",
    263                                              dialog, @"dialog",
    264                                              nil];
    265 
    266         if (x)
    267             [dictFeatures setObject:x forKey:@"x"];
    268         if (y)
    269             [dictFeatures setObject:y forKey:@"y"];
    270         if (width)
    271             [dictFeatures setObject:width forKey:@"width"];
    272         if (height)
    273             [dictFeatures setObject:height forKey:@"height"];
    274 
    275         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), nil, dictFeatures);
    276 
    277         [dictFeatures release];
    278         [x release];
    279         [y release];
    280         [width release];
    281         [height release];
    282         [menuBarVisible release];
    283         [statusBarVisible release];
    284         [toolBarVisible release];
    285         [scrollbarsVisible release];
    286         [resizable release];
    287         [fullscreen release];
    288         [dialog release];
    289     } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) {
    290         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), nil);
    291     } else {
    292         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), nil);
    293     }
    294 
    295 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
    296     if (newWebView)
    297         WebKit::NetscapePluginHostManager::shared().didCreateWindow();
    298 #endif
    299 
    300     return core(newWebView);
    301 }
    302 
    303 void WebChromeClient::show()
    304 {
    305     [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
    306 }
    307 
    308 bool WebChromeClient::canRunModal()
    309 {
    310     return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
    311 }
    312 
    313 void WebChromeClient::runModal()
    314 {
    315     CallUIDelegate(m_webView, @selector(webViewRunModal:));
    316 }
    317 
    318 void WebChromeClient::setToolbarsVisible(bool b)
    319 {
    320     [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
    321 }
    322 
    323 bool WebChromeClient::toolbarsVisible()
    324 {
    325     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:));
    326 }
    327 
    328 void WebChromeClient::setStatusbarVisible(bool b)
    329 {
    330     [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
    331 }
    332 
    333 bool WebChromeClient::statusbarVisible()
    334 {
    335     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:));
    336 }
    337 
    338 void WebChromeClient::setScrollbarsVisible(bool b)
    339 {
    340     [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
    341 }
    342 
    343 bool WebChromeClient::scrollbarsVisible()
    344 {
    345     return [[[m_webView mainFrame] frameView] allowsScrolling];
    346 }
    347 
    348 void WebChromeClient::setMenubarVisible(bool)
    349 {
    350     // The menubar is always visible in Mac OS X.
    351     return;
    352 }
    353 
    354 bool WebChromeClient::menubarVisible()
    355 {
    356     // The menubar is always visible in Mac OS X.
    357     return true;
    358 }
    359 
    360 void WebChromeClient::setResizable(bool b)
    361 {
    362     [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
    363 }
    364 
    365 inline static NSString *stringForMessageSource(MessageSource source)
    366 {
    367     switch (source) {
    368     case HTMLMessageSource:
    369         return WebConsoleMessageHTMLMessageSource;
    370     case WMLMessageSource:
    371         return WebConsoleMessageWMLMessageSource;
    372     case XMLMessageSource:
    373         return WebConsoleMessageXMLMessageSource;
    374     case JSMessageSource:
    375         return WebConsoleMessageJSMessageSource;
    376     case CSSMessageSource:
    377         return WebConsoleMessageCSSMessageSource;
    378     case OtherMessageSource:
    379         return WebConsoleMessageOtherMessageSource;
    380     }
    381     ASSERT_NOT_REACHED();
    382     return @"";
    383 }
    384 
    385 inline static NSString *stringForMessageType(MessageType type)
    386 {
    387     switch (type) {
    388     case LogMessageType:
    389         return WebConsoleMessageLogMessageType;
    390     case ObjectMessageType:
    391         return WebConsoleMessageObjectMessageType;
    392     case TraceMessageType:
    393         return WebConsoleMessageTraceMessageType;
    394     case StartGroupMessageType:
    395         return WebConsoleMessageStartGroupMessageType;
    396     case StartGroupCollapsedMessageType:
    397         return WebConsoleMessageStartGroupCollapsedMessageType;
    398     case EndGroupMessageType:
    399         return WebConsoleMessageEndGroupMessageType;
    400     case AssertMessageType:
    401         return WebConsoleMessageAssertMessageType;
    402     case UncaughtExceptionMessageType:
    403         return WebConsoleMessageUncaughtExceptionMessageType;
    404     case NetworkErrorMessageType:
    405         return WebConsoleMessageNetworkErrorMessageType;
    406     }
    407     ASSERT_NOT_REACHED();
    408     return @"";
    409 }
    410 
    411 inline static NSString *stringForMessageLevel(MessageLevel level)
    412 {
    413     switch (level) {
    414     case TipMessageLevel:
    415         return WebConsoleMessageTipMessageLevel;
    416     case LogMessageLevel:
    417         return WebConsoleMessageLogMessageLevel;
    418     case WarningMessageLevel:
    419         return WebConsoleMessageWarningMessageLevel;
    420     case ErrorMessageLevel:
    421         return WebConsoleMessageErrorMessageLevel;
    422     case DebugMessageLevel:
    423         return WebConsoleMessageDebugMessageLevel;
    424     }
    425     ASSERT_NOT_REACHED();
    426     return @"";
    427 }
    428 
    429 void WebChromeClient::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned int lineNumber, const String& sourceURL)
    430 {
    431     id delegate = [m_webView UIDelegate];
    432     BOOL respondsToNewSelector = NO;
    433 
    434     SEL selector = @selector(webView:addMessageToConsole:withSource:);
    435     if ([delegate respondsToSelector:selector])
    436         respondsToNewSelector = YES;
    437     else {
    438         // The old selector only takes JSMessageSource messages.
    439         if (source != JSMessageSource)
    440             return;
    441         selector = @selector(webView:addMessageToConsole:);
    442         if (![delegate respondsToSelector:selector])
    443             return;
    444     }
    445 
    446     NSString *messageSource = stringForMessageSource(source);
    447     NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
    448         (NSString *)message, @"message",
    449         [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
    450         (NSString *)sourceURL, @"sourceURL",
    451         messageSource, @"MessageSource",
    452         stringForMessageType(type), @"MessageType",
    453         stringForMessageLevel(level), @"MessageLevel",
    454         NULL];
    455 
    456     if (respondsToNewSelector)
    457         CallUIDelegate(m_webView, selector, dictionary, messageSource);
    458     else
    459         CallUIDelegate(m_webView, selector, dictionary);
    460 
    461     [dictionary release];
    462 }
    463 
    464 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
    465 {
    466     return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
    467 }
    468 
    469 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
    470 {
    471     return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame));
    472 }
    473 
    474 void WebChromeClient::closeWindowSoon()
    475 {
    476     // We need to remove the parent WebView from WebViewSets here, before it actually
    477     // closes, to make sure that JavaScript code that executes before it closes
    478     // can't find it. Otherwise, window.open will select a closed WebView instead of
    479     // opening a new one <rdar://problem/3572585>.
    480 
    481     // We also need to stop the load to prevent further parsing or JavaScript execution
    482     // after the window has torn down <rdar://problem/4161660>.
    483 
    484     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
    485     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
    486     // This approach is an inherent limitation of not making a close execute immediately
    487     // after a call to window.close.
    488 
    489     [m_webView setGroupName:nil];
    490     [m_webView stopLoading:nil];
    491     [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
    492 }
    493 
    494 void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
    495 {
    496     id delegate = [m_webView UIDelegate];
    497     SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
    498     if ([delegate respondsToSelector:selector]) {
    499         CallUIDelegate(m_webView, selector, message, kit(frame));
    500         return;
    501     }
    502 
    503     // Call the old version of the delegate method if it is implemented.
    504     selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
    505     if ([delegate respondsToSelector:selector]) {
    506         CallUIDelegate(m_webView, selector, message);
    507         return;
    508     }
    509 }
    510 
    511 bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
    512 {
    513     id delegate = [m_webView UIDelegate];
    514     SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
    515     if ([delegate respondsToSelector:selector])
    516         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame));
    517 
    518     // Call the old version of the delegate method if it is implemented.
    519     selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
    520     if ([delegate respondsToSelector:selector])
    521         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
    522 
    523     return NO;
    524 }
    525 
    526 bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
    527 {
    528     id delegate = [m_webView UIDelegate];
    529     SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
    530     if ([delegate respondsToSelector:selector]) {
    531         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultText, 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, defaultText);
    539         return !result.isNull();
    540     }
    541 
    542     result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(frame)];
    543     return !result.isNull();
    544 }
    545 
    546 bool WebChromeClient::shouldInterruptJavaScript()
    547 {
    548     return CallUIDelegate(m_webView, @selector(webViewShouldInterruptJavaScript:));
    549 }
    550 
    551 void 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 
    560 IntRect WebChromeClient::windowResizerRect() const
    561 {
    562     NSRect rect = [[m_webView window] _growBoxRect];
    563     if ([m_webView _usesDocumentViews])
    564         return enclosingIntRect(rect);
    565     return enclosingIntRect([m_webView convertRect:rect fromView:nil]);
    566 }
    567 
    568 void WebChromeClient::invalidateWindow(const IntRect&, bool immediate)
    569 {
    570     if (immediate) {
    571         [[m_webView window] displayIfNeeded];
    572         [[m_webView window] flushWindowIfNeeded];
    573     }
    574 }
    575 
    576 void WebChromeClient::invalidateContentsAndWindow(const IntRect& rect, bool immediate)
    577 {
    578     if ([m_webView _usesDocumentViews])
    579         return;
    580 
    581     [m_webView setNeedsDisplayInRect:rect];
    582 
    583     if (immediate) {
    584         [[m_webView window] displayIfNeeded];
    585         [[m_webView window] flushWindowIfNeeded];
    586     }
    587 }
    588 
    589 void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect, bool immediate)
    590 {
    591     invalidateContentsAndWindow(rect, immediate);
    592 }
    593 
    594 void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&)
    595 {
    596 }
    597 
    598 IntPoint WebChromeClient::screenToWindow(const IntPoint& p) const
    599 {
    600     if ([m_webView _usesDocumentViews])
    601         return p;
    602     NSPoint windowCoord = [[m_webView window] convertScreenToBase:p];
    603     return IntPoint([m_webView convertPoint:windowCoord fromView:nil]);
    604 }
    605 
    606 IntRect WebChromeClient::windowToScreen(const IntRect& r) const
    607 {
    608     if ([m_webView _usesDocumentViews])
    609         return r;
    610     NSRect tempRect = r;
    611     tempRect = [m_webView convertRect:tempRect toView:nil];
    612     tempRect.origin = [[m_webView window] convertBaseToScreen:tempRect.origin];
    613     return enclosingIntRect(tempRect);
    614 }
    615 
    616 PlatformPageClient WebChromeClient::platformPageClient() const
    617 {
    618     if ([m_webView _usesDocumentViews])
    619         return 0;
    620     return m_webView;
    621 }
    622 
    623 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
    624 {
    625 }
    626 
    627 void WebChromeClient::scrollRectIntoView(const IntRect& r, const ScrollView*) const
    628 {
    629     // FIXME: This scrolling behavior should be under the control of the embedding client,
    630     // perhaps in a delegate method, rather than something WebKit does unconditionally.
    631     NSView *coordinateView = [m_webView _usesDocumentViews]
    632         ? [[[m_webView mainFrame] frameView] documentView] : m_webView;
    633     NSRect rect = r;
    634     for (NSView *view = m_webView; view; view = [view superview]) {
    635         if ([view isKindOfClass:[NSClipView class]]) {
    636             NSClipView *clipView = (NSClipView *)view;
    637             NSView *documentView = [clipView documentView];
    638             [documentView scrollRectToVisible:[documentView convertRect:rect fromView:coordinateView]];
    639         }
    640     }
    641 }
    642 
    643 // End host window methods.
    644 
    645 bool WebChromeClient::shouldMissingPluginMessageBeButton() const
    646 {
    647     return [[m_webView UIDelegate] respondsToSelector:@selector(webView:didPressMissingPluginButton:)];
    648 }
    649 
    650 void WebChromeClient::missingPluginButtonClicked(Element* element) const
    651 {
    652     CallUIDelegate(m_webView, @selector(webView:didPressMissingPluginButton:), kit(element));
    653 }
    654 
    655 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
    656 {
    657     WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result];
    658     [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags];
    659     [element release];
    660 }
    661 
    662 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
    663 {
    664     [m_webView _setToolTip:toolTip];
    665 }
    666 
    667 void WebChromeClient::print(Frame* frame)
    668 {
    669     WebFrame *webFrame = kit(frame);
    670     if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)])
    671         CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame);
    672     else if ([m_webView _usesDocumentViews])
    673         CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]);
    674 }
    675 
    676 #if ENABLE(DATABASE)
    677 
    678 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName)
    679 {
    680     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    681 
    682     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
    683     // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
    684     if (WKAppVersionCheckLessThan(@"com.apple.Safari", -1, 3.1)) {
    685         const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
    686         [[webOrigin databaseQuotaManager] setQuota:defaultQuota];
    687     } else
    688         CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName);
    689     [webOrigin release];
    690 
    691     END_BLOCK_OBJC_EXCEPTIONS;
    692 }
    693 
    694 #endif
    695 
    696 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    697 
    698 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
    699 {
    700     // FIXME: Free some space.
    701 }
    702 
    703 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin* origin)
    704 {
    705     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    706 
    707     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin];
    708     CallUIDelegate(m_webView, @selector(webView:exceededApplicationCacheOriginQuotaForSecurityOrigin:), webOrigin);
    709     [webOrigin release];
    710 
    711     END_BLOCK_OBJC_EXCEPTIONS;
    712 }
    713 
    714 #endif
    715 
    716 void WebChromeClient::populateVisitedLinks()
    717 {
    718     if ([m_webView historyDelegate]) {
    719         WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView);
    720 
    721         if (implementations->populateVisitedLinksFunc)
    722             CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:));
    723 
    724         return;
    725     }
    726 
    727     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    728     [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()];
    729     END_BLOCK_OBJC_EXCEPTIONS;
    730 }
    731 
    732 #if ENABLE(DASHBOARD_SUPPORT)
    733 
    734 void WebChromeClient::dashboardRegionsChanged()
    735 {
    736     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    737     CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), [m_webView _dashboardRegions]);
    738     END_BLOCK_OBJC_EXCEPTIONS;
    739 }
    740 
    741 #endif
    742 
    743 FloatRect WebChromeClient::customHighlightRect(Node* node, const AtomicString& type, const FloatRect& lineRect)
    744 {
    745     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    746 
    747     NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
    748     if (![documentView isKindOfClass:[WebHTMLView class]])
    749         return NSZeroRect;
    750 
    751     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
    752     id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
    753     return [highlighter highlightRectForLine:lineRect representedNode:kit(node)];
    754 
    755     END_BLOCK_OBJC_EXCEPTIONS;
    756 
    757     return NSZeroRect;
    758 }
    759 
    760 void WebChromeClient::paintCustomHighlight(Node* node, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect,
    761     bool behindText, bool entireLine)
    762 {
    763     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    764 
    765     NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
    766     if (![documentView isKindOfClass:[WebHTMLView class]])
    767         return;
    768 
    769     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
    770     id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
    771     [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine representedNode:kit(node)];
    772 
    773     END_BLOCK_OBJC_EXCEPTIONS;
    774 }
    775 
    776 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
    777 {
    778     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    779     BOOL allowMultipleFiles = chooser->allowsMultipleFiles();
    780     WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
    781     id delegate = [m_webView UIDelegate];
    782     if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
    783         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
    784     else
    785         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
    786     [listener release];
    787     END_BLOCK_OBJC_EXCEPTIONS;
    788 }
    789 
    790 void WebChromeClient::chooseIconForFiles(const Vector<String>& filenames, FileChooser* chooser)
    791 {
    792     chooser->iconLoaded(Icon::createIconForFiles(filenames));
    793 }
    794 
    795 void WebChromeClient::setCursor(const WebCore::Cursor& cursor)
    796 {
    797     if ([NSApp _cursorRectCursor])
    798         return;
    799 
    800     NSCursor *platformCursor = cursor.platformCursor();
    801     if ([NSCursor currentCursor] == platformCursor)
    802         return;
    803     [platformCursor set];
    804 }
    805 
    806 KeyboardUIMode WebChromeClient::keyboardUIMode()
    807 {
    808     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    809     return [m_webView _keyboardUIMode];
    810     END_BLOCK_OBJC_EXCEPTIONS;
    811     return KeyboardAccessDefault;
    812 }
    813 
    814 NSResponder *WebChromeClient::firstResponder()
    815 {
    816     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    817     return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
    818     END_BLOCK_OBJC_EXCEPTIONS;
    819     return nil;
    820 }
    821 
    822 void WebChromeClient::makeFirstResponder(NSResponder *responder)
    823 {
    824     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    825     [m_webView _pushPerformingProgrammaticFocus];
    826     [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
    827     [m_webView _popPerformingProgrammaticFocus];
    828     END_BLOCK_OBJC_EXCEPTIONS;
    829 }
    830 
    831 void WebChromeClient::willPopUpMenu(NSMenu *menu)
    832 {
    833     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    834     CallUIDelegate(m_webView, @selector(webView:willPopupMenu:), menu);
    835     END_BLOCK_OBJC_EXCEPTIONS;
    836 }
    837 
    838 bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
    839 {
    840     NSString* filename;
    841     if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
    842         return false;
    843     generatedFilename = filename;
    844     return true;
    845 }
    846 
    847 String WebChromeClient::generateReplacementFile(const String& path)
    848 {
    849     return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
    850 }
    851 
    852 void WebChromeClient::formDidFocus(const WebCore::Node* node)
    853 {
    854     CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node)));
    855 }
    856 
    857 void WebChromeClient::formDidBlur(const WebCore::Node* node)
    858 {
    859     CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node)));
    860 }
    861 
    862 bool WebChromeClient::selectItemWritingDirectionIsNatural()
    863 {
    864 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    865     return false;
    866 #else
    867     return true;
    868 #endif
    869 }
    870 
    871 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
    872 {
    873 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    874     return true;
    875 #else
    876     return false;
    877 #endif
    878 }
    879 
    880 PassRefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
    881 {
    882     return adoptRef(new PopupMenuMac(client));
    883 }
    884 
    885 PassRefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
    886 {
    887     return adoptRef(new SearchPopupMenuMac(client));
    888 }
    889 
    890 #if ENABLE(CONTEXT_MENUS)
    891 void WebChromeClient::showContextMenu()
    892 {
    893     Page* page = [m_webView page];
    894     if (!page)
    895         return;
    896 
    897     ContextMenuController* controller = page->contextMenuController();
    898     Node* node = controller->hitTestResult().innerNonSharedNode();
    899     if (!node)
    900         return;
    901     Frame* frame = node->document()->frame();
    902     if (!frame)
    903         return;
    904     FrameView* frameView = frame->view();
    905     if (!frameView)
    906         return;
    907     NSView* view = frameView->documentView();
    908 
    909     IntPoint point = frameView->contentsToWindow(controller->hitTestResult().point());
    910     NSPoint nsScreenPoint = [view convertPoint:point toView:nil];
    911     // Show the contextual menu for this event.
    912     NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
    913     NSMenu* nsMenu = [view menuForEvent:event];
    914     if (nsMenu)
    915         [NSMenu popUpContextMenu:nsMenu withEvent:event forView:view];
    916 }
    917 #endif
    918 
    919 #if USE(ACCELERATED_COMPOSITING)
    920 
    921 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
    922 {
    923     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    924 
    925     NSView *documentView = [[kit(frame) frameView] documentView];
    926     if (![documentView isKindOfClass:[WebHTMLView class]]) {
    927         // We should never be attaching when we don't have a WebHTMLView.
    928         ASSERT(!graphicsLayer);
    929         return;
    930     }
    931 
    932     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
    933     if (graphicsLayer)
    934         [webHTMLView attachRootLayer:graphicsLayer->platformLayer()];
    935     else
    936         [webHTMLView detachRootLayer];
    937     END_BLOCK_OBJC_EXCEPTIONS;
    938 }
    939 
    940 void WebChromeClient::setNeedsOneShotDrawingSynchronization()
    941 {
    942     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    943     [m_webView _setNeedsOneShotDrawingSynchronization:YES];
    944     END_BLOCK_OBJC_EXCEPTIONS;
    945 }
    946 
    947 void WebChromeClient::scheduleCompositingLayerSync()
    948 {
    949     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    950     [m_webView _scheduleCompositingLayerSync];
    951     END_BLOCK_OBJC_EXCEPTIONS;
    952 }
    953 
    954 #endif
    955 
    956 #if ENABLE(VIDEO)
    957 
    958 bool WebChromeClient::supportsFullscreenForNode(const Node* node)
    959 {
    960     return node->hasTagName(WebCore::HTMLNames::videoTag);
    961 }
    962 
    963 void WebChromeClient::enterFullscreenForNode(Node* node)
    964 {
    965     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    966     [m_webView _enterFullscreenForNode:node];
    967     END_BLOCK_OBJC_EXCEPTIONS;
    968 }
    969 
    970 void WebChromeClient::exitFullscreenForNode(Node*)
    971 {
    972     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    973     [m_webView _exitFullscreen];
    974     END_BLOCK_OBJC_EXCEPTIONS;
    975 }
    976 
    977 #endif
    978 
    979 #if ENABLE(FULLSCREEN_API)
    980 
    981 bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool withKeyboard)
    982 {
    983     SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:);
    984     if ([[m_webView UIDelegate] respondsToSelector:selector])
    985         return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(element)), withKeyboard);
    986     return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(element) withKeyboard:withKeyboard];
    987 }
    988 
    989 void WebChromeClient::enterFullScreenForElement(Element* element)
    990 {
    991     SEL selector = @selector(webView:enterFullScreenForElement:listener:);
    992     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
    993         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
    994         CallUIDelegate(m_webView, selector, kit(element), listener);
    995         [listener release];
    996     } else
    997         [m_webView _enterFullScreenForElement:element];
    998 }
    999 
   1000 void WebChromeClient::exitFullScreenForElement(Element* element)
   1001 {
   1002     SEL selector = @selector(webView:exitFullScreenForElement:listener:);
   1003     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
   1004         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
   1005         CallUIDelegate(m_webView, selector, kit(element), listener);
   1006         [listener release];
   1007     } else
   1008         [m_webView _exitFullScreenForElement:element];
   1009 }
   1010 
   1011 void WebChromeClient::fullScreenRendererChanged(RenderBox* renderer)
   1012 {
   1013     SEL selector = @selector(webView:fullScreenRendererChanged:);
   1014     if ([[m_webView UIDelegate] respondsToSelector:selector])
   1015         CallUIDelegate(m_webView, selector, (id)renderer);
   1016     else
   1017         [m_webView _fullScreenRendererChanged:renderer];
   1018 }
   1019 
   1020 #endif
   1021 
   1022 @implementation WebOpenPanelResultListener
   1023 
   1024 - (id)initWithChooser:(PassRefPtr<FileChooser>)chooser
   1025 {
   1026     self = [super init];
   1027     if (!self)
   1028         return nil;
   1029     _chooser = chooser.releaseRef();
   1030     return self;
   1031 }
   1032 
   1033 #ifndef NDEBUG
   1034 
   1035 - (void)dealloc
   1036 {
   1037     ASSERT(!_chooser);
   1038     [super dealloc];
   1039 }
   1040 
   1041 - (void)finalize
   1042 {
   1043     ASSERT(!_chooser);
   1044     [super finalize];
   1045 }
   1046 
   1047 #endif
   1048 
   1049 - (void)cancel
   1050 {
   1051     ASSERT(_chooser);
   1052     if (!_chooser)
   1053         return;
   1054     _chooser->deref();
   1055     _chooser = 0;
   1056 }
   1057 
   1058 - (void)chooseFilename:(NSString *)filename
   1059 {
   1060     ASSERT(_chooser);
   1061     if (!_chooser)
   1062         return;
   1063     _chooser->chooseFile(filename);
   1064     _chooser->deref();
   1065     _chooser = 0;
   1066 }
   1067 
   1068 - (void)chooseFilenames:(NSArray *)filenames
   1069 {
   1070     ASSERT(_chooser);
   1071     if (!_chooser)
   1072         return;
   1073     int count = [filenames count];
   1074     Vector<String> names(count);
   1075     for (int i = 0; i < count; i++)
   1076         names[i] = [filenames objectAtIndex:i];
   1077     _chooser->chooseFiles(names);
   1078     _chooser->deref();
   1079     _chooser = 0;
   1080 }
   1081 
   1082 @end
   1083 
   1084 #if ENABLE(FULLSCREEN_API)
   1085 
   1086 @implementation WebKitFullScreenListener
   1087 
   1088 - (id)initWithElement:(Element*)element
   1089 {
   1090     if (!(self = [super init]))
   1091         return nil;
   1092 
   1093     _element = element;
   1094     return self;
   1095 }
   1096 
   1097 - (void)webkitWillEnterFullScreen
   1098 {
   1099     if (_element)
   1100         _element->document()->webkitWillEnterFullScreenForElement(_element.get());
   1101 }
   1102 
   1103 - (void)webkitDidEnterFullScreen
   1104 {
   1105     if (_element)
   1106         _element->document()->webkitDidEnterFullScreenForElement(_element.get());
   1107 }
   1108 
   1109 - (void)webkitWillExitFullScreen
   1110 {
   1111     if (_element)
   1112         _element->document()->webkitWillExitFullScreenForElement(_element.get());
   1113 }
   1114 
   1115 - (void)webkitDidExitFullScreen
   1116 {
   1117     if (_element)
   1118         _element->document()->webkitDidExitFullScreenForElement(_element.get());
   1119 }
   1120 
   1121 @end
   1122 
   1123 #endif
   1124