c69420f9b5a97dd6bcecd5121168fbb8477731e2
[WebKit-https.git] / WebKit / WebCoreSupport / WebFrameBridge.mm
1 /*
2  * Copyright (C) 2005, 2006 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 "WebFrameBridge.h"
30
31 #import "WebBackForwardList.h"
32 #import "WebBaseNetscapePluginView.h"
33 #import "WebBasePluginPackage.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultUIDelegate.h"
36 #import "WebEditingDelegate.h"
37 #import "WebFormDelegate.h"
38 #import "WebFrameInternal.h"
39 #import "WebFrameLoadDelegate.h"
40 #import "WebFrameLoaderClient.h"
41 #import "WebFrameViewInternal.h"
42 #import "WebHTMLRepresentationPrivate.h"
43 #import "WebHTMLViewInternal.h"
44 #import "WebHistoryItemInternal.h"
45 #import "WebHistoryItemPrivate.h"
46 #import "WebIconDatabase.h"
47 #import "WebIconDatabasePrivate.h"
48 #import "WebJavaPlugIn.h"
49 #import "WebJavaScriptTextInputPanel.h"
50 #import "WebKitErrorsPrivate.h"
51 #import "WebKitLogging.h"
52 #import "WebKitNSStringExtras.h"
53 #import "WebKitStatisticsPrivate.h"
54 #import "WebKitSystemBits.h"
55 #import "WebLocalizableStrings.h"
56 #import "WebNSObjectExtras.h"
57 #import "WebNSURLExtras.h"
58 #import "WebNSURLRequestExtras.h"
59 #import "WebNSViewExtras.h"
60 #import "WebNetscapePluginEmbeddedView.h"
61 #import "WebNetscapePluginPackage.h"
62 #import "WebNullPluginView.h"
63 #import "WebPlugin.h"
64 #import "WebPluginController.h"
65 #import "WebPluginDatabase.h"
66 #import "WebPluginPackage.h"
67 #import "WebPluginViewFactoryPrivate.h"
68 #import "WebPreferencesPrivate.h"
69 #import "WebResourcePrivate.h"
70 #import "WebScriptDebugServerPrivate.h"
71 #import "WebUIDelegatePrivate.h"
72 #import "WebViewInternal.h"
73 #import <Foundation/NSURLConnection.h>
74 #import <Foundation/NSURLRequest.h>
75 #import <Foundation/NSURLResponse.h>
76 #import <JavaScriptCore/Assertions.h>
77 #import <JavaVM/jni.h>
78 #import <WebCore/Cache.h>
79 #import <WebCore/Document.h>
80 #import <WebCore/DocumentLoader.h>
81 #import <WebCore/FrameLoader.h>
82 #import <WebCore/FrameLoaderClient.h>
83 #import <WebCore/FrameMac.h>
84 #import <WebCore/FrameTree.h>
85 #import <WebCore/HTMLFrameOwnerElement.h>
86 #import <WebCore/Page.h>
87 #import <WebCore/ResourceLoader.h>
88 #import <WebCore/SubresourceLoader.h>
89 #import <WebCore/WebCoreSettings.h>
90 #import <WebKitSystemInterface.h>
91 #import <wtf/RefPtr.h>
92 #import <WebCore/MimeTypeRegistry.h>
93
94 // For compatibility with old SPI. 
95 @interface NSView (OldWebPlugin)
96 - (void)setIsSelected:(BOOL)f;
97 @end
98
99 @interface NSView (AppKitSecretsWebBridgeKnowsAbout)
100 - (NSView *)_findLastViewInKeyViewLoop;
101 @end
102
103 @interface NSView (JavaPluginSecrets)
104 - (jobject)pollForAppletInWindow:(NSWindow *)window;
105 @end
106
107 using namespace WebCore;
108
109 NSString *WebPluginBaseURLKey =     @"WebPluginBaseURL";
110 NSString *WebPluginAttributesKey =  @"WebPluginAttributes";
111 NSString *WebPluginContainerKey =   @"WebPluginContainer";
112
113 #define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange"
114 #define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode")
115 #define UniversalAccessDomain CFSTR("com.apple.universalaccess")
116
117 @implementation WebFrameBridge
118
119 - (WebView *)webView
120 {
121     return kit(m_frame->page());
122 }
123
124 - (void)finishInitializingWithPage:(Page*)page frameName:(NSString *)name frameView:(WebFrameView *)frameView ownerElement:(HTMLFrameOwnerElement*)ownerElement
125 {
126     ++WebBridgeCount;
127
128     WebView *webView = kit(page);
129
130     _frame = [[WebFrame alloc] _initWithWebFrameView:frameView webView:webView bridge:self];
131
132     m_frame = new FrameMac(page, ownerElement, new WebFrameLoaderClient(_frame));
133     m_frame->setBridge(self);
134     m_frame->tree()->setName(name);
135     m_frame->setSettings([[webView _settings] settings]);
136     
137     [self setTextSizeMultiplier:[webView textSizeMultiplier]];
138
139     // FIXME: This is one-time initialization, but it gets the value of the setting from the
140     // current WebView. That's a mismatch and not good!
141     static bool initializedObjectCacheSize;
142     if (!initializedObjectCacheSize) {
143         initializedObjectCacheSize = true;
144         cache()->setMaximumSize([self getObjectCacheSize]);
145     }
146 }
147
148 - (id)initMainFrameWithPage:(Page*)page frameName:(NSString *)name frameView:(WebFrameView *)frameView
149 {
150     self = [super init];
151     [self finishInitializingWithPage:page frameName:name frameView:frameView ownerElement:0];
152     return self;
153 }
154
155 - (id)initSubframeWithOwnerElement:(HTMLFrameOwnerElement*)ownerElement frameName:(NSString *)name frameView:(WebFrameView *)frameView
156 {
157     self = [super init];
158     [self finishInitializingWithPage:ownerElement->document()->frame()->page() frameName:name frameView:frameView ownerElement:ownerElement];
159     return self;
160 }
161
162 - (void)fini
163 {
164     if (_keyboardUIModeAccessed) {
165         [[NSDistributedNotificationCenter defaultCenter] 
166             removeObserver:self name:KeyboardUIModeDidChangeNotification object:nil];
167         [[NSNotificationCenter defaultCenter] 
168             removeObserver:self name:WebPreferencesChangedNotification object:nil];
169     }
170     ASSERT(_frame == nil);
171     --WebBridgeCount;
172 }
173
174 - (void)dealloc
175 {
176     [lastDashboardRegions release];
177     [_frame release];
178     
179     [self fini];
180     [super dealloc];
181 }
182
183 - (void)finalize
184 {
185     [self fini];
186     [super finalize];
187 }
188
189 - (WebPreferences *)_preferences
190 {
191     return [[self webView] preferences];
192 }
193
194 - (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification
195 {
196     CFPreferencesAppSynchronize(UniversalAccessDomain);
197
198     Boolean keyExistsAndHasValidFormat;
199     int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat);
200     
201     // The keyboard access mode is reported by two bits:
202     // Bit 0 is set if feature is on
203     // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists
204     // We require both bits to be on.
205     // I do not know that we would ever get one bit on and the other off since
206     // checking the checkbox in system preferences which is marked as "Turn on full keyboard access"
207     // turns on both bits.
208     _keyboardUIMode = (mode & 0x2) ? KeyboardAccessFull : KeyboardAccessDefault;
209     
210     // check for tabbing to links
211     if ([[self _preferences] tabsToLinks])
212         _keyboardUIMode = (KeyboardUIMode)(_keyboardUIMode | KeyboardAccessTabsToLinks);
213 }
214
215 - (KeyboardUIMode)keyboardUIMode
216 {
217     if (!_keyboardUIModeAccessed) {
218         _keyboardUIModeAccessed = YES;
219         [self _retrieveKeyboardUIModeFromPreferences:nil];
220         
221         [[NSDistributedNotificationCenter defaultCenter] 
222             addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 
223             name:KeyboardUIModeDidChangeNotification object:nil];
224
225         [[NSNotificationCenter defaultCenter] 
226             addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 
227                    name:WebPreferencesChangedNotification object:nil];
228     }
229     return _keyboardUIMode;
230 }
231
232 - (WebFrame *)webFrame
233 {
234     return _frame;
235 }
236
237 - (WebCoreFrameBridge *)mainFrame
238 {
239     ASSERT(_frame != nil);
240     return [[[self webView] mainFrame] _bridge];
241 }
242
243 - (NSView *)documentView
244 {
245     ASSERT(_frame != nil);
246     return [[_frame frameView] documentView];
247 }
248
249 - (NSResponder *)firstResponder
250 {
251     ASSERT(_frame != nil);
252     WebView *webView = [self webView];
253     return [[webView _UIDelegateForwarder] webViewFirstResponder:webView];
254 }
255
256 - (void)makeFirstResponder:(NSResponder *)view
257 {
258     ASSERT(_frame != nil);
259     WebView *webView = [self webView];
260     [webView _pushPerformingProgrammaticFocus];
261     [[webView _UIDelegateForwarder] webView:webView makeFirstResponder:view];
262     [webView _popPerformingProgrammaticFocus];
263 }
264
265 - (void)willMakeFirstResponderForNodeFocus
266 {
267     ASSERT([[[_frame frameView] documentView] isKindOfClass:[WebHTMLView class]]);
268     [(WebHTMLView *)[[_frame frameView] documentView] _willMakeFirstResponderForNodeFocus];
269 }
270
271 - (BOOL)textViewWasFirstResponderAtMouseDownTime:(NSTextView *)textView;
272 {
273     ASSERT(_frame != nil);
274     NSView *documentView = [[_frame frameView] documentView];
275     if (![documentView isKindOfClass:[WebHTMLView class]])
276         return NO;
277     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
278     return [webHTMLView _textViewWasFirstResponderAtMouseDownTime:textView];
279 }
280
281 - (void)closeWindowSoon
282 {
283     WebView *parentWebView = [self webView];
284
285     // We need to remove the parent WebView from WebViewSets here, before it actually
286     // closes, to make sure that JavaScript code that executes before it closes
287     // can't find it. Otherwise, window.open will select a closed WebView instead of 
288     // opening a new one <rdar://problem/3572585>.
289
290     // We also need to stop the load to prevent further parsing or JavaScript execution
291     // after the window has torn down <rdar://problem/4161660>.
292   
293     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
294     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
295     // This approach is an inherent limitation of not making a close execute immediately
296     // after a call to window.close.
297     
298     [parentWebView setGroupName:nil];
299     [parentWebView stopLoading:self];
300     [parentWebView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
301 }
302
303 - (NSWindow *)window
304 {
305     ASSERT(_frame != nil);
306     return [[_frame frameView] window];
307 }
308
309 - (void)runJavaScriptAlertPanelWithMessage:(NSString *)message
310 {
311     WebView *wv = [self webView];
312     id wd = [wv UIDelegate];
313     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
314     // fall back to shared delegate's implementation of new version.
315     if ([wd respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)])
316         [wd webView:wv runJavaScriptAlertPanelWithMessage:message initiatedByFrame:_frame];
317     else if ([wd respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:)])
318         [wd webView:wv runJavaScriptAlertPanelWithMessage:message];
319     else
320         [[WebDefaultUIDelegate sharedUIDelegate] webView:wv runJavaScriptAlertPanelWithMessage:message initiatedByFrame:_frame];
321 }
322
323 - (BOOL)runJavaScriptConfirmPanelWithMessage:(NSString *)message
324 {
325     WebView *wv = [self webView];
326     id wd = [wv UIDelegate];
327     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
328     // fall back to shared delegate's implementation of new version.
329     if ([wd respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)])
330         return [wd webView:wv runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:_frame];
331     if ([wd respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:)])
332         return [wd webView:wv runJavaScriptConfirmPanelWithMessage:message];    
333     return [[WebDefaultUIDelegate sharedUIDelegate] webView:wv runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:_frame];
334 }
335
336 - (BOOL)shouldInterruptJavaScript
337 {
338     WebView *wv = [self webView];
339     id wd = [wv UIDelegate];
340     if ([wd respondsToSelector:@selector(webViewShouldInterruptJavaScript:)])
341         return [wd webViewShouldInterruptJavaScript:wv];
342     return NO;
343 }
344
345 - (BOOL)canRunBeforeUnloadConfirmPanel
346 {
347     WebView *wv = [self webView];
348     id wd = [wv UIDelegate];
349     return [wd respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
350 }
351
352 - (BOOL)runBeforeUnloadConfirmPanelWithMessage:(NSString *)message
353 {
354     WebView *wv = [self webView];
355     id wd = [wv UIDelegate];
356     if ([wd respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)])
357         return [wd webView:wv runBeforeUnloadConfirmPanelWithMessage:message initiatedByFrame:_frame];
358     return YES;
359 }
360
361 - (BOOL)runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText returningText:(NSString **)result
362 {
363     WebView *wv = [self webView];
364     id wd = [wv UIDelegate];
365     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
366     // fall back to shared delegate's implementation of new version.
367     if ([wd respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)])
368         *result = [wd webView:wv runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:_frame];
369     else if ([wd respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:)])
370         *result = [wd webView:wv runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText];
371     else
372         *result = [[WebDefaultUIDelegate sharedUIDelegate] webView:wv runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:_frame];
373     return *result != nil;
374 }
375
376 - (void)runOpenPanelForFileButtonWithResultListener:(id<WebCoreOpenPanelResultListener>)resultListener
377 {
378     WebView *wv = [self webView];
379     [[wv _UIDelegateForwarder] webView:wv runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener];
380 }
381
382 - (WebDataSource *)dataSource
383 {
384     ASSERT(_frame != nil);
385     WebDataSource *dataSource = [_frame dataSource];
386
387     ASSERT(dataSource != nil);
388
389     return dataSource;
390 }
391
392 - (void)setStatusText:(NSString *)status
393 {
394     ASSERT(_frame != nil);
395     WebView *wv = [self webView];
396     [[wv _UIDelegateForwarder] webView:wv setStatusText:status];
397 }
398
399 - (void)close
400 {
401     [super close];
402     [_frame release];
403     _frame = nil;
404 }
405
406 - (void)formControlIsBecomingFirstResponder:(NSView *)formControl
407 {
408     // When a form element becomes first responder, its enclosing WebHTMLView might need to
409     // change its focus-displaying state, but isn't otherwise notified.
410     [(WebHTMLView *)[[_frame frameView] documentView] _formControlIsBecomingFirstResponder:formControl];
411 }
412
413 - (void)formControlIsResigningFirstResponder:(NSView *)formControl
414 {
415     // When a form element resigns first responder, its enclosing WebHTMLView might need to
416     // change its focus-displaying state, but isn't otherwise notified.
417     [(WebHTMLView *)[[_frame frameView] documentView] _formControlIsResigningFirstResponder:formControl];
418 }
419
420 - (WebCoreFrameBridge *)createChildFrameNamed:(NSString *)frameName 
421                                       withURL:(NSURL *)URL
422                                      referrer:(const String&)referrer
423                                  ownerElement:(HTMLFrameOwnerElement*)ownerElement
424                               allowsScrolling:(BOOL)allowsScrolling 
425                                   marginWidth:(int)width
426                                  marginHeight:(int)height
427 {
428     bool hideReferrer;
429     if (!m_frame->loader()->canLoad(URL, referrer, hideReferrer))
430         return nil;
431
432     ASSERT(_frame);
433     
434     WebFrameView *childView = [[WebFrameView alloc] initWithFrame:NSMakeRect(0,0,0,0)];
435     [childView setAllowsScrolling:allowsScrolling];
436     WebFrameBridge *newBridge = [[WebFrameBridge alloc] initSubframeWithOwnerElement:ownerElement frameName:frameName frameView:childView];
437     [_frame _addChild:[newBridge webFrame]];
438     [childView release];
439
440     [childView _setMarginWidth:width];
441     [childView _setMarginHeight:height];
442
443     [newBridge release];
444
445     if (!newBridge)
446         return nil;
447
448     [_frame _loadURL:URL referrer:(hideReferrer ? String() : referrer) intoChild:[newBridge webFrame]];
449
450     return newBridge;
451 }
452
453 - (void)saveDocumentState:(NSArray *)documentState
454 {
455     WebHistoryItem *item = [_frame _itemForSavingDocState];
456     LOG(Loading, "%@: saving form state from to 0x%x", [_frame name], item);
457     if (item)
458         [item setDocumentState:documentState];
459         // You might think we could save the scroll state here too, but unfortunately this
460         // often gets called after WebFrame::_transitionToCommitted has restored the scroll
461         // position of the next document.
462 }
463
464 - (NSArray *)documentState
465 {
466     LOG(Loading, "%@: restoring form state from item 0x%x", [_frame name], [_frame _itemForRestoringDocState]);
467     return [[_frame _itemForRestoringDocState] documentState];
468 }
469
470 - (NSString *)userAgentForURL:(NSURL *)URL
471 {
472     return [[self webView] userAgentForURL:URL];
473 }
474
475 - (BOOL)inNextKeyViewOutsideWebFrameViews
476 {
477     return _inNextKeyViewOutsideWebFrameViews;
478 }
479
480 - (NSView *)_nextKeyViewOutsideWebFrameViewsWithValidityCheck:(BOOL)mustBeValid
481 {
482     // We can get here in unusual situations such as the one listed in 4451831, so we
483     // return nil to avoid an infinite recursion.
484     if (_inNextKeyViewOutsideWebFrameViews)
485         return nil;
486     
487     _inNextKeyViewOutsideWebFrameViews = YES;
488     WebView *webView = [self webView];
489     // Do not ask webView for its next key view, but rather, ask it for 
490     // the next key view of the last view in its key view loop.
491     // Doing so gives us the correct answer as calculated by AppKit, 
492     // and makes HTML views behave like other views.
493     NSView *lastViewInLoop = [webView _findLastViewInKeyViewLoop];
494     NSView *nextKeyView = mustBeValid ? [lastViewInLoop nextValidKeyView] : [lastViewInLoop nextKeyView];
495     _inNextKeyViewOutsideWebFrameViews = NO;
496     return nextKeyView;
497 }
498
499 - (NSView *)nextKeyViewOutsideWebFrameViews
500 {
501     return [self _nextKeyViewOutsideWebFrameViewsWithValidityCheck:NO];
502 }
503
504 - (NSView *)nextValidKeyViewOutsideWebFrameViews
505 {
506     return [self _nextKeyViewOutsideWebFrameViewsWithValidityCheck:YES];
507 }
508
509 - (NSView *)previousKeyViewOutsideWebFrameViews
510 {
511     return [[self webView] previousKeyView];
512 }
513
514 - (void)setNeedsReapplyStyles
515 {
516     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
517     if ([view isKindOfClass:[WebHTMLView class]]) {
518         [(WebHTMLView *)view setNeedsToApplyStyles:YES];
519         [view setNeedsLayout:YES];
520         [view setNeedsDisplay:YES];
521     }
522 }
523
524 - (NSView *)pluginViewWithPackage:(WebPluginPackage *)pluginPackage
525                    attributeNames:(NSArray *)attributeNames
526                   attributeValues:(NSArray *)attributeValues
527                           baseURL:(NSURL *)baseURL
528                        DOMElement:(DOMElement *)element
529                      loadManually:(BOOL)loadManually
530 {
531     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
532     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
533         
534     WebPluginController *pluginController = [docView _pluginController];
535     
536     // Store attributes in a dictionary so they can be passed to WebPlugins.
537     NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:attributeValues forKeys:attributeNames];
538     
539     [pluginPackage load];
540     Class viewFactory = [pluginPackage viewFactory];
541     
542     NSView *view = nil;
543     NSDictionary *arguments = nil;
544     
545     if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
546         arguments = [NSDictionary dictionaryWithObjectsAndKeys:
547             baseURL, WebPlugInBaseURLKey,
548             attributes, WebPlugInAttributesKey,
549             pluginController, WebPlugInContainerKey,
550             [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey,
551             [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey,
552             element, WebPlugInContainingElementKey,
553             nil];
554         LOG(Plugins, "arguments:\n%@", arguments);
555     } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
556         arguments = [NSDictionary dictionaryWithObjectsAndKeys:
557             baseURL, WebPluginBaseURLKey,
558             attributes, WebPluginAttributesKey,
559             pluginController, WebPluginContainerKey,
560             element, WebPlugInContainingElementKey,
561             nil];
562         LOG(Plugins, "arguments:\n%@", arguments);
563     }
564
565     view = [WebPluginController plugInViewWithArguments:arguments fromPluginPackage:pluginPackage];
566     
567     [attributes release];
568     return view;
569 }
570
571 - (NSString *)valueForKey:(NSString *)key keys:(NSArray *)keys values:(NSArray *)values
572 {
573     unsigned count = [keys count];
574     unsigned i;
575     for (i = 0; i < count; i++)
576         if ([[keys objectAtIndex:i] _webkit_isCaseInsensitiveEqualToString:key])
577             return [values objectAtIndex:i];
578     return nil;
579 }
580
581 - (NSView *)viewForPluginWithURL:(NSURL *)URL
582                   attributeNames:(NSArray *)attributeNames
583                  attributeValues:(NSArray *)attributeValues
584                         MIMEType:(NSString *)MIMEType
585                       DOMElement:(DOMElement *)element
586                     loadManually:(BOOL)loadManually
587 {
588     bool hideReferrer;
589     if (!m_frame->loader()->canLoad(URL, m_frame->loader()->outgoingReferrer(), hideReferrer))
590         return nil;
591
592     ASSERT([attributeNames count] == [attributeValues count]);
593
594     WebBasePluginPackage *pluginPackage = nil;
595     NSView *view = nil;
596     int errorCode = 0;
597
598     WebView *wv = [self webView];
599     id wd = [wv UIDelegate];
600
601     if ([wd respondsToSelector:@selector(webView:plugInViewWithArguments:)]) {
602         NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithObjects:attributeValues forKeys:attributeNames];
603         NSDictionary *arguments = [NSDictionary dictionaryWithObjectsAndKeys:
604             attributes, WebPlugInAttributesKey,
605             [NSNumber numberWithInt:loadManually ? WebPlugInModeFull : WebPlugInModeEmbed], WebPlugInModeKey,
606             URL, WebPlugInBaseURLKey, // URL might be nil, so add it last
607             [NSNumber numberWithBool:!loadManually], WebPlugInShouldLoadMainResourceKey,
608             element, WebPlugInContainingElementKey,
609             nil];
610         [attributes release];
611         view = [wd webView:wv plugInViewWithArguments:arguments];
612         if (view)
613             return view;
614     }
615
616     if ([MIMEType length] != 0)
617         pluginPackage = [[self webView] _pluginForMIMEType:MIMEType];
618     else
619         MIMEType = nil;
620     
621     NSString *extension = [[URL path] pathExtension];
622     if (!pluginPackage && [extension length] != 0) {
623         pluginPackage = [[self webView] _pluginForExtension:extension];
624         if (pluginPackage) {
625             NSString *newMIMEType = [pluginPackage MIMETypeForExtension:extension];
626             if ([newMIMEType length] != 0)
627                 MIMEType = newMIMEType;
628         }
629     }
630
631     NSURL *baseURL = [self baseURL];
632     if (pluginPackage) {
633         if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) {
634             view = [self pluginViewWithPackage:(WebPluginPackage *)pluginPackage
635                                 attributeNames:attributeNames
636                                attributeValues:attributeValues
637                                        baseURL:baseURL
638                                     DOMElement:element
639                                   loadManually:loadManually];
640         } else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
641             WebNetscapePluginEmbeddedView *embeddedView = [[[WebNetscapePluginEmbeddedView alloc] initWithFrame:NSZeroRect
642                                                                   plugin:(WebNetscapePluginPackage *)pluginPackage
643                                                                      URL:URL
644                                                                  baseURL:baseURL
645                                                                 MIMEType:MIMEType
646                                                            attributeKeys:attributeNames
647                                                          attributeValues:attributeValues
648                                                             loadManually:loadManually
649                                                               DOMElement:element] autorelease];
650             view = embeddedView;
651             [_frame _addPlugInView:embeddedView];
652         } else
653             ASSERT_NOT_REACHED();
654     } else
655         errorCode = WebKitErrorCannotFindPlugIn;
656
657     if (!errorCode && !view)
658         errorCode = WebKitErrorCannotLoadPlugIn;
659
660     if (errorCode) {
661         NSString *pluginPage = [self valueForKey:@"pluginspage" keys:attributeNames values:attributeValues];
662         NSURL *pluginPageURL = pluginPage != nil ? [self URLWithAttributeString:pluginPage] : nil;
663         NSError *error = [[NSError alloc] _initWithPluginErrorCode:errorCode
664                                                         contentURL:URL
665                                                      pluginPageURL:pluginPageURL
666                                                         pluginName:[pluginPackage name]
667                                                           MIMEType:MIMEType];
668         WebNullPluginView *nullView = [[[WebNullPluginView alloc] initWithFrame:NSZeroRect error:error] autorelease];
669         [_frame _addPlugInView:nullView];
670         view = nullView;
671         [error release];
672     }
673     
674     ASSERT(view);
675     return view;
676 }
677
678 - (void)redirectDataToPlugin:(NSView *)pluginView
679 {
680     WebHTMLRepresentation *representation = (WebHTMLRepresentation *)[[_frame dataSource] representation];
681
682     if ([pluginView isKindOfClass:[WebNetscapePluginEmbeddedView class]])
683         [representation _redirectDataToManualLoader:(WebNetscapePluginEmbeddedView *)pluginView forPluginView:pluginView];
684     else {
685         WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
686         ASSERT([docView isKindOfClass:[WebHTMLView class]]);
687         
688         WebPluginController *pluginController = [docView _pluginController];
689         [representation _redirectDataToManualLoader:pluginController forPluginView:pluginView];
690     }
691 }
692
693 - (NSView *)viewForJavaAppletWithFrame:(NSRect)theFrame
694                         attributeNames:(NSArray *)attributeNames
695                        attributeValues:(NSArray *)attributeValues
696                                baseURL:(NSURL *)baseURL
697                             DOMElement:(DOMElement *)element
698 {
699     NSString *MIMEType = @"application/x-java-applet";
700     WebBasePluginPackage *pluginPackage;
701     NSView *view = nil;
702     
703     pluginPackage = [[self webView] _pluginForMIMEType:MIMEType];
704
705     if (pluginPackage) {
706         if ([pluginPackage isKindOfClass:[WebPluginPackage class]]) {
707             // For some reason, the Java plug-in requires that we pass the dimension of the plug-in as attributes.
708             NSMutableArray *names = [attributeNames mutableCopy];
709             NSMutableArray *values = [attributeValues mutableCopy];
710             if ([self valueForKey:@"width" keys:attributeNames values:attributeValues] == nil) {
711                 [names addObject:@"width"];
712                 [values addObject:[NSString stringWithFormat:@"%d", (int)theFrame.size.width]];
713             }
714             if ([self valueForKey:@"height" keys:attributeNames values:attributeValues] == nil) {
715                 [names addObject:@"height"];
716                 [values addObject:[NSString stringWithFormat:@"%d", (int)theFrame.size.height]];
717             }
718             view = [self pluginViewWithPackage:(WebPluginPackage *)pluginPackage
719                                 attributeNames:names
720                                attributeValues:values
721                                        baseURL:baseURL
722                                     DOMElement:element
723                                   loadManually:NO];
724             [names release];
725             [values release];
726         } else if ([pluginPackage isKindOfClass:[WebNetscapePluginPackage class]]) {
727             view = [[[WebNetscapePluginEmbeddedView alloc] initWithFrame:theFrame
728                                                                   plugin:(WebNetscapePluginPackage *)pluginPackage
729                                                                      URL:nil
730                                                                  baseURL:baseURL
731                                                                 MIMEType:MIMEType
732                                                            attributeKeys:attributeNames
733                                                          attributeValues:attributeValues
734                                                             loadManually:NO
735                                                               DOMElement:element] autorelease];
736         } else {
737             ASSERT_NOT_REACHED();
738         }
739     }
740
741     if (!view) {
742         NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorJavaUnavailable
743                                                         contentURL:nil
744                                                      pluginPageURL:nil
745                                                         pluginName:[pluginPackage name]
746                                                           MIMEType:MIMEType];
747         view = [[[WebNullPluginView alloc] initWithFrame:theFrame error:error] autorelease];
748         [error release];
749     }
750
751     ASSERT(view);
752
753     return view;
754 }
755
756 #ifndef NDEBUG
757 static BOOL loggedObjectCacheSize = NO;
758 #endif
759
760 -(int)getObjectCacheSize
761 {
762     vm_size_t memSize = WebSystemMainMemory();
763     int cacheSize = [[self _preferences] _objectCacheSize];
764     int multiplier = 1;
765     
766     // 2GB and greater will be 128mb.  1gb and greater will be 64mb.
767     // Otherwise just use 32mb.
768     if (memSize >= (unsigned)(2048 * 1024 * 1024)) 
769         multiplier = 4;
770     else if (memSize >= 1024 * 1024 * 1024)
771         multiplier = 2;
772
773 #ifndef NDEBUG
774     if (!loggedObjectCacheSize){
775         LOG(CacheSizes, "Object cache size set to %d bytes.", cacheSize * multiplier);
776         loggedObjectCacheSize = YES;
777     }
778 #endif
779
780     return cacheSize * multiplier;
781 }
782
783 - (ObjectElementType)determineObjectFromMIMEType:(NSString*)MIMEType URL:(NSURL*)URL
784 {
785     if ([MIMEType length] == 0) {
786         // Try to guess the MIME type based off the extension.
787         NSString *extension = [[URL path] pathExtension];
788         if ([extension length] > 0) {
789             MIMEType = WKGetMIMETypeForExtension(extension);
790             if ([MIMEType length] == 0 && [[self webView] _pluginForExtension:extension])
791                 // If no MIME type is specified, use a plug-in if we have one that can handle the extension.
792                 return ObjectElementPlugin;
793         }
794     }
795
796     if ([MIMEType length] == 0)
797         return ObjectElementFrame; // Go ahead and hope that we can display the content.
798
799     if (MimeTypeRegistry::isSupportedImageMIMEType(MIMEType))
800         return ObjectElementFrame;
801
802     if ([[self webView] _isMIMETypeRegisteredAsPlugin:MIMEType])
803         return ObjectElementPlugin;
804
805     if ([WebFrameView _viewClassForMIMEType:MIMEType])
806         return ObjectElementFrame;
807     
808     return ObjectElementNone;
809 }
810
811 - (NSString *)MIMETypeForPath:(NSString *)path
812 {
813     ASSERT(path);
814     NSString *extension = [path pathExtension];
815     NSString *type = WKGetMIMETypeForExtension(extension);
816     return [type length] == 0 ? (NSString *)@"application/octet-stream" : type;
817 }
818
819 - (void)allowDHTMLDrag:(BOOL *)flagDHTML UADrag:(BOOL *)flagUA
820 {
821     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
822     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
823     unsigned int mask = [docView _delegateDragSourceActionMask];
824     *flagDHTML = (mask & WebDragSourceActionDHTML) != 0;
825     *flagUA = ((mask & WebDragSourceActionImage) || (mask & WebDragSourceActionLink) || (mask & WebDragSourceActionSelection));
826 }
827
828 - (BOOL)startDraggingImage:(NSImage *)dragImage at:(NSPoint)dragLoc operation:(NSDragOperation)op
829     event:(NSEvent *)event sourceIsDHTML:(BOOL)flag DHTMLWroteData:(BOOL)dhtmlWroteData
830 {
831     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
832     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
833     [docView _setInitiatedDrag:YES];
834     return [docView _startDraggingImage:dragImage at:dragLoc operation:op event:event
835         sourceIsDHTML:flag DHTMLWroteData:dhtmlWroteData];
836 }
837
838 - (BOOL)mayStartDragAtEventLocation:(NSPoint)location
839 {
840     WebHTMLView *docView = (WebHTMLView *)[[_frame frameView] documentView];
841     ASSERT([docView isKindOfClass:[WebHTMLView class]]);
842     return [docView _mayStartDragAtEventLocation:location];
843 }
844
845 - (int)historyLength
846 {
847     return [[[self webView] backForwardList] backListCount] + 1;
848 }
849
850 - (BOOL)canGoBackOrForward:(int)distance
851 {
852     if (distance == 0)
853         return YES;
854     if (distance > 0 && distance <= [[[self webView] backForwardList] forwardListCount])
855         return YES;
856     if (distance < 0 && -distance <= [[[self webView] backForwardList] backListCount])
857         return YES;
858     return NO;
859 }
860
861 - (void)goBackOrForward:(int)distance
862 {
863     if (distance == 0)
864         return;
865     WebView *webView = [self webView];
866     WebBackForwardList *list = [webView backForwardList];
867     WebHistoryItem *item = [list itemAtIndex:distance];
868     if (!item) {
869         if (distance > 0) {
870             int forwardListCount = [list forwardListCount];
871             if (forwardListCount > 0) {
872                 item = [list itemAtIndex:forwardListCount];
873             }
874         } else {
875             int backListCount = [list forwardListCount];
876             if (backListCount > 0) {
877                 item = [list itemAtIndex:-backListCount];
878             }
879         }
880     }
881     if (item) {
882         [webView goToBackForwardItem:item];
883     }
884 }
885
886 - (NSURL*)historyURL:(int)distance
887 {
888     WebView *webView = [self webView];
889     WebBackForwardList *list = [webView backForwardList];
890     WebHistoryItem *item = [list itemAtIndex:distance];
891     if (!item) {
892         if (distance > 0) {
893             int forwardListCount = [list forwardListCount];
894             if (forwardListCount > 0)
895                 item = [list itemAtIndex:forwardListCount];
896         } else {
897             int backListCount = [list forwardListCount];
898             if (backListCount > 0)
899                 item = [list itemAtIndex:-backListCount];
900         }
901     }
902     if (item)
903         return [item URL];
904     
905     return nil;
906 }
907
908 static id <WebFormDelegate> formDelegate(WebFrameBridge *self)
909 {
910     ASSERT(self->_frame != nil);
911     return [[self->_frame webView] _formDelegate];
912 }
913
914 #define FormDelegateLog(ctrl)  LOG(FormDelegate, "control=%@", ctrl)
915
916 - (void)textFieldDidBeginEditing:(DOMHTMLInputElement *)element
917 {
918     FormDelegateLog(element);
919     [formDelegate(self) textFieldDidBeginEditing:element inFrame:_frame];
920 }
921
922 - (void)textFieldDidEndEditing:(DOMHTMLInputElement *)element
923 {
924     FormDelegateLog(element);
925     [formDelegate(self) textFieldDidEndEditing:element inFrame:_frame];
926 }
927
928 - (void)textDidChangeInTextField:(DOMHTMLInputElement *)element
929 {
930     FormDelegateLog(element);
931     [formDelegate(self) textDidChangeInTextField:(DOMHTMLInputElement *)element inFrame:_frame];
932 }
933
934 - (void)textDidChangeInTextArea:(DOMHTMLTextAreaElement *)element
935 {
936     FormDelegateLog(element);
937     [formDelegate(self) textDidChangeInTextArea:element inFrame:_frame];
938 }
939
940 - (BOOL)textField:(DOMHTMLInputElement *)element doCommandBySelector:(SEL)commandSelector
941 {
942     FormDelegateLog(element);
943     return [formDelegate(self) textField:element doCommandBySelector:commandSelector inFrame:_frame];
944 }
945
946 - (BOOL)textField:(DOMHTMLInputElement *)element shouldHandleEvent:(NSEvent *)event
947 {
948     FormDelegateLog(element);
949     return [formDelegate(self) textField:element shouldHandleEvent:event inFrame:_frame];
950 }
951
952 - (void)setHasBorder:(BOOL)hasBorder
953 {
954     [[_frame frameView] _setHasBorder:hasBorder];
955 }
956
957 - (void)print
958 {
959     id wd = [[self webView] UIDelegate];    
960     if ([wd respondsToSelector:@selector(webView:printFrameView:)])
961         [wd webView:[self webView] printFrameView:[_frame frameView]];
962     else
963         [[WebDefaultUIDelegate sharedUIDelegate] webView:[self webView] printFrameView:[_frame frameView]];
964 }
965
966 - (jobject)getAppletInView:(NSView *)view
967 {
968     if ([view respondsToSelector:@selector(webPlugInGetApplet)])
969         return [view webPlugInGetApplet];
970     return [self pollForAppletInView:view];
971 }
972
973 // NOTE: pollForAppletInView: will block until the block is ready to use, or
974 // until a timeout is exceeded.  It will return nil if the timeout is
975 // exceeded.
976 // Deprecated, use getAppletInView:.
977 - (jobject)pollForAppletInView:(NSView *)view
978 {
979     if ([view respondsToSelector:@selector(pollForAppletInWindow:)])
980         // The Java VM needs the containing window of the view to
981         // initialize. The view may not yet be in the window's view 
982         // hierarchy, so we have to pass the window when requesting
983         // the applet.
984         return [view pollForAppletInWindow:[[self webView] window]];
985     return 0;
986 }
987
988 - (void)respondToChangedContents
989 {
990     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
991     if ([view isKindOfClass:[WebHTMLView class]])
992         [(WebHTMLView *)view _updateFontPanel];
993     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeNotification object:[self webView]];
994 }
995
996 - (void)respondToChangedSelection
997 {
998     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
999     if ([view isKindOfClass:[WebHTMLView class]])
1000         [(WebHTMLView *)view _selectionChanged];
1001     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeSelectionNotification object:[self webView]];
1002 }
1003
1004 - (NSUndoManager *)undoManager
1005 {
1006     return [[self webView] undoManager];
1007 }
1008
1009 - (void)issueCutCommand
1010 {
1011     NSView* documentView = [[_frame frameView] documentView];
1012     if ([documentView isKindOfClass:[WebHTMLView class]])
1013         [(WebHTMLView*)documentView cut:nil];
1014 }
1015
1016 - (void)issueCopyCommand
1017 {
1018     NSView* documentView = [[_frame frameView] documentView];
1019     if ([documentView isKindOfClass:[WebHTMLView class]])
1020         [(WebHTMLView*)documentView copy:nil];
1021 }
1022
1023 - (void)issuePasteCommand
1024 {
1025     NSView* documentView = [[_frame frameView] documentView];
1026     if ([documentView isKindOfClass:[WebHTMLView class]])
1027         [(WebHTMLView*)documentView paste:nil];
1028 }
1029
1030 - (void)issuePasteAndMatchStyleCommand
1031 {
1032     NSView <WebDocumentView> *documentView = [[_frame frameView] documentView];
1033     if ([documentView isKindOfClass:[WebHTMLView class]])
1034         [(WebHTMLView*)documentView pasteAsPlainText:nil];
1035 }
1036
1037 - (void)issueTransposeCommand
1038 {
1039     NSView <WebDocumentView> *view = [[_frame frameView] documentView];
1040     if ([view isKindOfClass:[WebHTMLView class]])
1041         [(WebHTMLView *)view transpose:nil];
1042 }
1043
1044 - (void)setIsSelected:(BOOL)isSelected forView:(NSView *)view
1045 {
1046     if ([view respondsToSelector:@selector(webPlugInSetIsSelected:)])
1047         [view webPlugInSetIsSelected:isSelected];
1048     else if ([view respondsToSelector:@selector(setIsSelected:)])
1049         [view setIsSelected:isSelected];
1050 }
1051
1052 - (NSString *)overrideMediaType
1053 {
1054     return [[self webView] mediaStyle];
1055 }
1056
1057 - (BOOL)isEditable
1058 {
1059     return [[self webView] isEditable];
1060 }
1061
1062 - (BOOL)shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(EAffinity)selectionAffinity stillSelecting:(BOOL)flag
1063 {
1064     return [[self webView] _shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:kit(selectionAffinity) stillSelecting:flag];
1065 }
1066
1067 - (BOOL)shouldDeleteSelectedDOMRange:(DOMRange *)range
1068 {
1069     WebView *webView = [self webView];
1070     return [[webView _editingDelegateForwarder] webView:webView shouldDeleteDOMRange:range];
1071 }
1072
1073 - (void)windowObjectCleared
1074 {
1075     WebView *wv = [self webView];
1076     [[wv _frameLoadDelegateForwarder] webView:wv windowScriptObjectAvailable:m_frame->windowScriptObject()];
1077     if ([wv scriptDebugDelegate] || [WebScriptDebugServer listenerCount]) {
1078         [_frame _detachScriptDebugger]; // FIXME: remove this once <rdar://problem/4608404> is fixed
1079         [_frame _attachScriptDebugger];
1080     }
1081 }
1082
1083 - (BOOL)_compareDashboardRegions:(NSDictionary *)regions
1084 {
1085     return [lastDashboardRegions isEqualToDictionary:regions];
1086 }
1087
1088 - (void)dashboardRegionsChanged:(NSMutableDictionary *)regions
1089 {
1090     WebView *wv = [self webView];
1091     id wd = [wv UIDelegate];
1092     
1093     [wv _addScrollerDashboardRegions:regions];
1094     
1095     if (![self _compareDashboardRegions:regions]) {
1096         if ([wd respondsToSelector:@selector(webView:dashboardRegionsChanged:)]) {
1097             [wd webView:wv dashboardRegionsChanged:regions];
1098             [lastDashboardRegions release];
1099             lastDashboardRegions = [regions retain];
1100         }
1101     }
1102 }
1103
1104 - (void)willPopupMenu:(NSMenu *)menu
1105 {
1106     WebView *wv = [self webView];
1107     id wd = [wv UIDelegate];
1108         
1109     if ([wd respondsToSelector:@selector(webView:willPopupMenu:)])
1110         [wd webView:wv willPopupMenu:menu];
1111 }
1112
1113 - (NSRect)customHighlightRect:(NSString*)type forLine:(NSRect)lineRect
1114 {
1115     ASSERT(_frame != nil);
1116     NSView *documentView = [[_frame frameView] documentView];
1117     if (![documentView isKindOfClass:[WebHTMLView class]])
1118         return NSZeroRect;
1119
1120     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
1121     id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
1122     return [highlighter highlightRectForLine:lineRect];
1123 }
1124
1125 - (void)paintCustomHighlight:(NSString*)type forBox:(NSRect)boxRect onLine:(NSRect)lineRect behindText:(BOOL)text
1126                   entireLine:(BOOL)line
1127 {
1128     ASSERT(_frame != nil);
1129     NSView *documentView = [[_frame frameView] documentView];
1130     if (![documentView isKindOfClass:[WebHTMLView class]])
1131         return;
1132
1133     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
1134     id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
1135     [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:text entireLine:line];
1136 }
1137
1138 - (NSString*)imageTitleForFilename:(NSString*)filename size:(NSSize)size
1139 {
1140     return [NSString stringWithFormat:UI_STRING("%@ %.0f×%.0f pixels", "window title for a standalone image (uses multiplication symbol, not x)"), filename, size.width, size.height];
1141 }
1142
1143 @end