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