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