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