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