fa3385112f343e1ec092c4f94b787b63d2b5cb9d
[WebKit-https.git] / WebKit / WebCoreSupport.subproj / WebBridge.m
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import <WebKit/WebBridge.h>
30
31 #import <WebKit/WebAssertions.h>
32 #import <WebKit/WebBackForwardList.h>
33 #import <WebKit/WebBaseNetscapePluginView.h>
34 #import <WebKit/WebBasePluginPackage.h>
35 #import <WebKit/WebBaseResourceHandleDelegate.h>
36 #import "WebControllerSets.h"
37 #import <WebKit/WebDataSourcePrivate.h>
38 #import <WebKit/WebDefaultUIDelegate.h>
39 #import <WebKit/WebEditingDelegate.h>
40 #import <WebKit/WebFileButton.h>
41 #import <WebKit/WebFormDataStream.h>
42 #import <WebKit/WebFormDelegate.h>
43 #import <WebKit/WebFrameInternal.h>
44 #import <WebKit/WebFrameLoadDelegate.h>
45 #import <WebKit/WebFrameViewInternal.h>
46 #import <WebKit/WebHistoryItemPrivate.h>
47 #import <WebKit/WebHTMLRepresentationPrivate.h>
48 #import <WebKit/WebHTMLViewInternal.h>
49 #import <WebKit/WebImageView.h>
50 #import <WebKit/WebJavaPlugIn.h>
51 #import <WebKit/WebJavaScriptTextInputPanel.h>
52 #import <WebKit/WebKitErrorsPrivate.h>
53 #import <WebKit/WebKitLogging.h>
54 #import <WebKit/WebKitNSStringExtras.h>
55 #import <WebKit/WebKitStatisticsPrivate.h>
56 #import <WebKit/WebKitSystemBits.h>
57 #import <WebKit/WebNetscapePluginEmbeddedView.h>
58 #import <WebKit/WebNetscapePluginPackage.h>
59 #import <WebKit/WebNSObjectExtras.h>
60 #import <WebKit/WebNSURLExtras.h>
61 #import <WebKit/WebNSURLRequestExtras.h>
62 #import <WebKit/WebNullPluginView.h>
63 #import <WebKit/WebPlugin.h>
64 #import <WebKit/WebPluginController.h>
65 #import <WebKit/WebPluginDatabase.h>
66 #import <WebKit/WebPluginDocumentView.h>
67 #import <WebKit/WebPluginPackage.h>
68 #import <WebKit/WebPluginViewFactoryPrivate.h>
69 #import <WebKit/WebNetscapePluginDocumentView.h>
70 #import <WebKit/WebPreferencesPrivate.h>
71 #import <WebKit/WebResourcePrivate.h>
72 #import <WebKit/WebSubresourceClient.h>
73 #import <WebKit/WebViewInternal.h>
74 #import <WebKit/WebViewPrivate.h>
75 #import <WebKit/WebUIDelegatePrivate.h>
76
77 #import <Foundation/NSURLRequest.h>
78 #import <Foundation/NSURLConnection.h>
79 #import <Foundation/NSURLResponse.h>
80 #import <Foundation/NSURLResponsePrivate.h>
81 #import <Foundation/NSURLFileTypeMappings.h>
82
83 #import <WebKit/WebLocalizableStrings.h>
84
85 #import <JavaVM/jni.h>
86
87 #define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange"
88 #define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode")
89 #define UniversalAccessDomain CFSTR("com.apple.universalaccess")
90
91 // For compatibility only with old SPI. 
92 @interface NSObject (OldWebPlugin)
93 - (void)setIsSelected:(BOOL)f;
94 @end
95
96 @interface NSApplication (DeclarationStolenFromAppKit)
97 - (void)_cycleWindowsReversed:(BOOL)reversed;
98 @end
99
100 @interface NSView (AppKitSecretsWebBridgeKnowsAbout)
101 - (NSView *)_findLastViewInKeyViewLoop;
102 @end
103
104 @interface NSURLResponse (FoundationSecretsWebBridgeKnowsAbout)
105 - (NSTimeInterval)_calculatedExpiration;
106 @end
107
108 @interface NSView (JavaPluginSecrets)
109 - (jobject)pollForAppletInWindow: (NSWindow *)window;
110 @end
111
112 NSString *WebPluginBaseURLKey =     @"WebPluginBaseURL";
113 NSString *WebPluginAttributesKey =  @"WebPluginAttributes";
114 NSString *WebPluginContainerKey =   @"WebPluginContainer";
115
116 @implementation WebBridge
117
118 - (id)initWithWebFrame:(WebFrame *)webFrame
119 {
120     self = [super init];
121
122     ++WebBridgeCount;
123     
124     WebView *webView = [webFrame webView];
125     
126     // Non-retained because data source owns representation owns bridge.
127     // But WebFrame will call close on us before it goes away, which
128     // guarantees we will not have a stale reference.
129     _frame = webFrame;
130
131     [self setName:[webFrame name]];
132     [self initializeSettings:[webView _settings]];
133     [self setTextSizeMultiplier:[webView textSizeMultiplier]];
134
135     return self;
136 }
137
138 - (void)fini
139 {
140     ASSERT(_frame == nil);
141
142     if (_keyboardUIModeAccessed) {
143         [[NSDistributedNotificationCenter defaultCenter] 
144             removeObserver:self name:KeyboardUIModeDidChangeNotification object:nil];
145         [[NSNotificationCenter defaultCenter] 
146             removeObserver:self name:WebPreferencesChangedNotification object:nil];
147     }
148
149     --WebBridgeCount;
150 }
151
152 - (void)dealloc
153 {
154     [lastDashboardRegions release];
155     
156     [self fini];
157     [super dealloc];
158 }
159
160 - (void)finalize
161 {
162     [self fini];
163     [super finalize];
164 }
165
166 - (WebFrame *)webFrame
167 {
168     return _frame;
169 }
170
171 - (NSArray *)childFrames
172 {
173     ASSERT(_frame != nil);
174     NSArray *frames = [_frame childFrames];
175     NSEnumerator *e = [frames objectEnumerator];
176     NSMutableArray *frameBridges = [NSMutableArray arrayWithCapacity:[frames count]];
177     WebFrame *childFrame;
178     while ((childFrame = [e nextObject])) {
179         id frameBridge = [childFrame _bridge];
180         if (frameBridge)
181             [frameBridges addObject:frameBridge];
182     }
183     return frameBridges;
184 }
185
186 - (WebCoreBridge *)mainFrame
187 {
188     ASSERT(_frame != nil);
189     return [[[_frame webView] mainFrame] _bridge];
190 }
191
192 - (WebCoreBridge *)findFrameNamed:(NSString *)name;
193 {
194     ASSERT(_frame != nil);
195     return [[_frame findFrameNamed:name] _bridge];
196 }
197
198 - (NSView *)documentView
199 {
200     ASSERT(_frame != nil);
201     return [[_frame frameView] documentView];
202 }
203
204 - (WebCoreBridge *)createWindowWithURL:(NSURL *)URL frameName:(NSString *)name
205 {
206     ASSERT(_frame != nil);
207
208     NSMutableURLRequest *request = nil;
209
210     if (URL != nil && ![URL _web_isEmpty]) {
211         request = [NSMutableURLRequest requestWithURL:URL];
212         [request _web_setHTTPReferrer:[self referrer]];
213     }
214
215     WebView *currentWebView = [_frame webView];
216     id wd = [currentWebView UIDelegate];
217     WebView *newWebView = nil;
218     
219     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
220         newWebView = [wd webView:currentWebView createWebViewWithRequest:request];
221     else
222         newWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:request];
223     [newWebView _setTopLevelFrameName:name];
224     return [[newWebView mainFrame] _bridge];
225 }
226
227 - (void)showWindow
228 {
229     WebView *wv = [_frame webView];
230     [[wv _UIDelegateForwarder] webViewShow: wv];
231 }
232
233 - (BOOL)areToolbarsVisible
234 {
235     ASSERT(_frame != nil);
236     WebView *wv = [_frame webView];
237     id wd = [wv UIDelegate];
238     if ([wd respondsToSelector: @selector(webViewAreToolbarsVisible:)])
239         return [wd webViewAreToolbarsVisible: wv];
240     return [[WebDefaultUIDelegate sharedUIDelegate] webViewAreToolbarsVisible:wv];
241 }
242
243 - (void)setToolbarsVisible:(BOOL)visible
244 {
245     ASSERT(_frame != nil);
246     WebView *wv = [_frame webView];
247     [[wv _UIDelegateForwarder] webView:wv setToolbarsVisible:visible];
248 }
249
250 - (BOOL)areScrollbarsVisible
251 {
252     ASSERT(_frame != nil);
253     return [[_frame frameView] allowsScrolling];
254 }
255
256 - (void)setScrollbarsVisible:(BOOL)visible
257 {
258     ASSERT(_frame != nil);
259     [[_frame frameView] setAllowsScrolling:visible];
260 }
261
262 - (BOOL)isStatusBarVisible
263 {
264     ASSERT(_frame != nil);
265     WebView *wv = [_frame webView];
266     id wd = [wv UIDelegate];
267     if ([wd respondsToSelector: @selector(webViewIsStatusBarVisible:)])
268         return [wd webViewIsStatusBarVisible:wv];
269     return [[WebDefaultUIDelegate sharedUIDelegate] webViewIsStatusBarVisible:wv];
270 }
271
272 - (void)setStatusBarVisible:(BOOL)visible
273 {
274     ASSERT(_frame != nil);
275     WebView *wv = [_frame webView];
276     [[wv _UIDelegateForwarder] webView:wv setStatusBarVisible:visible];
277 }
278
279 - (void)setWindowFrame:(NSRect)frameRect
280 {
281     ASSERT(_frame != nil);
282     WebView *webView = [_frame webView];
283     [[webView _UIDelegateForwarder] webView:webView setFrame:frameRect];
284 }
285
286 - (NSRect)windowFrame
287 {
288     ASSERT(_frame != nil);
289     WebView *webView = [_frame webView];
290     return [[webView _UIDelegateForwarder] webViewFrame:webView];
291 }
292
293 - (void)setWindowContentRect:(NSRect)contentRect
294 {
295     ASSERT(_frame != nil);
296     WebView *webView = [_frame webView];
297     [[webView _UIDelegateForwarder] webView:webView setFrame:contentRect];
298 }
299
300 - (NSRect)windowContentRect
301 {
302     ASSERT(_frame != nil);
303     WebView *webView = [_frame webView];
304     return [[webView _UIDelegateForwarder] webViewContentRect:webView];
305 }
306
307 - (void)setWindowIsResizable:(BOOL)resizable
308 {
309     ASSERT(_frame != nil);
310     WebView *webView = [_frame webView];
311     [[webView _UIDelegateForwarder] webView:webView setResizable:resizable];
312 }
313
314 - (BOOL)windowIsResizable
315 {
316     ASSERT(_frame != nil);
317     WebView *webView = [_frame webView];
318     return [[webView _UIDelegateForwarder] webViewIsResizable:webView];
319 }
320
321 - (NSResponder *)firstResponder
322 {
323     ASSERT(_frame != nil);
324     WebView *webView = [_frame webView];
325     return [[webView _UIDelegateForwarder] webViewFirstResponder:webView];
326 }
327
328 - (void)makeFirstResponder:(NSResponder *)view
329 {
330     ASSERT(_frame != nil);
331     WebView *webView = [_frame webView];
332     [webView _pushPerformingProgrammaticFocus];
333     [[webView _UIDelegateForwarder] webView:webView makeFirstResponder:view];
334     [webView _popPerformingProgrammaticFocus];
335 }
336
337 - (BOOL)wasFirstResponderAtMouseDownTime:(NSResponder *)responder;
338 {
339     ASSERT(_frame != nil);
340     NSView *documentView = [[_frame frameView] documentView];
341     if (![documentView isKindOfClass:[WebHTMLView class]]) {
342         return NO;
343     }
344     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
345     return [webHTMLView _wasFirstResponderAtMouseDownTime:responder];
346 }
347
348 - (void)closeWindowSoon
349 {
350     [[_frame webView] performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
351 }
352
353 - (NSWindow *)window
354 {
355     ASSERT(_frame != nil);
356     return [[_frame frameView] window];
357 }
358
359 - (void)runJavaScriptAlertPanelWithMessage:(NSString *)message
360 {
361     WebView *wv = [_frame webView];
362     [[wv _UIDelegateForwarder] webView:wv runJavaScriptAlertPanelWithMessage:message];
363 }
364
365 - (BOOL)runJavaScriptConfirmPanelWithMessage:(NSString *)message
366 {
367     WebView *wv = [_frame webView];
368     id wd = [wv UIDelegate];
369     if ([wd respondsToSelector: @selector(webView:runJavaScriptConfirmPanelWithMessage:)])
370         return [wd webView:wv runJavaScriptConfirmPanelWithMessage:message];
371     return [[WebDefaultUIDelegate sharedUIDelegate] webView:wv runJavaScriptConfirmPanelWithMessage:message];
372 }
373
374 - (BOOL)runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText returningText:(NSString **)result
375 {
376     WebView *wv = [_frame webView];
377     id wd = [wv UIDelegate];
378     if ([wd respondsToSelector: @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:)])
379         *result = [wd webView:wv runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText];
380     else
381         *result = [[WebDefaultUIDelegate sharedUIDelegate] webView:wv runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText];
382     return *result != nil;
383 }
384
385 - (void)addMessageToConsole:(NSDictionary *)message
386 {
387     WebView *wv = [_frame webView];
388     id wd = [wv UIDelegate];
389     if ([wd respondsToSelector: @selector(webView:addMessageToConsole:)])
390         [wd webView:wv addMessageToConsole:message];
391 }
392
393 - (NSView <WebCoreFileButton> *)fileButtonWithDelegate:(id <WebCoreFileButtonDelegate>)delegate
394 {
395     return [[WebFileButton alloc] initWithBridge:self delegate:delegate];
396 }
397
398 - (void)runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener
399 {
400     WebView *wv = [_frame webView];
401     [[wv _UIDelegateForwarder] webView:wv runOpenPanelForFileButtonWithResultListener:resultListener];
402 }
403
404
405 - (WebDataSource *)dataSource
406 {
407     ASSERT(_frame != nil);
408     WebDataSource *dataSource = [_frame dataSource];
409
410     ASSERT(dataSource != nil);
411     ASSERT([dataSource _isCommitted]);
412
413     return dataSource;
414 }
415
416 - (void)setTitle:(NSString *)title
417 {
418     [[self dataSource] _setTitle:[title _webkit_stringByCollapsingNonPrintingCharacters]];
419 }
420
421 - (void)setStatusText:(NSString *)status
422 {
423     ASSERT(_frame != nil);
424     WebView *wv = [_frame webView];
425     [[wv _UIDelegateForwarder] webView:wv setStatusText:status];
426 }
427
428 - (void)receivedData:(NSData *)data textEncodingName:(NSString *)textEncodingName
429 {
430     // Set the encoding. This only needs to be done once, but it's harmless to do it again later.
431     NSString *encoding = [[self dataSource] _overrideEncoding];
432     BOOL userChosen = encoding != nil;
433     if (encoding == nil) {
434         encoding = textEncodingName;
435     }
436     [self setEncoding:encoding userChosen:userChosen];
437
438     [self addData:data];
439 }
440
441 - (id <WebCoreResourceHandle>)startLoadingResource:(id <WebCoreResourceLoader>)resourceLoader withURL:(NSURL *)URL customHeaders:(NSDictionary *)customHeaders
442 {
443     // If we are no longer attached to a WebView, this must be an attempted load from an
444     // onUnload handler, so let's just block it.
445     if ([[self dataSource] _webView] == nil) {
446         return nil;
447     }
448
449     // Since this is a subresource, we can load any URL (we ignore the return value).
450     // But we still want to know whether we should hide the referrer or not, so we call the canLoadURL method.
451     BOOL hideReferrer;
452     [self canLoadURL:URL fromReferrer:[self referrer] hideReferrer:&hideReferrer];
453
454     return [WebSubresourceClient startLoadingResource:resourceLoader
455                                               withURL:URL
456                                         customHeaders:customHeaders
457                                              referrer:(hideReferrer ? nil : [self referrer])
458                                         forDataSource:[self dataSource]];
459 }
460
461 - (id <WebCoreResourceHandle>)startLoadingResource:(id <WebCoreResourceLoader>)resourceLoader withURL:(NSURL *)URL customHeaders:(NSDictionary *)customHeaders postData:(NSArray *)postData
462 {
463     // If we are no longer attached to a WebView, this must be an attempted load from an
464     // onUnload handler, so let's just block it.
465     if ([[self dataSource] _webView] == nil) {
466         return nil;
467     }
468
469     // Since this is a subresource, we can load any URL (we ignore the return value).
470     // But we still want to know whether we should hide the referrer or not, so we call the canLoadURL method.
471     BOOL hideReferrer;
472     [self canLoadURL:URL fromReferrer:[self referrer] hideReferrer:&hideReferrer];
473
474     return [WebSubresourceClient startLoadingResource:resourceLoader
475                                               withURL:URL
476                                         customHeaders:customHeaders
477                                              postData:postData
478                                              referrer:(hideReferrer ? nil : [self referrer])
479                                         forDataSource:[self dataSource]];
480 }
481
482 - (void)objectLoadedFromCacheWithURL:(NSURL *)URL response:(NSURLResponse *)response data:(NSData *)data
483 {
484     // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
485     NSError *error;
486     id identifier;
487     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
488     [_frame _requestFromDelegateForRequest:request identifier:&identifier error:&error];    
489     [_frame _saveResourceAndSendRemainingDelegateMessagesWithRequest:request identifier:identifier response:response data:data error:error];
490     [request release];
491 }
492
493 - (NSData *)syncLoadResourceWithURL:(NSURL *)URL customHeaders:(NSDictionary *)requestHeaders postData:(NSArray *)postData finalURL:(NSURL **)finalURL responseHeaders:(NSDictionary **)responseHeaderDict statusCode:(int *)statusCode
494 {
495     // Since this is a subresource, we can load any URL (we ignore the return value).
496     // But we still want to know whether we should hide the referrer or not, so we call the canLoadURL method.
497     BOOL hideReferrer;
498     [self canLoadURL:URL fromReferrer:[self referrer] hideReferrer:&hideReferrer];
499
500     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
501
502     if (postData) {
503         [request setHTTPMethod:@"POST"];
504         webSetHTTPBody(request, postData);
505     }
506
507     NSEnumerator *e = [requestHeaders keyEnumerator];
508     NSString *key;
509     while ((key = (NSString *)[e nextObject]) != nil) {
510         [request addValue:[requestHeaders objectForKey:key] forHTTPHeaderField:key];
511     }
512     
513     // Never use cached data for these requests (xmlhttprequests).
514     [request setCachePolicy:[[[self dataSource] request] cachePolicy]];
515     if (!hideReferrer)
516         [request _web_setHTTPReferrer:[self referrer]];
517     
518     WebView *webView = [_frame webView];
519     [request setMainDocumentURL:[[[[webView mainFrame] dataSource] request] URL]];
520     [request _web_setHTTPUserAgent:[webView userAgentForURL:[request URL]]];
521     
522     NSError *error = nil;
523     id identifier = nil;    
524     NSURLRequest *newRequest = [_frame _requestFromDelegateForRequest:request identifier:&identifier error:&error];
525     
526     NSURLResponse *response = nil;
527     NSData *result = nil;
528     if (error == nil) {
529         ASSERT(newRequest != nil);
530         result = [NSURLConnection sendSynchronousRequest:newRequest returningResponse:&response error:&error];
531     }
532     
533     if (error == nil) {
534         *finalURL = [response URL];
535         if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
536             NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 
537             *responseHeaderDict = [httpResponse allHeaderFields];
538             *statusCode = [httpResponse statusCode];
539         } else {
540             *responseHeaderDict = [NSDictionary dictionary];
541             *statusCode = 200;
542         }
543     } else {
544         *finalURL = URL;
545         *responseHeaderDict = [NSDictionary dictionary];
546         if ([error domain] == NSURLErrorDomain) {
547             *statusCode = [error code];
548         } else {
549             *statusCode = 404;
550         }
551     }
552     
553     [_frame _saveResourceAndSendRemainingDelegateMessagesWithRequest:newRequest identifier:identifier response:response data:result error:error];
554     [request release];
555     
556     return result;
557 }
558
559 - (BOOL)isReloading
560 {
561     return [[[self dataSource] request] cachePolicy] == NSURLRequestReloadIgnoringCacheData;
562 }
563
564 // We would like a better value for a maximum time_t,
565 // but there is no way to do that in C with any certainty.
566 // INT_MAX should work well enough for our purposes.
567 #define MAX_TIME_T ((time_t)INT_MAX)    
568
569 - (time_t)expiresTimeForResponse:(NSURLResponse *)response
570 {
571     // This check can be removed when the new Foundation method
572     // has been around long enough for everyone to have it.
573     if ([response respondsToSelector:@selector(_calculatedExpiration)]) {
574         NSTimeInterval expiration = [response _calculatedExpiration];
575         expiration += kCFAbsoluteTimeIntervalSince1970;
576         return expiration > MAX_TIME_T ? MAX_TIME_T : expiration;
577     }
578
579     // Fall back to the older calculation
580     time_t now = time(NULL);
581     NSTimeInterval lifetime = [response _freshnessLifetime];
582     if (lifetime < 0)
583         lifetime = 0;
584     
585     if (now + lifetime > MAX_TIME_T)
586         return MAX_TIME_T;
587     
588     return now + lifetime;
589 }
590
591 - (void)reportClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
592 {
593     [_frame _clientRedirectedTo:URL delay:seconds fireDate:date lockHistory:lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction];
594 }
595
596 - (void)reportClientRedirectCancelled:(BOOL)cancelWithLoadInProgress
597 {
598     [_frame _clientRedirectCancelled:cancelWithLoadInProgress];
599 }
600
601 - (void)close
602 {
603     _frame = nil;
604 }
605
606 - (void)focusWindow
607 {
608     [[[_frame webView] _UIDelegateForwarder] webViewFocus:[_frame webView]];
609 }
610
611 - (void)unfocusWindow
612 {
613     if ([[self window] isKeyWindow] || [[[self window] attachedSheet] isKeyWindow]) {
614         [NSApp _cycleWindowsReversed:FALSE];
615     }
616 }
617
618 - (void)setIconURL:(NSURL *)URL
619 {
620     [[self dataSource] _setIconURL:URL];
621 }
622
623 - (void)setIconURL:(NSURL *)URL withType:(NSString *)type
624 {
625     [[self dataSource] _setIconURL:URL withType:type];
626 }
627
628 - (BOOL)canTargetLoadInFrame:(WebFrame *)targetFrame
629 {
630     // This method prevents this exploit:
631     // <rdar://problem/3715785> multiple frame injection vulnerability reported by Secunia, affects almost all browsers
632     
633     // don't mess with navigation purely within the same frame
634     if ([[self webFrame] webView] == [targetFrame webView]) {
635         return YES;
636     }
637
638     // Normally, domain should be called on the DOMDocument since it is a DOM method, but this fix is needed for
639     // Jaguar as well where the DOM API doesn't exist.
640     NSString *thisDomain = [self domain];
641     if ([thisDomain length] == 0) {
642         // Allow if the request is made from a local file.
643         return YES;
644     }
645     
646     WebFrame *parentFrame = [targetFrame parentFrame];
647     if (parentFrame == nil) {
648         // Allow if target is an entire window.
649         return YES;
650     }
651     
652     NSString *parentDomain = [[parentFrame _bridge] domain];
653     if (parentDomain != nil && [thisDomain _webkit_isCaseInsensitiveEqualToString:parentDomain]) {
654         // Allow if the domain of the parent of the targeted frame equals this domain.
655         return YES;
656     }
657
658     return NO;
659 }
660
661 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer reload:(BOOL)reload userGesture:(BOOL)forUser target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
662 {
663     BOOL hideReferrer;
664     if (![self canLoadURL:URL fromReferrer:referrer hideReferrer:&hideReferrer])
665         return;
666
667     if ([target length] == 0) {
668         target = nil;
669     }
670
671     WebFrame *targetFrame = [_frame findFrameNamed:target];
672     if (![self canTargetLoadInFrame:targetFrame]) {
673         return;
674     }
675     
676     WebFrameLoadType loadType;
677     
678     if (reload)
679         loadType = WebFrameLoadTypeReload;
680     else if (!forUser)
681         loadType = WebFrameLoadTypeInternal;
682     else
683         loadType = WebFrameLoadTypeStandard;
684     [_frame _loadURL:URL referrer:(hideReferrer ? nil : referrer) loadType:loadType target:target triggeringEvent:event form:form formValues:values];
685
686     if (targetFrame != nil && _frame != targetFrame) {
687         [[targetFrame _bridge] focusWindow];
688     }
689 }
690
691 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target data:(NSArray *)postData contentType:(NSString *)contentType triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
692 {
693     BOOL hideReferrer;
694     if (![self canLoadURL:URL fromReferrer:referrer hideReferrer:&hideReferrer])
695         return;
696
697     if ([target length] == 0) {
698         target = nil;
699     }
700
701     WebFrame *targetFrame = [_frame findFrameNamed:target];
702     if (![self canTargetLoadInFrame:targetFrame]) {
703         return;
704     }
705
706     [_frame _postWithURL:URL referrer:(hideReferrer ? nil : referrer) target:target data:postData contentType:contentType triggeringEvent:event form:form formValues:values];
707
708     if (targetFrame != nil && _frame != targetFrame) {
709         [[targetFrame _bridge] focusWindow];
710     }
711 }
712
713 - (NSString *)generateFrameName
714 {
715     return [_frame _generateFrameName];
716 }
717
718 - (WebCoreBridge *)createChildFrameNamed:(NSString *)frameName 
719                                  withURL:(NSURL *)URL
720                                 referrer:(NSString *)referrer
721                               renderPart:(KHTMLRenderPart *)childRenderPart
722                          allowsScrolling:(BOOL)allowsScrolling 
723                              marginWidth:(int)width
724                             marginHeight:(int)height
725 {
726     BOOL hideReferrer;
727     if (![self canLoadURL:URL fromReferrer:referrer hideReferrer:&hideReferrer])
728         return nil;
729
730     ASSERT(_frame != nil);
731     WebFrame *newFrame = [[_frame webView] _createFrameNamed:frameName inParent:_frame allowsScrolling:allowsScrolling];
732     if (newFrame == nil) {
733         return nil;
734     }
735     
736     [[newFrame _bridge] setRenderPart:childRenderPart];
737
738     [[newFrame frameView] _setMarginWidth:width];
739     [[newFrame frameView] _setMarginHeight:height];
740
741     [_frame _loadURL:URL referrer:(hideReferrer ? nil : referrer) intoChild:newFrame];
742
743     return [newFrame _bridge];
744 }
745
746 - (void)saveDocumentState: (NSArray *)documentState
747 {
748     WebHistoryItem *item = [_frame _itemForSavingDocState];
749     LOG(Loading, "%@: saving form state from to 0x%x", [_frame name], item);
750     if (item) {
751         [item setDocumentState: documentState];
752         // You might think we could save the scroll state here too, but unfortunately this
753         // often gets called after WebFrame::_transitionToCommitted has restored the scroll
754         // position of the next document.
755     }
756 }
757
758 - (NSArray *)documentState
759 {
760     LOG(Loading, "%@: restoring form state from item 0x%x", [_frame name], [_frame _itemForRestoringDocState]);
761     return [[_frame _itemForRestoringDocState] documentState];
762 }
763
764 - (BOOL)saveDocumentToPageCache: documentInfo
765 {
766     WebHistoryItem *item = [_frame _itemForSavingDocState];
767     if (![item hasPageCache]) {
768         return false;
769     }
770     [[item pageCache] setObject: documentInfo forKey: WebCorePageCacheStateKey];
771     return true;
772 }
773
774 - (NSString *)userAgentForURL:(NSURL *)URL
775 {
776     return [[_frame webView] userAgentForURL:URL];
777 }
778
779 - (BOOL)inNextKeyViewOutsideWebFrameViews
780 {
781     return _inNextKeyViewOutsideWebFrameViews;
782 }
783
784 - (NSView *)_nextKeyViewOutsideWebFrameViewsWithValidityCheck:(BOOL)mustBeValid
785 {
786     if (_inNextKeyViewOutsideWebFrameViews) {
787         // We should never get here, but unrepro bug 3997185 says we sometimes do.
788         // So we'll fail on debug builds to try to catch the problem, but on
789         // deployment builds we'll return nil to avoid recursing forever.
790         ASSERT_NOT_REACHED();
791         return nil;
792     }
793     
794     _inNextKeyViewOutsideWebFrameViews = YES;
795     WebView *webView = [_frame webView];
796     // Do not ask webView for its next key view, but rather, ask it for 
797     // the next key view of the last view in its key view loop.
798     // Doing so gives us the correct answer as calculated by AppKit, 
799     // and makes HTML views behave like other views.
800     NSView *lastViewInLoop = [webView _findLastViewInKeyViewLoop];
801     NSView *nextKeyView = mustBeValid ? [lastViewInLoop nextValidKeyView] : [lastViewInLoop nextKeyView];
802     _inNextKeyViewOutsideWebFrameViews = NO;
803     return nextKeyView;
804 }
805
806 - (NSView *)nextKeyViewOutsideWebFrameViews
807 {
808     return [self _nextKeyViewOutsideWebFrameViewsWithValidityCheck:NO];
809 }
810
811 - (NSView *)nextValidKeyViewOutsideWebFrameViews
812 {
813     return [self _nextKeyViewOutsideWebFrameViewsWithValidityCheck:YES];
814 }
815
816 - (NSView *)previousKeyViewOutsideWebFrameViews
817 {
818     WebView *webView = [_frame webView];
819     NSView *previousKeyView = [webView previousKeyView];
820     return previousKeyView;
821 }
822
823 - (BOOL)defersLoading
824 {
825     return [[_frame webView] defersCallbacks];
826 }
827
828 - (void)setDefersLoading:(BOOL)defers
829 {
830     [[_frame webView] setDefersCallbacks:defers];
831 }
832
833 - (void)setNeedsReapplyStyles
834 {
835     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
836     if ([view isKindOfClass:[WebHTMLView class]]) {
837         [(WebHTMLView *)view setNeedsToApplyStyles:YES];
838         [view setNeedsLayout:YES];
839         [view setNeedsDisplay:YES];
840     }
841 }
842
843 - (void)tokenizerProcessedData
844 {
845     [_frame _checkLoadComplete];
846 }
847
848 // OK to be an NSString rather than an NSURL.
849 // This URL is only used for coloring visited links.
850 - (NSString *)requestedURLString
851 {
852     return [[[[self dataSource] request] URL] _web_originalDataAsString];
853 }
854
855 - (NSString *)incomingReferrer
856 {
857     return [[[self dataSource] request] _web_HTTPReferrer];
858 }
859
860 - (NSView *)pluginViewWithPackage:(WebPluginPackage *)pluginPackage
861                    attributeNames:(NSArray *)attributeNames
862                   attributeValues:(NSArray *)attributeValues
863                           baseURL:(NSURL *)baseURL
864 {
865     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
866     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
867         
868     WebPluginController *pluginController = [docView _pluginController];
869     
870     // Store attributes in a dictionary so they can be passed to WebPlugins.
871     NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
872     unsigned count = [attributeNames count];
873     unsigned i;
874     for (i = 0; i < count; i++) {
875         [attributes setObject:[attributeValues objectAtIndex:i] forKey:[attributeNames objectAtIndex:i]];
876     }    
877     
878     [pluginPackage load];
879     Class viewFactory = [pluginPackage viewFactory];
880     
881     NSView *view = nil;
882     NSDictionary *arguments = nil;
883     
884     if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
885         arguments = [NSDictionary dictionaryWithObjectsAndKeys:
886             baseURL, WebPlugInBaseURLKey,
887             attributes, WebPlugInAttributesKey,
888             pluginController, WebPlugInContainerKey,
889             [NSNumber numberWithInt:WebPlugInModeEmbed], WebPlugInModeKey,
890             nil];
891         LOG(Plugins, "arguments:\n%@", arguments);
892     } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
893         arguments = [NSDictionary dictionaryWithObjectsAndKeys:
894             baseURL, WebPluginBaseURLKey,
895             attributes, WebPluginAttributesKey,
896             pluginController, WebPluginContainerKey,
897             nil];
898         LOG(Plugins, "arguments:\n%@", arguments);
899     }
900     
901     view = [WebPluginController plugInViewWithArguments:arguments fromPluginPackage:pluginPackage];
902     
903     [attributes release];
904     return view;
905 }
906
907 - (NSString *)valueForKey:(NSString *)key keys:(NSArray *)keys values:(NSArray *)values
908 {
909     unsigned count = [keys count];
910     unsigned i;
911     for (i = 0; i < count; i++) {
912         if ([[keys objectAtIndex:i] _webkit_isCaseInsensitiveEqualToString:key]) {
913             return [values objectAtIndex:i];
914         }
915     }
916     return nil;
917 }
918
919 - (NSView *)viewForPluginWithURL:(NSURL *)URL
920                   attributeNames:(NSArray *)attributeNames
921                  attributeValues:(NSArray *)attributeValues
922                         MIMEType:(NSString *)MIMEType
923 {
924     BOOL hideReferrer;
925     if (![self canLoadURL:URL fromReferrer:[self referrer] hideReferrer:&hideReferrer])
926         return nil;
927
928     ASSERT([attributeNames count] == [attributeValues count]);
929
930     WebBasePluginPackage *pluginPackage = nil;
931     NSView *view = nil;
932     int errorCode = 0;
933     
934     if ([MIMEType length] != 0) {
935         pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
936     } else {
937         MIMEType = nil;
938     }
939     
940     NSString *extension = [[URL path] pathExtension];
941     if (!pluginPackage && [extension length] != 0) {
942         pluginPackage = [[WebPluginDatabase installedPlugins] pluginForExtension:extension];
943         if (pluginPackage) {
944             NSString *newMIMEType = [pluginPackage MIMETypeForExtension:extension];
945             if ([newMIMEType length] != 0) {
946                 MIMEType = newMIMEType;
947             }
948         }
949     }
950
951     NSURL *baseURL = [self baseURL];
952     if (pluginPackage) {
953         if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) {
954             view = [self pluginViewWithPackage:(WebPluginPackage *)pluginPackage
955                                 attributeNames:attributeNames
956                                attributeValues:attributeValues
957                                        baseURL:baseURL];
958         } else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
959             view = [[[WebNetscapePluginEmbeddedView alloc] initWithFrame:NSZeroRect
960                                                                   plugin:(WebNetscapePluginPackage *)pluginPackage
961                                                                      URL:URL
962                                                                  baseURL:baseURL
963                                                                 MIMEType:MIMEType
964                                                            attributeKeys:attributeNames
965                                                          attributeValues:attributeValues] autorelease];
966         } else {
967             ASSERT_NOT_REACHED();
968         }
969     } else {
970         errorCode = WebKitErrorCannotFindPlugIn;
971     }
972
973     if (!errorCode && !view) {
974         errorCode = WebKitErrorCannotLoadPlugIn;
975     }
976
977     if (errorCode) {
978         NSString *pluginPage = [self valueForKey:@"pluginspage" keys:attributeNames values:attributeValues];
979         NSURL *pluginPageURL = pluginPage != nil ? [self URLWithAttributeString:pluginPage] : nil;
980         NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode
981                                                         contentURL:URL
982                                                      pluginPageURL:pluginPageURL
983                                                         pluginName:[pluginPackage name]
984                                                           MIMEType:MIMEType];
985         view = [[[WebNullPluginView alloc] initWithFrame:NSZeroRect error:error] autorelease];
986         [error release];
987     }
988     
989     ASSERT(view);
990     return view;
991 }
992
993 - (NSView *)viewForJavaAppletWithFrame:(NSRect)theFrame
994                         attributeNames:(NSArray *)attributeNames
995                        attributeValues:(NSArray *)attributeValues
996                                baseURL:(NSURL *)baseURL;
997 {
998     NSString *MIMEType = @"application/x-java-applet";
999     WebBasePluginPackage *pluginPackage;
1000     NSView *view = nil;
1001     
1002     pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
1003
1004     if (pluginPackage) {
1005         if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) {
1006             // For some reason, the Java plug-in requires that we pass the dimension of the plug-in as attributes.
1007             NSMutableArray *names = [attributeNames mutableCopy];
1008             NSMutableArray *values = [attributeValues mutableCopy];
1009             if ([self valueForKey:@"width" keys:attributeNames values:attributeValues] == nil) {
1010                 [names addObject:@"width"];
1011                 [values addObject:[NSString stringWithFormat:@"%d", (int)theFrame.size.width]];
1012             }
1013             if ([self valueForKey:@"height" keys:attributeNames values:attributeValues] == nil) {
1014                 [names addObject:@"height"];
1015                 [values addObject:[NSString stringWithFormat:@"%d", (int)theFrame.size.height]];
1016             }
1017             view = [self pluginViewWithPackage:(WebPluginPackage *)pluginPackage
1018                                 attributeNames:names
1019                                attributeValues:values
1020                                        baseURL:baseURL];
1021             [names release];
1022             [values release];
1023         } else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
1024             view = [[[WebNetscapePluginEmbeddedView alloc] initWithFrame:theFrame
1025                                                                   plugin:(WebNetscapePluginPackage *)pluginPackage
1026                                                                      URL:nil
1027                                                                  baseURL:baseURL
1028                                                                 MIMEType:MIMEType
1029                                                            attributeKeys:attributeNames
1030                                                          attributeValues:attributeValues] autorelease];
1031         } else {
1032             ASSERT_NOT_REACHED();
1033         }
1034     }
1035
1036     if (!view) {
1037         NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorJavaUnavailable
1038                                                         contentURL:nil
1039                                                      pluginPageURL:nil
1040                                                         pluginName:[pluginPackage name]
1041                                                           MIMEType:MIMEType];
1042         view = [[[WebNullPluginView alloc] initWithFrame:theFrame error:error] autorelease];
1043         [error release];
1044     }
1045
1046     ASSERT(view);
1047
1048     return view;
1049 }
1050
1051 #ifndef NDEBUG
1052 static BOOL loggedObjectCacheSize = NO;
1053 #endif
1054
1055 - (WebPreferences *)_preferences
1056 {
1057     WebPreferences *prefs = [[_frame webView] preferences];
1058     if (prefs == nil) {
1059         prefs = [WebPreferences standardPreferences];
1060     }
1061     return prefs;
1062 }
1063
1064 -(int)getObjectCacheSize
1065 {
1066     vm_size_t memSize = WebSystemMainMemory();
1067     int cacheSize = [[self _preferences] _objectCacheSize];
1068     int multiplier = 1;
1069     if (memSize >= 1024 * 1024 * 1024)
1070         multiplier = 4;
1071     else if (memSize >= 512 * 1024 * 1024)
1072         multiplier = 2;
1073
1074 #ifndef NDEBUG
1075     if (!loggedObjectCacheSize){
1076         LOG (CacheSizes, "Object cache size set to %d bytes.", cacheSize * multiplier);
1077         loggedObjectCacheSize = YES;
1078     }
1079 #endif
1080
1081     return cacheSize * multiplier;
1082 }
1083
1084 - (ObjectElementType)determineObjectFromMIMEType:(NSString*)MIMEType URL:(NSURL*)URL
1085 {
1086     if ([MIMEType length] == 0) {
1087         // Try to guess the MIME type based off the extension.
1088         NSString *extension = [[URL path] pathExtension];
1089         if ([extension length] > 0) {
1090             MIMEType = [[NSURLFileTypeMappings sharedMappings] MIMETypeForExtension:extension];
1091             if ([MIMEType length] == 0 && [[WebPluginDatabase installedPlugins] pluginForExtension:extension])
1092                 // If no MIME type is specified, use a plug-in if we have one that can handle the extension.
1093                 return ObjectElementPlugin;
1094         }
1095     }
1096
1097     if ([MIMEType length] == 0)
1098         return ObjectElementFrame; // Go ahead and hope that we can display the content.
1099                 
1100     Class viewClass = [WebFrameView _viewClassForMIMEType:MIMEType];
1101     if (!viewClass)
1102         // Nothing is registered at all.
1103         return ObjectElementNone;
1104     
1105     if ([viewClass isSubclassOfClass:[WebImageView class]])
1106         return ObjectElementImage;
1107     
1108     // If we're a supported type other than a plugin, we want to make a frame.
1109     // Ultimately we should just use frames for all mime types (plugins and HTML/XML/text documents),
1110     // but for now we're burdened with making a distinction between the two.
1111     if ([viewClass isSubclassOfClass:[WebNetscapePluginDocumentView class]] || [viewClass isSubclassOfClass:[WebPluginDocumentView class]])
1112         return ObjectElementPlugin;
1113     return ObjectElementFrame;
1114 }
1115
1116 - (void)loadEmptyDocumentSynchronously
1117 {
1118     NSURL *url = [[NSURL alloc] initWithString:@""];
1119     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
1120     [_frame loadRequest:request];
1121     [request release];
1122     [url release];
1123 }
1124
1125 - (NSString *)MIMETypeForPath:(NSString *)path
1126 {
1127     ASSERT(path);
1128     NSString *extension = [path pathExtension];
1129     NSString *type = [[NSURLFileTypeMappings sharedMappings] MIMETypeForExtension:extension];
1130     return [type length] == 0 ? @"application/octet-stream" : type;
1131 }
1132
1133 - (void)allowDHTMLDrag:(BOOL *)flagDHTML UADrag:(BOOL *)flagUA
1134 {
1135     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
1136     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
1137     unsigned int mask = [docView _delegateDragSourceActionMask];
1138     *flagDHTML = (mask & WebDragSourceActionDHTML) != 0;
1139     *flagUA = ((mask & WebDragSourceActionImage) || (mask & WebDragSourceActionLink) || (mask & WebDragSourceActionSelection));
1140 }
1141
1142 - (BOOL)startDraggingImage:(NSImage *)dragImage at:(NSPoint)dragLoc operation:(NSDragOperation)op event:(NSEvent *)event sourceIsDHTML:(BOOL)flag DHTMLWroteData:(BOOL)dhtmlWroteData
1143 {
1144     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
1145     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
1146     return [docView _startDraggingImage:dragImage at:dragLoc operation:op event:event sourceIsDHTML:flag DHTMLWroteData:dhtmlWroteData];
1147 }
1148
1149 - (void)handleAutoscrollForMouseDragged:(NSEvent *)event;
1150 {
1151     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
1152
1153     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
1154
1155     [docView _handleAutoscrollForMouseDragged:event];
1156 }
1157
1158 - (BOOL)mayStartDragAtEventLocation:(NSPoint)location
1159 {
1160     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
1161
1162     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
1163
1164     return [docView _mayStartDragAtEventLocation:location];
1165 }
1166
1167 - (BOOL)selectWordBeforeMenuEvent
1168 {
1169     return [[_frame webView] _selectWordBeforeMenuEvent];
1170 }
1171
1172 - (int)historyLength
1173 {
1174     return [[[_frame webView] backForwardList] backListCount] + 1;
1175 }
1176
1177 - (BOOL)canGoBackOrForward:(int)distance
1178 {
1179     if (distance == 0)
1180         return TRUE;
1181
1182     if (distance > 0 && distance <= [[[_frame webView] backForwardList] forwardListCount])
1183         return TRUE;
1184
1185     if (distance < 0 && -distance <= [[[_frame webView] backForwardList] backListCount])
1186         return TRUE;
1187     
1188     return FALSE;
1189 }
1190
1191 - (void)goBackOrForward:(int)distance
1192 {
1193     if (distance == 0) {
1194         return;
1195     }
1196     WebView *webView = [_frame webView];
1197     WebBackForwardList *list = [webView backForwardList];
1198     WebHistoryItem *item = [list itemAtIndex:distance];
1199     if (!item) {
1200         if (distance > 0) {
1201             int forwardListCount = [list forwardListCount];
1202             if (forwardListCount > 0) {
1203                 item = [list itemAtIndex:forwardListCount];
1204             }
1205         } else {
1206             int backListCount = [list forwardListCount];
1207             if (backListCount > 0) {
1208                 item = [list itemAtIndex:-backListCount];
1209             }
1210         }
1211     }
1212     if (item) {
1213         [webView goToBackForwardItem:item];
1214     }
1215 }
1216
1217 static id <WebFormDelegate> formDelegate(WebBridge *self)
1218 {
1219     ASSERT(self->_frame != nil);
1220     return [[self->_frame webView] _formDelegate];
1221 }
1222
1223 #define FormDelegateLog(ctrl)  LOG(FormDelegate, "control=%@", ctrl)
1224
1225 - (void)controlTextDidBeginEditing:(NSNotification *)obj
1226 {
1227     FormDelegateLog([obj object]);
1228     [formDelegate(self) controlTextDidBeginEditing:obj inFrame:_frame];
1229 }
1230
1231 - (void)controlTextDidEndEditing:(NSNotification *)obj
1232 {
1233     FormDelegateLog([obj object]);
1234     [formDelegate(self) controlTextDidEndEditing:obj inFrame:_frame];
1235 }
1236
1237 - (void)controlTextDidChange:(NSNotification *)obj
1238 {
1239     FormDelegateLog([obj object]);
1240     [formDelegate(self) controlTextDidChange:obj inFrame:_frame];
1241 }
1242
1243 - (void)textDidChange:(NSNotification *)obj
1244 {
1245     FormDelegateLog([obj object]);
1246     [formDelegate(self) textDidChange:obj inFrame:_frame];
1247 }
1248
1249 - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
1250 {
1251     FormDelegateLog(control);
1252     return [formDelegate(self) control:control textShouldBeginEditing:fieldEditor inFrame:_frame];
1253 }
1254
1255 - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
1256 {
1257     FormDelegateLog(control);
1258     return [formDelegate(self) control:control textShouldEndEditing:fieldEditor inFrame:_frame];
1259 }
1260
1261 - (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string errorDescription:(NSString *)error
1262 {
1263     FormDelegateLog(control);
1264     return [formDelegate(self) control:control didFailToFormatString:string errorDescription:error inFrame:_frame];
1265 }
1266
1267 - (void)control:(NSControl *)control didFailToValidatePartialString:(NSString *)string errorDescription:(NSString *)error
1268 {
1269     FormDelegateLog(control);
1270     [formDelegate(self) control:control didFailToValidatePartialString:string errorDescription:error inFrame:_frame];
1271 }
1272
1273 - (BOOL)control:(NSControl *)control isValidObject:(id)obj
1274 {
1275     FormDelegateLog(control);
1276     return [formDelegate(self) control:control isValidObject:obj inFrame:_frame];
1277 }
1278
1279 - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
1280 {
1281     FormDelegateLog(control);
1282     return [formDelegate(self) control:control textView:textView doCommandBySelector:commandSelector inFrame:_frame];
1283 }
1284
1285 - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView shouldHandleEvent:(NSEvent *)event
1286 {
1287     FormDelegateLog(control);
1288     return [formDelegate(self) control:control textView:textView shouldHandleEvent:event inFrame:_frame];
1289 }
1290
1291 - (void)frameDetached
1292 {
1293     // Put _frame into a local variable because _detachFromParent
1294     // will disconnect the bridge from the frame and make _frame nil.
1295     WebFrame *frame = _frame;
1296
1297     [frame stopLoading];
1298     [frame _detachFromParent];
1299     [[frame parentFrame] _removeChild:frame];
1300 }
1301
1302 - (void)setHasBorder:(BOOL)hasBorder
1303 {
1304     [[_frame frameView] _setHasBorder:hasBorder];
1305 }
1306
1307 - (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification
1308 {
1309     CFPreferencesAppSynchronize(UniversalAccessDomain);
1310
1311     Boolean keyExistsAndHasValidFormat;
1312     int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat);
1313     
1314     // The keyboard access mode is reported by two bits:
1315     // Bit 0 is set if feature is on
1316     // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists
1317     // We require both bits to be on.
1318     // I do not know that we would ever get one bit on and the other off since
1319     // checking the checkbox in system preferences which is marked as "Turn on full keyboard access"
1320     // turns on both bits.
1321     _keyboardUIMode = (mode & 0x2) ? WebCoreKeyboardAccessFull : WebCoreKeyboardAccessDefault;
1322     
1323     // check for tabbing to links
1324     if ([[self _preferences] tabsToLinks]) {
1325         _keyboardUIMode |= WebCoreKeyboardAccessTabsToLinks;
1326     }
1327 }
1328
1329 - (WebCoreKeyboardUIMode)keyboardUIMode
1330 {
1331     if (!_keyboardUIModeAccessed) {
1332         _keyboardUIModeAccessed = YES;
1333         [self _retrieveKeyboardUIModeFromPreferences:nil];
1334         
1335         [[NSDistributedNotificationCenter defaultCenter] 
1336             addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 
1337             name:KeyboardUIModeDidChangeNotification object:nil];
1338
1339         [[NSNotificationCenter defaultCenter] 
1340             addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 
1341                    name:WebPreferencesChangedNotification object:nil];
1342     }
1343     return _keyboardUIMode;
1344 }
1345
1346 - (void)didSetName:(NSString *)name
1347 {
1348     [_frame _setName:name];
1349 }
1350
1351 - (NSFileWrapper *)fileWrapperForURL:(NSURL *)URL
1352 {
1353     return [[_frame dataSource] _fileWrapperForURL:URL];
1354 }
1355
1356 - (void)print
1357 {
1358     id wd = [[_frame webView] UIDelegate];
1359     
1360     if ([wd respondsToSelector:@selector(webView:printFrameView:)]) {
1361         [wd webView:[_frame webView] printFrameView:[_frame frameView]];
1362     } else if ([wd respondsToSelector:@selector(webViewPrint:)]) {
1363         // Backward-compatible, but webViewPrint: was never public, so probably not needed.
1364         [wd webViewPrint:[_frame webView]];
1365     } else {
1366         [[WebDefaultUIDelegate sharedUIDelegate] webView:[_frame webView] printFrameView:[_frame frameView]];
1367     }
1368 }
1369
1370 - (jobject)getAppletInView:(NSView *)view
1371 {
1372     jobject applet = 0;
1373
1374     if ([view respondsToSelector: @selector(webPlugInGetApplet)])
1375         applet = [view webPlugInGetApplet];
1376     else
1377         applet = [self pollForAppletInView:view];
1378         
1379     return applet;
1380 }
1381
1382 // NOTE: pollForAppletInView: will block until the block is ready to use, or
1383 // until a timeout is exceeded.  It will return nil if the timeour is
1384 // exceeded.
1385 // Deprecated, use getAppletInView:.
1386 - (jobject)pollForAppletInView: (NSView *)view
1387 {
1388     jobject applet = 0;
1389     
1390     if ([view respondsToSelector: @selector(pollForAppletInWindow:)]) {
1391         // The Java VM needs the containing window of the view to
1392         // initialize.  The view may not yet be in the window's view 
1393         // hierarchy, so we have to pass the window when requesting
1394         // the applet.
1395         applet = [view pollForAppletInWindow:[[_frame webView] window]];
1396     }
1397     
1398     return applet;
1399 }
1400
1401 - (void)respondToChangedContents
1402 {
1403     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
1404     if ([view isKindOfClass:[WebHTMLView class]]) {
1405         [(WebHTMLView *)view _updateFontPanel];
1406     }
1407     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeNotification object:[_frame webView]];
1408 }
1409
1410 - (void)respondToChangedSelection
1411 {
1412     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
1413     if ([view isKindOfClass:[WebHTMLView class]]) {
1414         [(WebHTMLView *)view _selectionChanged];
1415     }
1416     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeSelectionNotification object:[_frame webView]];
1417 }
1418
1419 - (NSUndoManager *)undoManager
1420 {
1421     return [[_frame webView] undoManager];
1422 }
1423
1424 - (void)issueCutCommand
1425 {
1426     [[_frame webView] cut:nil];
1427 }
1428
1429 - (void)issueCopyCommand
1430 {
1431     [[_frame webView] copy:nil];
1432 }
1433
1434 - (void)issuePasteCommand
1435 {
1436     [[_frame webView] paste:nil];
1437 }
1438
1439 - (void)issuePasteAndMatchStyleCommand
1440 {
1441     [[_frame webView] pasteAsPlainText:nil];
1442 }
1443
1444 - (void)issueTransposeCommand
1445 {
1446     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
1447     if ([view isKindOfClass:[WebHTMLView class]]) {
1448         [(WebHTMLView *)view transpose:nil];
1449     }
1450 }
1451
1452 - (BOOL)canPaste
1453 {
1454     return [[_frame webView] _canPaste];
1455 }
1456
1457 - (void)setIsSelected:(BOOL)isSelected forView:(NSView *)view
1458 {
1459     if ([view respondsToSelector:@selector(webPlugInSetIsSelected:)]) {
1460         [view webPlugInSetIsSelected:isSelected];
1461     }
1462     else if ([view respondsToSelector:@selector(setIsSelected:)]) {
1463         [view setIsSelected:isSelected];
1464     }
1465 }
1466
1467 - (NSString *)overrideMediaType
1468 {
1469     return [[_frame webView] mediaStyle];
1470 }
1471
1472 - (BOOL)isEditable
1473 {
1474     return [[_frame webView] isEditable];
1475 }
1476
1477 - (BOOL)shouldBeginEditing:(DOMRange *)range
1478 {
1479     return [[_frame webView] _shouldBeginEditingInDOMRange:range];
1480 }
1481
1482 - (BOOL)shouldEndEditing:(DOMRange *)range
1483 {
1484     return [[_frame webView] _shouldEndEditingInDOMRange:range];
1485 }
1486
1487 - (void)windowObjectCleared
1488 {
1489     WebView *wv = [_frame webView];
1490     [[wv _frameLoadDelegateForwarder] webView:wv windowScriptObjectAvailable:[self windowScriptObject]];
1491 }
1492
1493 - (int)spellCheckerDocumentTag
1494 {
1495     return [[_frame webView] spellCheckerDocumentTag];
1496 }
1497
1498 - (BOOL)isContinuousSpellCheckingEnabled
1499 {
1500     return [[_frame webView] isContinuousSpellCheckingEnabled];
1501 }
1502
1503 - (void)didFirstLayout
1504 {
1505     WebView *wv = [_frame webView];
1506     [[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:_frame];
1507 }
1508
1509 - (BOOL)_compareDashboardRegions:(NSDictionary *)regions
1510 {
1511     return [lastDashboardRegions isEqualToDictionary:regions];
1512 }
1513
1514 - (void)dashboardRegionsChanged:(NSMutableDictionary *)regions
1515 {
1516     WebView *wv = [_frame webView];
1517     id wd = [wv UIDelegate];
1518     
1519     [wv _addScrollerDashboardRegions:regions];
1520     
1521     if (![self _compareDashboardRegions:regions]) {
1522         if ([wd respondsToSelector: @selector(webView:dashboardRegionsChanged:)]) {
1523             [wd webView:wv dashboardRegionsChanged:regions];
1524             [lastDashboardRegions release];
1525             lastDashboardRegions = [regions retain];
1526         }
1527     }
1528 }
1529
1530 - (NSString *)nameForUndoAction:(WebUndoAction)undoAction
1531 {
1532     switch (undoAction) {
1533         case WebUndoActionUnspecified: return nil;
1534         case WebUndoActionSetColor: return UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name");
1535         case WebUndoActionSetBackgroundColor: return UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name");
1536         case WebUndoActionTurnOffKerning: return UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name");
1537         case WebUndoActionTightenKerning: return UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name");
1538         case WebUndoActionLoosenKerning: return UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name");
1539         case WebUndoActionUseStandardKerning: return UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name");
1540         case WebUndoActionTurnOffLigatures: return UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name");
1541         case WebUndoActionUseStandardLigatures: return UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name");
1542         case WebUndoActionUseAllLigatures: return UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name");
1543         case WebUndoActionRaiseBaseline: return UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name");
1544         case WebUndoActionLowerBaseline: return UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name");
1545         case WebUndoActionSetTraditionalCharacterShape: return UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name");
1546         case WebUndoActionSetFont: return UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name");
1547         case WebUndoActionChangeAttributes: return UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name");
1548         case WebUndoActionAlignLeft: return UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name");
1549         case WebUndoActionAlignRight: return UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name");
1550         case WebUndoActionCenter: return UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name");
1551         case WebUndoActionJustify: return UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name");
1552         case WebUndoActionSetWritingDirection: return UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name");
1553         case WebUndoActionSubscript: return UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name");
1554         case WebUndoActionSuperscript: return UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name");
1555         case WebUndoActionUnderline: return UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name");
1556         case WebUndoActionOutline: return UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name");
1557         case WebUndoActionUnscript: return UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name");
1558         case WebUndoActionDrag: return UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name");
1559         case WebUndoActionCut: return UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name");
1560         case WebUndoActionPaste: return UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name");
1561         case WebUndoActionPasteFont: return UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name");
1562         case WebUndoActionPasteRuler: return UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name");
1563         case WebUndoActionTyping: return UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
1564     }
1565     return nil;
1566 }
1567
1568 // FIXME: The following 2 functions are copied from AppKit. It would be best share code.
1569
1570 // MF:!!! For now we will use static character sets for the computation, but we should eventually probably make these keys in the language dictionaries.
1571 // MF:!!! The following characters (listed with their nextstep encoding values) were in the preSmartTable in the old text objet, but aren't yet in the new text object: NS_FIGSPACE (0x80), exclamdown (0xa1), sterling (0xa3), yen (0xa5), florin (0xa6) section (0xa7), currency (0xa8), quotesingle (0xa9), quotedblleft (0xaa), guillemotleft (0xab), guilsinglleft (0xac), endash (0xb1), quotesinglbase (0xb8), quotedblbase (0xb9), questiondown (0xbf), emdash (0xd0), plusminus (0xd1).
1572 // MF:!!! The following characters (listed with their nextstep encoding values) were in the postSmartTable in the old text objet, but aren't yet in the new text object: NS_FIGSPACE (0x80), cent (0xa2), guilsinglright (0xad), registered (0xb0), dagger (0xa2), daggerdbl (0xa3), endash (0xb1), quotedblright (0xba), guillemotright (0xbb), perthousand (0xbd), onesuperior (0xc0), twosuperior (0xc9), threesuperior (0xcc), emdash (0xd0), ordfeminine (0xe3), ordmasculine (0xeb).
1573 // MF:!!! Another difference in both of these sets from the old text object is we include all the whitespace in whitespaceAndNewlineCharacterSet.
1574 #define _preSmartString @"([\"\'#$/-`{"
1575 #define _postSmartString @")].,;:?\'!\"%*-/}"
1576
1577 static NSCharacterSet *_getPreSmartSet(void)
1578 {
1579     static NSMutableCharacterSet *_preSmartSet = nil;
1580     if (!_preSmartSet) {
1581         _preSmartSet = [[NSMutableCharacterSet characterSetWithCharactersInString:_preSmartString] retain];
1582         [_preSmartSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
1583         // Adding CJK ranges
1584         [_preSmartSet addCharactersInRange:NSMakeRange(0x1100, 256)]; // Hangul Jamo (0x1100 - 0x11FF)
1585         [_preSmartSet addCharactersInRange:NSMakeRange(0x2E80, 352)]; // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
1586         [_preSmartSet addCharactersInRange:NSMakeRange(0x2FF0, 464)]; // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
1587         [_preSmartSet addCharactersInRange:NSMakeRange(0x3200, 29392)]; // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
1588         [_preSmartSet addCharactersInRange:NSMakeRange(0xAC00, 11183)]; // Hangul Syllables (0xAC00 - 0xD7AF)
1589         [_preSmartSet addCharactersInRange:NSMakeRange(0xF900, 352)]; // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
1590         [_preSmartSet addCharactersInRange:NSMakeRange(0xFE30, 32)]; // CJK Compatibility From (0xFE30 - 0xFE4F)
1591         [_preSmartSet addCharactersInRange:NSMakeRange(0xFF00, 240)]; // Half/Full Width Form (0xFF00 - 0xFFEF)
1592         [_preSmartSet addCharactersInRange:NSMakeRange(0x20000, 0xA6D7)]; // CJK Ideograph Exntension B
1593         [_preSmartSet addCharactersInRange:NSMakeRange(0x2F800, 0x021E)]; // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)
1594     }
1595     return _preSmartSet;
1596 }
1597
1598 static NSCharacterSet *_getPostSmartSet(void)
1599 {
1600     static NSMutableCharacterSet *_postSmartSet = nil;
1601     if (!_postSmartSet) {
1602         _postSmartSet = [[NSMutableCharacterSet characterSetWithCharactersInString:_postSmartString] retain];
1603         [_postSmartSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
1604         [_postSmartSet addCharactersInRange:NSMakeRange(0x1100, 256)]; // Hangul Jamo (0x1100 - 0x11FF)
1605         [_postSmartSet addCharactersInRange:NSMakeRange(0x2E80, 352)]; // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
1606         [_postSmartSet addCharactersInRange:NSMakeRange(0x2FF0, 464)]; // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
1607         [_postSmartSet addCharactersInRange:NSMakeRange(0x3200, 29392)]; // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
1608         [_postSmartSet addCharactersInRange:NSMakeRange(0xAC00, 11183)]; // Hangul Syllables (0xAC00 - 0xD7AF)
1609         [_postSmartSet addCharactersInRange:NSMakeRange(0xF900, 352)]; // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
1610         [_postSmartSet addCharactersInRange:NSMakeRange(0xFE30, 32)]; // CJK Compatibility From (0xFE30 - 0xFE4F)
1611         [_postSmartSet addCharactersInRange:NSMakeRange(0xFF00, 240)]; // Half/Full Width Form (0xFF00 - 0xFFEF)
1612         [_postSmartSet addCharactersInRange:NSMakeRange(0x20000, 0xA6D7)]; // CJK Ideograph Exntension B
1613         [_postSmartSet addCharactersInRange:NSMakeRange(0x2F800, 0x021E)]; // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)        
1614         [_postSmartSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
1615     }
1616     return _postSmartSet;
1617 }
1618
1619 - (BOOL)isCharacterSmartReplaceExempt:(unichar)c isPreviousCharacter:(BOOL)isPreviousCharacter
1620 {
1621     return [isPreviousCharacter ? _getPreSmartSet() : _getPostSmartSet() characterIsMember:c];
1622 }
1623
1624 - (WebCoreBridge *)createModalDialogWithURL:(NSURL *)URL
1625 {
1626     ASSERT(_frame != nil);
1627
1628     NSMutableURLRequest *request = nil;
1629
1630     if (URL != nil && ![URL _web_isEmpty]) {
1631         request = [NSMutableURLRequest requestWithURL:URL];
1632         [request _web_setHTTPReferrer:[self referrer]];
1633     }
1634
1635     WebView *currentWebView = [_frame webView];
1636     id UIDelegate = [currentWebView UIDelegate];
1637
1638     WebView *newWebView = nil;
1639     if ([UIDelegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)])
1640         newWebView = [UIDelegate webView:currentWebView createWebViewModalDialogWithRequest:request];
1641     else if ([UIDelegate respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1642         newWebView = [UIDelegate webView:currentWebView createWebViewWithRequest:request];
1643     else
1644         newWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:request];
1645
1646     return [[newWebView mainFrame] _bridge];
1647 }
1648
1649 - (BOOL)canRunModal
1650 {
1651     WebView *webView = [_frame webView];
1652     id UIDelegate = [webView UIDelegate];
1653     return [UIDelegate respondsToSelector:@selector(webViewRunModal:)];
1654 }
1655
1656 - (BOOL)canRunModalNow
1657 {
1658     return [self canRunModal] && ![WebBaseResourceHandleDelegate inConnectionCallback];
1659 }
1660
1661 - (void)runModal
1662 {
1663     if (![self canRunModal])
1664         return;
1665
1666     WebView *webView = [_frame webView];
1667     if ([webView defersCallbacks]) {
1668         ERROR("tried to run modal in a view when it was deferring callbacks -- should never happen");
1669         return;
1670     }
1671
1672     // Defer callbacks in all the other views in this group, so we don't try to run JavaScript
1673     // in a way that could interact with this view.
1674     NSMutableArray *deferredWebViews = [NSMutableArray array];
1675     NSString *setName = [webView groupName];
1676     if (setName) {
1677         NSEnumerator *enumerator = [WebViewSets webViewsInSetNamed:setName];
1678         WebView *otherWebView;
1679         while ((otherWebView = [enumerator nextObject]) != nil) {
1680             if (otherWebView != webView && ![otherWebView defersCallbacks]) {
1681                 [otherWebView setDefersCallbacks:YES];
1682                 [deferredWebViews addObject:otherWebView];
1683             }
1684         }
1685     }
1686
1687     // Go run the modal event loop.
1688     [[webView UIDelegate] webViewRunModal:webView];
1689
1690     // Restore the callbacks for any views that we deferred them for.
1691     unsigned count = [deferredWebViews count];
1692     unsigned i;
1693     for (i = 0; i < count; ++i) {
1694         WebView *otherWebView = [deferredWebViews objectAtIndex:i];
1695         [otherWebView setDefersCallbacks:NO];
1696     }
1697 }
1698
1699 @end