WebKit:
[WebKit-https.git] / WebKit / WebView.subproj / WebView.m
1 /*      
2     WebView.m
3     Copyright 2001, 2002 Apple, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebViewInternal.h>
7
8 #import <WebKit/DOM.h>
9 #import <WebKit/DOMExtensions.h>
10 #import <WebKit/WebAssertions.h>
11 #import <WebKit/WebBackForwardList.h>
12 #import <WebKit/WebBaseNetscapePluginView.h>
13 #import <WebKit/WebBridge.h>
14 #import <WebKit/WebControllerSets.h>
15 #import <WebKit/WebDataProtocol.h>
16 #import <WebKit/WebDataSourcePrivate.h>
17 #import <WebKit/WebDefaultEditingDelegate.h>
18 #import <WebKit/WebDefaultFrameLoadDelegate.h>
19 #import <WebKit/WebDefaultPolicyDelegate.h>
20 #import <WebKit/WebDefaultResourceLoadDelegate.h>
21 #import <WebKit/WebDefaultUIDelegate.h>
22 #import <WebKit/WebDocument.h>
23 #import <WebKit/WebDocumentInternal.h>
24 #import <WebKit/WebDynamicScrollBarsView.h>
25 #import <WebKit/WebDownload.h>
26 #import <WebKit/WebEditingDelegate.h>
27 #import <WebKit/WebException.h>
28 #import <WebKit/WebFormDelegatePrivate.h>
29 #import <WebKit/WebFrameInternal.h>
30 #import <WebKit/WebFrameViewPrivate.h>
31 #import <WebKit/WebHistoryItemPrivate.h>
32 #import <WebKit/WebHTMLRepresentation.h>
33 #import <WebKit/WebHTMLView.h>
34 #import <WebKit/WebHTMLViewPrivate.h>
35 #import <WebKit/WebIconDatabase.h>
36 #import <WebKit/WebKitErrors.h>
37 #import <WebKit/WebKitLogging.h>
38 #import <WebKit/WebKitStatisticsPrivate.h>
39 #import <WebKit/WebNSPasteboardExtras.h>
40 #import "WebNSPrintOperationExtras.h"
41 #import <WebKit/WebNSURLExtras.h>
42 #import <WebKit/WebNSViewExtras.h>
43 #import <WebKit/WebPluginDatabase.h>
44 #import <WebKit/WebPolicyDelegate.h>
45 #import <WebKit/WebPreferencesPrivate.h>
46 #import <WebKit/WebResourceLoadDelegate.h>
47 #import <WebKit/WebTextView.h>
48 #import <WebKit/WebTextRepresentation.h>
49 #import <WebKit/WebTextRenderer.h>
50 #import <WebKit/WebUIDelegate.h>
51 #import <WebKit/WebUIDelegatePrivate.h>
52
53 #import <WebCore/WebCoreEncodings.h>
54 #import <WebCore/WebCoreSettings.h>
55
56 #import <Foundation/NSData_NSURLExtras.h>
57 #import <Foundation/NSDictionary_NSURLExtras.h>
58 #import <Foundation/NSString_NSURLExtras.h>
59 #import <Foundation/NSURLConnection.h>
60 #import <Foundation/NSURLDownloadPrivate.h>
61 #import <Foundation/NSURLFileTypeMappings.h>
62 #import <Foundation/NSURLRequestPrivate.h>
63 #import <Foundation/NSUserDefaults_NSURLExtras.h>
64
65 // Included to help work around this bug:
66 // <rdar://problem/3630640>: "Calling interpretKeyEvents: in a custom text view can fail to process keys right after app startup"
67 #import <AppKit/NSKeyBindingManager.h>
68
69 NSString *WebElementDOMNodeKey =            @"WebElementDOMNode";
70 NSString *WebElementFrameKey =              @"WebElementFrame";
71 NSString *WebElementImageKey =              @"WebElementImage";
72 NSString *WebElementImageAltStringKey =     @"WebElementImageAltString";
73 NSString *WebElementImageRectKey =          @"WebElementImageRect";
74 NSString *WebElementImageURLKey =           @"WebElementImageURL";
75 NSString *WebElementIsSelectedKey =         @"WebElementIsSelected";
76 NSString *WebElementLinkURLKey =            @"WebElementLinkURL";
77 NSString *WebElementLinkTargetFrameKey =    @"WebElementTargetFrame";
78 NSString *WebElementLinkLabelKey =          @"WebElementLinkLabel";
79 NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
80
81 NSString *WebViewProgressStartedNotification =          @"WebProgressStartedNotification";
82 NSString *WebViewProgressEstimateChangedNotification =  @"WebProgressEstimateChangedNotification";
83 NSString *WebViewProgressFinishedNotification =         @"WebProgressFinishedNotification";
84
85 NSString * const WebViewDidBeginEditingNotification =         @"WebViewDidBeginEditingNotification";
86 NSString * const WebViewDidChangeNotification =               @"WebViewDidChangeNotification";
87 NSString * const WebViewDidEndEditingNotification =           @"WebViewDidEndEditingNotification";
88 NSString * const WebViewDidChangeTypingStyleNotification =    @"WebViewDidChangeTypingStyleNotification";
89 NSString * const WebViewDidChangeSelectionNotification =      @"WebViewDidChangeSelectionNotification";
90
91 enum { WebViewVersion = 2 };
92
93 #define timedLayoutSize 4096
94
95 static NSMutableSet *schemesWithRepresentationsSet;
96
97 NSString *_WebCanGoBackKey =            @"canGoBack";
98 NSString *_WebCanGoForwardKey =         @"canGoForward";
99 NSString *_WebEstimatedProgressKey =    @"estimatedProgress";
100 NSString *_WebIsLoadingKey =            @"isLoading";
101 NSString *_WebMainFrameIconKey =        @"mainFrameIcon";
102 NSString *_WebMainFrameTitleKey =       @"mainFrameTitle";
103 NSString *_WebMainFrameURLKey =         @"mainFrameURL";
104
105 @interface WebProgressItem : NSObject
106 {
107 @public
108     long long bytesReceived;
109     long long estimatedLength;
110 }
111 @end
112
113 @implementation WebProgressItem
114 @end
115
116 @interface WebView (WebViewEditingInternal)
117 - (void)_alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity;
118 - (WebBridge *)_bridgeForCurrentSelection;
119 - (BOOL)_currentSelectionIsEditable;
120 @end
121
122
123 @implementation WebViewPrivate
124
125 - init 
126 {
127     backForwardList = [[WebBackForwardList alloc] init];
128     textSizeMultiplier = 1;
129     progressNotificationInterval = 0.02;
130     progressNotificationTimeInterval = 0.1;
131     settings = [[WebCoreSettings alloc] init];
132
133     return self;
134 }
135
136 - (void)dealloc
137 {
138     ASSERT(!mainFrame);
139     
140     [backForwardList release];
141     [applicationNameForUserAgent release];
142     [userAgent release];
143     
144     [preferences release];
145     [settings release];
146     [hostWindow release];
147     
148     [policyDelegateForwarder release];
149     [resourceProgressDelegateForwarder release];
150     [UIDelegateForwarder release];
151     [frameLoadDelegateForwarder release];
152     [editingDelegateForwarder release];
153     
154     [progressItems release];
155     
156     [draggedTypes release];
157     
158     [mediaStyle release];
159     
160     [super dealloc];
161 }
162
163 @end
164
165 @implementation WebView (WebPrivate)
166
167 + (NSArray *)_supportedMIMETypes
168 {
169     // Load the plug-in DB allowing plug-ins to install types.
170     [WebPluginDatabase installedPlugins];
171     return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
172 }
173
174 + (NSArray *)_supportedFileExtensions
175 {
176     NSMutableSet *extensions = [[NSMutableSet alloc] init];
177     NSArray *MIMETypes = [self _supportedMIMETypes];
178     NSEnumerator *enumerator = [MIMETypes objectEnumerator];
179     NSString *MIMEType;
180     NSURLFileTypeMappings *mappings = [NSURLFileTypeMappings sharedMappings];
181     while ((MIMEType = [enumerator nextObject]) != nil) {
182         NSArray *extensionsForType = [mappings extensionsForMIMEType:MIMEType];
183         if (extensionsForType) {
184             [extensions addObjectsFromArray:extensionsForType];
185         }
186     }
187     NSArray *uniqueExtensions = [extensions allObjects];
188     [extensions release];
189     return uniqueExtensions;
190 }
191
192 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
193 {
194     MIMEType = [MIMEType lowercaseString];
195     Class viewClass;
196     Class repClass;
197     
198     // Simple optimization that avoids loading the plug-in DB and image types for the HTML case.
199     if ([self canShowMIMETypeAsHTML:MIMEType]) {
200         viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _web_objectForMIMEType:MIMEType];
201         repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _web_objectForMIMEType:MIMEType];
202         if (viewClass && repClass) {
203             if (vClass) {
204                 *vClass = viewClass;
205             }
206             if (rClass) {
207                 *rClass = repClass;
208             }
209             return YES;
210         }
211     }
212     
213     // Load the plug-in DB allowing plug-ins to install types.
214     [[WebPluginDatabase installedPlugins] loadPluginIfNeededForMIMEType:MIMEType];
215     
216     // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
217     viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _web_objectForMIMEType:MIMEType];
218     repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _web_objectForMIMEType:MIMEType];
219     if (viewClass && repClass) {
220         // Special-case WebTextView for text types that shouldn't be shown.
221         if (viewClass == [WebTextView class] &&
222             repClass == [WebTextRepresentation class] &&
223             [[WebTextView unsupportedTextMIMETypes] containsObject:MIMEType]) {
224             return NO;
225         }
226         if (vClass) {
227             *vClass = viewClass;
228         }
229         if (rClass) {
230             *rClass = repClass;
231         }
232         return YES;
233     }
234     
235     return NO;
236 }
237
238 + (void)_setAlwaysUseATSU:(BOOL)f
239 {
240     [WebTextRenderer _setAlwaysUseATSU:f];
241 }
242
243 + (BOOL)canShowFile:(NSString *)path
244 {
245     return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
246 }
247
248 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
249 {
250     return [[NSURLFileTypeMappings sharedMappings] preferredExtensionForMIMEType:type];
251 }
252
253 - (void)_close
254 {
255     if (_private->setName != nil) {
256         [WebViewSets removeWebView:self fromSetNamed:_private->setName];
257         [_private->setName release];
258         _private->setName = nil;
259     }
260
261     [_private->mainFrame _detachFromParent];
262     [_private->mainFrame release];
263     _private->mainFrame = nil;
264     
265     // Clear the page cache so we call destroy on all the plug-ins in the page cache to break any retain cycles.
266     // See comment in [WebHistoryItem _releaseAllPendingPageCaches] for more information.
267     [_private->backForwardList _clearPageCache];
268 }
269
270 - (WebFrame *)_createFrameNamed:(NSString *)fname inParent:(WebFrame *)parent allowsScrolling:(BOOL)allowsScrolling
271 {
272     WebFrameView *childView = [[WebFrameView alloc] initWithFrame:NSMakeRect(0,0,0,0)];
273
274     [childView _setWebView:self];
275     [childView setAllowsScrolling:allowsScrolling];
276     
277     WebFrame *newFrame = [[WebFrame alloc] initWithName:fname webFrameView:childView webView:self];
278
279     [childView release];
280
281     [parent _addChild:newFrame];
282     
283     [newFrame release];
284         
285     return newFrame;
286 }
287
288 - (void)_finishedLoadingResourceFromDataSource: (WebDataSource *)dataSource
289 {
290     WebFrame *frame = [dataSource webFrame];
291     
292     ASSERT(dataSource != nil);
293     
294     // This resource has completed, so check if the load is complete for all frames.
295     if (frame != nil) {
296         [frame _transitionToLayoutAcceptable];
297         [frame _checkLoadComplete];
298     }
299 }
300
301 - (void)_mainReceivedBytesSoFar: (unsigned)bytesSoFar fromDataSource: (WebDataSource *)dataSource complete: (BOOL)isComplete
302 {
303     WebFrame *frame = [dataSource webFrame];
304     
305     ASSERT(dataSource != nil);
306
307     // The frame may be nil if a previously cancelled load is still making progress callbacks.
308     if (frame == nil)
309         return;
310         
311     // This resource has completed, so check if the load is complete for all frames.
312     if (isComplete){
313         // If the load is complete, mark the primary load as done.  The primary load is the load
314         // of the main document.  Other resources may still be arriving.
315         [dataSource _setPrimaryLoadComplete: YES];
316         [frame _checkLoadComplete];
317     }
318     else {
319         // If the frame isn't complete it might be ready for a layout.  Perform that check here.
320         // Note that transitioning a frame to this state doesn't guarantee a layout, rather it
321         // just indicates that an early layout can be performed.
322         if ((int)bytesSoFar > timedLayoutSize)
323             [frame _transitionToLayoutAcceptable];
324     }
325 }
326
327 - (void)_receivedError: (NSError *)error fromDataSource: (WebDataSource *)dataSource
328 {
329     WebFrame *frame = [dataSource webFrame];
330
331     [frame _checkLoadComplete];
332 }
333
334
335 - (void)_mainReceivedError:(NSError *)error fromDataSource:(WebDataSource *)dataSource complete:(BOOL)isComplete
336 {
337     ASSERT(dataSource);
338 #ifndef NDEBUG
339     ASSERT([dataSource webFrame]);
340 #endif
341     
342     [dataSource _setMainDocumentError: error];
343
344     if (isComplete) {
345         [dataSource _setPrimaryLoadComplete:YES];
346         [[dataSource webFrame] _checkLoadComplete];
347     }
348 }
349
350 + (NSString *)_MIMETypeForFile:(NSString *)path
351 {
352     NSString *extension = [path pathExtension];
353     NSString *MIMEType = nil;
354
355     // FIXME: This is a workaround to make web archive files work with Foundations that
356     // are too old to know about web archive files. We should remove this before we ship.
357     if ([extension  _web_isCaseInsensitiveEqualToString:@"webarchive"]) {
358         return @"application/x-webarchive";
359     }
360     
361     // Get the MIME type from the extension.
362     if ([extension length] != 0) {
363         MIMEType = [[NSURLFileTypeMappings sharedMappings] MIMETypeForExtension:extension];
364     }
365
366     // If we can't get a known MIME type from the extension, sniff.
367     if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
368         NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
369         NSData *data = [handle readDataOfLength:GUESS_MIME_TYPE_PEEK_LENGTH];
370         [handle closeFile];
371         if ([data length] != 0) {
372             MIMEType = [data _web_guessedMIMEType];
373         }
374         if ([MIMEType length] == 0) {
375             MIMEType = @"application/octet-stream";
376         }
377     }
378
379     return MIMEType;
380 }
381
382 - (void)_downloadURL:(NSURL *)URL
383 {
384     [self _downloadURL:URL toDirectory:nil];
385 }
386
387 - (void)_downloadURL:(NSURL *)URL toDirectory:(NSString *)directory
388 {
389     ASSERT(URL);
390     
391     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
392     [WebDownload _downloadWithRequest:request
393                              delegate:_private->downloadDelegate
394                             directory:[directory isAbsolutePath] ? directory : nil];
395     [request release];
396 }
397
398 - (BOOL)defersCallbacks
399 {
400     return _private->defersCallbacks;
401 }
402
403 - (void)setDefersCallbacks:(BOOL)defers
404 {
405     if (defers == _private->defersCallbacks) {
406         return;
407     }
408
409     _private->defersCallbacks = defers;
410     [_private->mainFrame _defersCallbacksChanged];
411 }
412
413 - (void)_setTopLevelFrameName:(NSString *)name
414 {
415     [[self mainFrame] _setName:name];
416 }
417
418 - (WebFrame *)_findFrameInThisWindowNamed: (NSString *)name
419 {
420     return [[self mainFrame] _descendantFrameNamed:name];
421 }
422
423 - (WebFrame *)_findFrameNamed:(NSString *)name
424 {
425     // Try this WebView first.
426     WebFrame *frame = [self _findFrameInThisWindowNamed:name];
427
428     if (frame != nil) {
429         return frame;
430     }
431
432     // Try other WebViews in the same set
433     if (_private->setName != nil) {
434         NSEnumerator *enumerator = [WebViewSets webViewsInSetNamed:_private->setName];
435         WebView *webView;
436         while ((webView = [enumerator nextObject]) != nil && frame == nil) {
437             frame = [webView _findFrameInThisWindowNamed:name];
438         }
439     }
440
441     return frame;
442 }
443
444 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
445 {
446     id wd = [self UIDelegate];
447     WebView *newWindowWebView = nil;
448     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
449         newWindowWebView = [wd webView:self createWebViewWithRequest:request];
450     else {
451         newWindowWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:self createWebViewWithRequest: request];
452     }
453
454     [[newWindowWebView _UIDelegateForwarder] webViewShow: newWindowWebView];
455
456     return newWindowWebView;
457 }
458
459 - (NSMenu *)_menuForElement:(NSDictionary *)element
460 {
461     NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate]
462           webView:self contextMenuItemsForElement:element defaultMenuItems:nil];
463     NSArray *menuItems = defaultMenuItems;
464     NSMenu *menu = nil;
465     unsigned i;
466
467     if (_private->UIDelegate) {
468         id cd = _private->UIDelegate;
469         
470         if ([cd respondsToSelector:@selector(webView:contextMenuItemsForElement:defaultMenuItems:)])
471             menuItems = [cd webView:self contextMenuItemsForElement:element defaultMenuItems:defaultMenuItems];
472     } 
473
474     if (menuItems && [menuItems count] > 0) {
475         menu = [[[NSMenu alloc] init] autorelease];
476
477         for (i=0; i<[menuItems count]; i++) {
478             [menu addItem:[menuItems objectAtIndex:i]];
479         }
480     }
481
482     return menu;
483 }
484
485 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(unsigned)modifierFlags
486 {
487     // When the mouse isn't over this view at all, we'll get called with a dictionary of nil over
488     // and over again. So it's a good idea to catch that here and not send multiple calls to the delegate
489     // for that case.
490     
491     if (dictionary && _private->lastElementWasNonNil) {
492         [[self _UIDelegateForwarder] webView:self mouseDidMoveOverElement:dictionary modifierFlags:modifierFlags];
493     }
494     _private->lastElementWasNonNil = dictionary != nil;
495 }
496
497 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
498 {
499     // We never go back/forward on a per-frame basis, so the target must be the main frame
500     //ASSERT([item target] == nil || [self _findFrameNamed:[item target]] == [self mainFrame]);
501
502     // abort any current load if we're going back/forward
503     [[self mainFrame] stopLoading];
504     [[self mainFrame] _goToItem:item withLoadType:type];
505 }
506
507 // Not used now, but could be if we ever store frames in bookmarks or history
508 - (void)_loadItem:(WebHistoryItem *)item
509 {
510     WebHistoryItem *newItem = [item copy];      // Makes a deep copy, happily
511     [[self backForwardList] addItem:newItem];
512     [self _goToItem:newItem withLoadType:WebFrameLoadTypeIndexedBackForward];
513 }
514
515 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
516 {
517     // It turns out the right combination of behavior is done with the back/forward load
518     // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
519     // in the back forward list, and go to the current one.
520
521     WebBackForwardList *bfList = [self backForwardList];
522     ASSERT(![bfList currentItem]);      // destination list should be empty
523
524     WebBackForwardList *otherBFList = [otherView backForwardList];
525     if (![otherBFList currentItem]) {
526         return;         // empty back forward list, bail
527     }
528
529     WebHistoryItem *newItemToGoTo = nil;
530     int lastItemIndex = [otherBFList forwardListCount];
531     int i;
532     for (i = -[otherBFList backListCount]; i <= lastItemIndex; i++) {
533         if (i == 0) {
534             // If this item is showing , save away its current scroll and form state,
535             // since that might have changed since loading and it is normally not saved
536             // until we leave that page.
537             [[otherView mainFrame] _saveDocumentAndScrollState];
538         }
539         WebHistoryItem *newItem = [[otherBFList itemAtIndex:i] copy];
540         [bfList addItem:newItem];
541         if (i == 0) {
542             newItemToGoTo = newItem;
543         }
544     }
545     
546     [self _goToItem:newItemToGoTo withLoadType:WebFrameLoadTypeIndexedBackForward];
547 }
548
549 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
550 {
551     _private->formDelegate = delegate;
552 }
553
554 - (id<WebFormDelegate>)_formDelegate
555 {
556     if (!_private->formDelegate) {
557         // create lazily, to give the client a chance to set one before we bother to alloc the shared one
558         _private->formDelegate = [WebFormDelegate _sharedWebFormDelegate];
559     }
560     return _private->formDelegate;
561 }
562
563 - (WebCoreSettings *)_settings
564 {
565     return _private->settings;
566 }
567
568 - (void)_updateWebCoreSettingsFromPreferences: (WebPreferences *)preferences
569 {
570     [_private->settings setCursiveFontFamily:[preferences cursiveFontFamily]];
571     [_private->settings setDefaultFixedFontSize:[preferences defaultFixedFontSize]];
572     [_private->settings setDefaultFontSize:[preferences defaultFontSize]];
573     [_private->settings setDefaultTextEncoding:[preferences defaultTextEncodingName]];
574     [_private->settings setFantasyFontFamily:[preferences fantasyFontFamily]];
575     [_private->settings setFixedFontFamily:[preferences fixedFontFamily]];
576     [_private->settings setJavaEnabled:[preferences isJavaEnabled]];
577     [_private->settings setJavaScriptEnabled:[preferences isJavaScriptEnabled]];
578     [_private->settings setJavaScriptCanOpenWindowsAutomatically:[preferences javaScriptCanOpenWindowsAutomatically]];
579     [_private->settings setMinimumFontSize:[preferences minimumFontSize]];
580     [_private->settings setMinimumLogicalFontSize:[preferences minimumLogicalFontSize]];
581     [_private->settings setPluginsEnabled:[preferences arePlugInsEnabled]];
582     [_private->settings setSansSerifFontFamily:[preferences sansSerifFontFamily]];
583     [_private->settings setSerifFontFamily:[preferences serifFontFamily]];
584     [_private->settings setStandardFontFamily:[preferences standardFontFamily]];
585     [_private->settings setWillLoadImagesAutomatically:[preferences loadsImagesAutomatically]];
586
587     if ([preferences userStyleSheetEnabled]) {
588         [_private->settings setUserStyleSheetLocation:[[preferences userStyleSheetLocation] _web_originalDataAsString]];
589     } else {
590         [_private->settings setUserStyleSheetLocation:@""];
591     }
592     [_private->settings setShouldPrintBackgrounds:[preferences shouldPrintBackgrounds]];
593 }
594
595 - (void)_preferencesChangedNotification: (NSNotification *)notification
596 {
597     WebPreferences *preferences = (WebPreferences *)[notification object];
598     
599     ASSERT(preferences == [self preferences]);
600     if (!_private->userAgentOverridden) {
601         [_private->userAgent release];
602         _private->userAgent = nil;
603     }
604     [self _updateWebCoreSettingsFromPreferences: preferences];
605 }
606
607 - _frameLoadDelegateForwarder
608 {
609     if (!_private->frameLoadDelegateForwarder)
610         _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self frameLoadDelegate]  defaultTarget: [WebDefaultFrameLoadDelegate sharedFrameLoadDelegate] templateClass: [WebDefaultFrameLoadDelegate class]];
611     return _private->frameLoadDelegateForwarder;
612 }
613
614 - _resourceLoadDelegateForwarder
615 {
616     if (!_private->resourceProgressDelegateForwarder)
617         _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
618     return _private->resourceProgressDelegateForwarder;
619 }
620
621 - (void)_cacheResourceLoadDelegateImplementations
622 {
623     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:)])
624         _private->resourceLoadDelegateImplementations.delegateImplementsDidCancelAuthenticationChallenge = YES;
625
626     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)])
627         _private->resourceLoadDelegateImplementations.delegateImplementsDidReceiveAuthenticationChallenge = YES;
628
629     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)])
630         _private->resourceLoadDelegateImplementations.delegateImplementsDidFinishLoadingFromDataSource = YES;
631     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)])
632         _private->resourceLoadDelegateImplementations.delegateImplementsDidReceiveContentLength = YES;
633     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)])
634         _private->resourceLoadDelegateImplementations.delegateImplementsDidReceiveResponse = YES;
635     if ([[self resourceLoadDelegate] respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)])
636         _private->resourceLoadDelegateImplementations.delegateImplementsWillSendRequest = YES;
637     if ([[self resourceLoadDelegate] respondsToSelector: @selector(webView:identifierForInitialRequest:fromDataSource:)])
638         _private->resourceLoadDelegateImplementations.delegateImplementsIdentifierForRequest = YES;
639 }
640
641 - (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
642 {
643     return _private->resourceLoadDelegateImplementations;
644 }
645
646 - _policyDelegateForwarder
647 {
648     if (!_private->policyDelegateForwarder)
649         _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
650     return _private->policyDelegateForwarder;
651 }
652
653 - _UIDelegateForwarder
654 {
655     if (!_private->UIDelegateForwarder)
656         _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self UIDelegate] defaultTarget: [WebDefaultUIDelegate sharedUIDelegate] templateClass: [WebDefaultUIDelegate class]];
657     return _private->UIDelegateForwarder;
658 }
659
660 - _editingDelegateForwarder
661 {
662     if (!_private->editingDelegateForwarder)
663         _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self editingDelegate] defaultTarget: [WebDefaultEditingDelegate sharedEditingDelegate] templateClass: [WebDefaultEditingDelegate class]];
664     return _private->editingDelegateForwarder;
665 }
666
667
668 - (WebFrame *)_frameForDataSource: (WebDataSource *)dataSource fromFrame: (WebFrame *)frame
669 {
670     NSArray *frames;
671     int i, count;
672     WebFrame *result, *aFrame;
673
674     if ([frame dataSource] == dataSource)
675         return frame;
676
677     if ([frame provisionalDataSource] == dataSource)
678         return frame;
679
680     // It's safe to use the internal version because we know this
681     // function will not change the set of frames
682     frames = [frame _internalChildFrames];
683     count = [frames count];
684     for (i = 0; i < count; i++){
685         aFrame = [frames objectAtIndex: i];
686         result = [self _frameForDataSource: dataSource fromFrame: aFrame];
687         if (result)
688             return result;
689     }
690
691     return nil;
692 }
693
694
695 - (WebFrame *)_frameForDataSource: (WebDataSource *)dataSource
696 {
697     WebFrame *frame = [self mainFrame];
698
699     return [self _frameForDataSource: dataSource fromFrame: frame];
700 }
701
702
703 - (WebFrame *)_frameForView: (WebFrameView *)aView fromFrame: (WebFrame *)frame
704 {
705     NSArray *frames;
706     int i, count;
707     WebFrame *result, *aFrame;
708
709     if ([frame frameView] == aView)
710         return frame;
711
712     // It's safe to use the internal version because we know this
713     // function will not change the set of frames
714     frames = [frame _internalChildFrames];
715     count = [frames count];
716     for (i = 0; i < count; i++){
717         aFrame = [frames objectAtIndex: i];
718         result = [self _frameForView: aView fromFrame: aFrame];
719         if (result)
720             return result;
721     }
722
723     return nil;
724 }
725
726 - (WebFrame *)_frameForView: (WebFrameView *)aView
727 {
728     WebFrame *frame = [self mainFrame];
729
730     return [self _frameForView: aView fromFrame: frame];
731 }
732
733 - (void)_setDraggedTypes:(NSArray *)draggedTypes
734 {
735     [draggedTypes retain];
736     [_private->draggedTypes release];
737     _private->draggedTypes = draggedTypes;
738 }
739
740 - (void)unregisterDraggedTypes
741 {
742     [self _setDraggedTypes:nil];
743     [super unregisterDraggedTypes];
744 }
745
746 - (void)registerForDraggedTypes:(NSArray *)draggedTypes
747 {
748     [self _setDraggedTypes:draggedTypes];
749     [super registerForDraggedTypes:draggedTypes];
750 }
751
752 - (void)_registerDraggedTypes
753 {
754     [self registerForDraggedTypes:[NSPasteboard _web_dragTypesForURL]];
755 }
756
757 - (void)_closeWindow
758 {
759     [[self _UIDelegateForwarder] webViewClose:self];
760 }
761
762 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
763 {
764     [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
765     [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
766 }
767
768 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
769 {
770     NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
771     [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
772
773     // This is used to make _representationExistsForURLScheme faster.
774     // Without this set, we'd have to create the MIME type each time.
775     if (schemesWithRepresentationsSet == nil) {
776         schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
777     }
778     [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
779 }
780
781 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
782 {
783     return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
784 }
785
786 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
787 {
788     return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
789 }
790
791 + (BOOL)_canHandleRequest:(NSURLRequest *)request
792 {
793     if ([NSURLConnection canHandleRequest:request]) {
794         return YES;
795     }
796     
797     // We're always willing to load alternate content for unreachable URLs
798     if ([request _webDataRequestUnreachableURL]) {
799         return YES;
800     }
801
802     return [self _representationExistsForURLScheme:[[request URL] scheme]];
803 }
804
805 + (NSString *)_decodeData:(NSData *)data
806 {
807     return [WebCoreEncodings decodeData:data];
808 }
809
810 - (void)_pushPerformingProgrammaticFocus
811 {
812     _private->programmaticFocusCount++;
813 }
814
815 - (void)_popPerformingProgrammaticFocus
816 {
817     _private->programmaticFocusCount--;
818 }
819
820 - (BOOL)_isPerformingProgrammaticFocus
821 {
822     return _private->programmaticFocusCount != 0;
823 }
824
825 #define UnknownTotalBytes -1
826 #define WebProgressItemDefaultEstimatedLength 1024*16
827
828 - (void)_didChangeValueForKey: (NSString *)key
829 {
830     LOG (Bindings, "calling didChangeValueForKey: %@", key);
831     [self didChangeValueForKey: key];
832 }
833
834 - (void)_willChangeValueForKey: (NSString *)key
835 {
836     LOG (Bindings, "calling willChangeValueForKey: %@", key);
837     [self willChangeValueForKey: key];
838 }
839
840 // Always start progress at INITIAL_PROGRESS_VALUE so it appears progress indicators
841 // will immediately show some progress.  This helps provide feedback as soon as a load
842 // starts.
843 #define INITIAL_PROGRESS_VALUE 0.1
844
845 - (void)_resetProgress
846 {
847     [_private->progressItems release];
848     _private->progressItems = nil;
849     _private->totalPageAndResourceBytesToLoad = 0;
850     _private->totalBytesReceived = 0;
851     _private->progressValue = 0;
852     _private->lastNotifiedProgressValue = 0;
853     _private->lastNotifiedProgressTime = 0;
854     _private->finalProgressChangedSent = NO;
855     _private->numProgressTrackedFrames = 0;
856     [_private->orginatingProgressFrame release];
857     _private->orginatingProgressFrame = nil;
858 }
859 - (void)_progressStarted:(WebFrame *)frame
860 {
861     LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
862     [self _willChangeValueForKey: @"estimatedProgress"];
863     if (_private->numProgressTrackedFrames == 0 || _private->orginatingProgressFrame == frame){
864         [self _resetProgress];
865         _private->progressValue = INITIAL_PROGRESS_VALUE;
866         _private->orginatingProgressFrame = [frame retain];
867         [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:self];
868     }
869     _private->numProgressTrackedFrames++;
870     [self _didChangeValueForKey: @"estimatedProgress"];
871 }
872
873 - (void)_finalProgressComplete
874 {
875     LOG (Progress, "");
876
877     // Before resetting progress value be sure to send client a least one notification
878     // with final progress value.
879     if (!_private->finalProgressChangedSent) {
880         _private->progressValue = 1;
881         [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
882     }
883     
884     [self _resetProgress];
885     
886     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:self];
887 }
888
889 - (void)_progressCompleted:(WebFrame *)frame
890 {    
891     LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
892
893     if (_private->numProgressTrackedFrames <= 0)
894         return;
895
896     [self _willChangeValueForKey: @"estimatedProgress"];
897
898     _private->numProgressTrackedFrames--;
899     if (_private->numProgressTrackedFrames == 0 ||
900         (frame == _private->orginatingProgressFrame && _private->numProgressTrackedFrames != 0)){
901         [self _finalProgressComplete];
902     }
903     [self _didChangeValueForKey: @"estimatedProgress"];
904 }
905
906 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate response:(NSURLResponse *)response;
907 {
908     if (!connectionDelegate)
909         return;
910
911     LOG (Progress, "_private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
912     
913     if (_private->numProgressTrackedFrames <= 0)
914         return;
915         
916     WebProgressItem *item = [[WebProgressItem alloc] init];
917
918     if (!item)
919         return;
920
921     long long length = [response expectedContentLength];
922     if (length < 0){
923         length = WebProgressItemDefaultEstimatedLength;
924     }
925     item->estimatedLength = length;
926     _private->totalPageAndResourceBytesToLoad += length;
927     
928     if (!_private->progressItems)
929         _private->progressItems = [[NSMutableDictionary alloc] init];
930         
931     [_private->progressItems _web_setObject:item forUncopiedKey:connectionDelegate];
932     [item release];
933 }
934
935 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate data:(NSData *)data
936 {
937     if (!connectionDelegate)
938         return;
939
940     WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
941
942     if (!item)
943         return;
944
945     [self _willChangeValueForKey: @"estimatedProgress"];
946
947     unsigned bytesReceived = [data length];
948     double increment = 0, percentOfRemainingBytes;
949     long long remainingBytes, estimatedBytesForPendingRequests;
950
951     item->bytesReceived += bytesReceived;
952     if (item->bytesReceived > item->estimatedLength){
953         _private->totalPageAndResourceBytesToLoad += ((item->bytesReceived*2) - item->estimatedLength);
954         item->estimatedLength = item->bytesReceived*2;
955     }
956     
957     int numPendingOrLoadingRequests = [[self mainFrame] _numPendingOrLoadingRequests:YES];
958     estimatedBytesForPendingRequests = WebProgressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
959     remainingBytes = ((_private->totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - _private->totalBytesReceived);
960     percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
961     increment = (1.0 - _private->progressValue) * percentOfRemainingBytes;
962     
963     _private->totalBytesReceived += bytesReceived;
964     
965     _private->progressValue += increment;
966
967     if (_private->progressValue < 0.0)
968         _private->progressValue = 0.0;
969
970     if (_private->progressValue > 1.0)
971         _private->progressValue = 1.0;
972
973     double now = CFAbsoluteTimeGetCurrent();
974     double notifiedProgressTimeDelta = CFAbsoluteTimeGetCurrent() - _private->lastNotifiedProgressTime;
975     _private->lastNotifiedProgressTime = now;
976     
977     LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
978     double notificationProgressDelta = _private->progressValue - _private->lastNotifiedProgressValue;
979     if ((notificationProgressDelta >= _private->progressNotificationInterval ||
980             notifiedProgressTimeDelta >= _private->progressNotificationTimeInterval) &&
981             _private->numProgressTrackedFrames > 0) {
982         if (!_private->finalProgressChangedSent) {
983             if (_private->progressValue == 1)
984                 _private->finalProgressChangedSent = YES;
985             [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
986             _private->lastNotifiedProgressValue = _private->progressValue;
987         }
988     }
989
990     [self _didChangeValueForKey: @"estimatedProgress"];
991 }
992
993 - (void)_completeProgressForConnectionDelegate:(id)connectionDelegate
994 {
995     WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
996
997     if (!item)
998         return;
999         
1000     // Adjust the total expected bytes to account for any overage/underage.
1001     long long delta = item->bytesReceived - item->estimatedLength;
1002     _private->totalPageAndResourceBytesToLoad += delta;
1003     item->estimatedLength = item->bytesReceived;
1004 }
1005
1006 // Required to prevent automatic observer notifications.
1007 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1008     return NO;
1009 }
1010
1011 - (NSArray *)_declaredKeys {
1012     static NSArray *declaredKeys = nil;
1013     
1014     if (!declaredKeys) {
1015         declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, nil];
1016     }
1017
1018     return declaredKeys;
1019 }
1020
1021 - (void)setObservationInfo:(void *)info
1022 {
1023     _private->observationInfo = info;
1024 }
1025
1026 - (void *)observationInfo
1027 {
1028     return _private->observationInfo;
1029 }
1030
1031 - (void)_willChangeBackForwardKeys
1032 {
1033     [self _willChangeValueForKey: _WebCanGoBackKey];
1034     [self _willChangeValueForKey: _WebCanGoForwardKey];
1035 }
1036
1037 - (void)_didChangeBackForwardKeys
1038 {
1039     [self _didChangeValueForKey: _WebCanGoBackKey];
1040     [self _didChangeValueForKey: _WebCanGoForwardKey];
1041 }
1042
1043 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1044 {
1045     [self _willChangeBackForwardKeys];
1046     if (frame == [self mainFrame]){
1047         // Force an observer update by sending a will/did.
1048         [self _willChangeValueForKey: _WebIsLoadingKey];
1049         [self _didChangeValueForKey: _WebIsLoadingKey];
1050
1051         [self _willChangeValueForKey: _WebMainFrameURLKey];
1052     }
1053     [NSApp setWindowsNeedUpdate:YES];
1054 }
1055
1056 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1057 {
1058     if (frame == [self mainFrame]){
1059         [self _didChangeValueForKey: _WebMainFrameURLKey];
1060     }
1061     [NSApp setWindowsNeedUpdate:YES];
1062 }
1063
1064 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1065 {
1066     [self _didChangeBackForwardKeys];
1067     if (frame == [self mainFrame]){
1068         // Force an observer update by sending a will/did.
1069         [self _willChangeValueForKey: _WebIsLoadingKey];
1070         [self _didChangeValueForKey: _WebIsLoadingKey];
1071     }
1072     [NSApp setWindowsNeedUpdate:YES];
1073 }
1074
1075 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1076 {
1077     [self _didChangeBackForwardKeys];
1078     if (frame == [self mainFrame]){
1079         // Force an observer update by sending a will/did.
1080         [self _willChangeValueForKey: _WebIsLoadingKey];
1081         [self _didChangeValueForKey: _WebIsLoadingKey];
1082     }
1083     [NSApp setWindowsNeedUpdate:YES];
1084 }
1085
1086 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1087 {
1088     [self _didChangeBackForwardKeys];
1089     if (frame == [self mainFrame]){
1090         // Force an observer update by sending a will/did.
1091         [self _willChangeValueForKey: _WebIsLoadingKey];
1092         [self _didChangeValueForKey: _WebIsLoadingKey];
1093         
1094         [self _didChangeValueForKey: _WebMainFrameURLKey];
1095     }
1096     [NSApp setWindowsNeedUpdate:YES];
1097 }
1098
1099 - (void)_reloadForPluginChanges
1100 {
1101     [[self mainFrame] _reloadForPluginChanges];
1102 }
1103
1104 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1105 {
1106     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1107     [request setHTTPUserAgent:[self userAgentForURL:URL]];
1108     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1109     [request release];
1110     return cachedResponse;
1111 }
1112
1113 - (void)_writeImageElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1114 {
1115     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1116     [pasteboard _web_writeImage:[element objectForKey:WebElementImageKey] 
1117                             URL:linkURL ? linkURL : [element objectForKey:WebElementImageURLKey]
1118                           title:[element objectForKey:WebElementImageAltStringKey] 
1119                         archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1120                           types:types];
1121 }
1122
1123 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1124 {
1125     [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1126                      andTitle:[element objectForKey:WebElementLinkLabelKey]
1127                         types:types];
1128 }
1129
1130 @end
1131
1132
1133 @implementation _WebSafeForwarder
1134
1135 - initWithTarget: t defaultTarget: dt templateClass: (Class)aClass
1136 {
1137     [super init];
1138     target = t;         // Non retained.
1139     defaultTarget = dt;
1140     templateClass = aClass;
1141     return self;
1142 }
1143
1144
1145 // Used to send messages to delegates that implement informal protocols.
1146 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
1147 {
1148     return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
1149 }
1150
1151 #ifndef NDEBUG
1152 NSMutableDictionary *countInvocations;
1153 #endif
1154
1155 - (void)forwardInvocation:(NSInvocation *)anInvocation
1156 {
1157 #ifndef NDEBUG
1158     if (!countInvocations){
1159         countInvocations = [[NSMutableDictionary alloc] init];
1160     }
1161     NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
1162     if (!count)
1163         count = [NSNumber numberWithInt: 1];
1164     else
1165         count = [NSNumber numberWithInt: [count intValue] + 1];
1166     [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
1167 #endif
1168     if ([target respondsToSelector: [anInvocation selector]])
1169         [anInvocation invokeWithTarget: target];
1170     else if ([defaultTarget respondsToSelector: [anInvocation selector]])
1171         [anInvocation invokeWithTarget: defaultTarget];
1172     // Do nothing quietly if method not implemented.
1173 }
1174
1175 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1176 {
1177     return [templateClass instanceMethodSignatureForSelector: aSelector];
1178 }
1179
1180 @end
1181
1182 @implementation WebView
1183
1184 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1185 {
1186     return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1187 }
1188
1189 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1190 {
1191     return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1192 }
1193
1194 + (NSArray *)MIMETypesShownAsHTML
1195 {
1196     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1197     NSEnumerator *enumerator = [viewTypes keyEnumerator];
1198     id key;
1199     NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1200     
1201     while ((key = [enumerator nextObject])) {
1202         if ([viewTypes objectForKey:key] == [WebHTMLView class]) {
1203             [array addObject:key];
1204         }
1205     }
1206     
1207     return array;
1208 }
1209
1210 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1211 {
1212     NSEnumerator *enumerator;
1213     id key;
1214     
1215     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1216     enumerator = [viewTypes keyEnumerator];
1217     while ((key = [enumerator nextObject])) {
1218         if ([viewTypes objectForKey:key] == [WebHTMLView class]) {
1219             [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1220         }
1221     }
1222     
1223     int i, count = [MIMETypes count];
1224     for (i = 0; i < count; i++) {
1225         [WebView registerViewClass:[WebHTMLView class] 
1226                 representationClass:[WebHTMLRepresentation class] 
1227                 forMIMEType:[MIMETypes objectAtIndex:i]];
1228     }
1229 }
1230
1231 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1232 {
1233     ERROR("unimplemented");
1234     return nil;
1235 }
1236
1237 + (NSURL *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1238 {
1239     ERROR("unimplemented");
1240     return nil;
1241 }
1242
1243 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1244 {
1245     _private->drawsBackground = YES;
1246
1247     NSRect f = [self frame];
1248     WebFrameView *wv = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1249     [wv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
1250     [self addSubview: wv];
1251     [wv release];
1252
1253     _private->mainFrame = [[WebFrame alloc] initWithName: frameName webFrameView: wv  webView: self];
1254     [self setGroupName:groupName];
1255     
1256     // If there's already a next key view (e.g., from a nib), wire it up to our
1257     // contained frame view. In any case, wire our next key view up to the our
1258     // contained frame view. This works together with our becomeFirstResponder 
1259     // and setNextKeyView overrides.
1260     NSView *nextKeyView = [self nextKeyView];
1261     if (nextKeyView != nil && nextKeyView != wv) {
1262         [wv setNextKeyView:nextKeyView];
1263     }
1264     [super setNextKeyView:wv];
1265
1266     ++WebViewCount;
1267
1268     [self _registerDraggedTypes];
1269
1270     // Update WebCore with preferences.  These values will either come from an archived WebPreferences,
1271     // or from the standard preferences, depending on whether this method was called from initWithCoder:
1272     // or initWithFrame, respectively.
1273     [self _updateWebCoreSettingsFromPreferences: [self preferences]];
1274     
1275     // Register to receive notifications whenever preference values change.
1276     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1277                                                  name:WebPreferencesChangedNotification object:[self preferences]];
1278 }
1279
1280 - init
1281 {
1282     return [self initWithFrame: NSZeroRect frameName: nil groupName: nil];
1283 }
1284
1285 - initWithFrame: (NSRect)f
1286 {
1287     [self initWithFrame: f frameName:nil groupName:nil];
1288     return self;
1289 }
1290
1291 - initWithFrame: (NSRect)f frameName: (NSString *)frameName groupName: (NSString *)groupName;
1292 {
1293     [super initWithFrame: f];
1294     _private = [[WebViewPrivate alloc] init];
1295     [self _commonInitializationWithFrameName:frameName groupName:groupName];
1296     [self setMaintainsBackForwardList: YES];
1297     return self;
1298 }
1299
1300 - (id)initWithCoder:(NSCoder *)decoder
1301 {
1302     WebView *result = nil;
1303
1304 NS_DURING
1305
1306     NSString *frameName;
1307     NSString *groupName;
1308     
1309     result = [super initWithCoder:decoder];
1310     result->_private = [[WebViewPrivate alloc] init];
1311     
1312     // We don't want any of the archived subviews.  The subviews will always
1313     // be created in _commonInitializationFrameName:groupName:.
1314     [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1315     
1316     if ([decoder allowsKeyedCoding]){
1317         frameName = [decoder decodeObjectForKey:@"FrameName"];
1318         groupName = [decoder decodeObjectForKey:@"GroupName"];
1319                 
1320         [result setPreferences: [decoder decodeObjectForKey:@"Preferences"]];
1321         result->_private->useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1322
1323         LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)_private->useBackForwardList);
1324     }
1325     else {
1326         int version;
1327     
1328         [decoder decodeValueOfObjCType:@encode(int) at:&version];
1329         frameName = [decoder decodeObject];
1330         groupName = [decoder decodeObject];
1331         [result setPreferences: [decoder decodeObject]];
1332         if (version > 1)
1333             [decoder decodeValuesOfObjCTypes:"c",&result->_private->useBackForwardList];
1334     }
1335     [result _commonInitializationWithFrameName:frameName groupName:groupName];
1336     
1337 NS_HANDLER
1338
1339     result = nil;
1340     [self release];
1341
1342 NS_ENDHANDLER
1343
1344     return result;
1345 }
1346
1347 - (void)encodeWithCoder:(NSCoder *)encoder
1348 {
1349     [super encodeWithCoder:encoder];
1350
1351     if ([encoder allowsKeyedCoding]){
1352         [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1353         [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1354         [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1355         [encoder encodeBool:_private->useBackForwardList forKey:@"UseBackForwardList"];
1356
1357         LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)_private->useBackForwardList);
1358     }
1359     else {
1360         int version = WebViewVersion;
1361         [encoder encodeValueOfObjCType:@encode(int) at:&version];
1362         [encoder encodeObject:[[self mainFrame] name]];
1363         [encoder encodeObject:[self groupName]];
1364         [encoder encodeObject:[self preferences]];
1365         [encoder encodeValuesOfObjCTypes:"c",&_private->useBackForwardList];
1366     }
1367 }
1368
1369 - (void)dealloc
1370 {
1371     [self _close];
1372     
1373     --WebViewCount;
1374     
1375     [[NSNotificationCenter defaultCenter] removeObserver:self];
1376     
1377     [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1378     
1379     [_private release];
1380     // [super dealloc] can end up dispatching against _private (3466082)
1381     _private = nil;
1382
1383     [super dealloc];
1384 }
1385
1386 - (void)setPreferences: (WebPreferences *)prefs
1387 {
1388     if (_private->preferences != prefs){
1389         [[NSNotificationCenter defaultCenter] removeObserver: self name: WebPreferencesChangedNotification object: [self preferences]];
1390         [WebPreferences _removeReferenceForIdentifier: [_private->preferences identifier]];
1391         [_private->preferences release];
1392         _private->preferences = [prefs retain];
1393         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1394                                                     name:WebPreferencesChangedNotification object:[self preferences]];
1395     }
1396 }
1397
1398 - (WebPreferences *)preferences
1399 {
1400     return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
1401 }
1402
1403 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
1404 {
1405     if (![anIdentifier isEqual: [[self preferences] identifier]]){
1406         [self setPreferences: [[WebPreferences alloc] initWithIdentifier:anIdentifier]];
1407     }
1408 }
1409
1410 - (NSString *)preferencesIdentifier
1411 {
1412     return [[self preferences] identifier];
1413 }
1414
1415
1416 - (void)setUIDelegate:delegate
1417 {
1418     _private->UIDelegate = delegate;
1419     [_private->UIDelegateForwarder release];
1420     _private->UIDelegateForwarder = nil;
1421 }
1422
1423 - UIDelegate
1424 {
1425     return _private->UIDelegate;
1426 }
1427
1428 - (void)setResourceLoadDelegate: delegate
1429 {
1430     _private->resourceProgressDelegate = delegate;
1431     [_private->resourceProgressDelegateForwarder release];
1432     _private->resourceProgressDelegateForwarder = nil;
1433     [self _cacheResourceLoadDelegateImplementations];
1434 }
1435
1436
1437 - resourceLoadDelegate
1438 {
1439     return _private->resourceProgressDelegate;
1440 }
1441
1442
1443 - (void)setDownloadDelegate: delegate
1444 {
1445     _private->downloadDelegate = delegate;
1446 }
1447
1448
1449 - downloadDelegate
1450 {
1451     return _private->downloadDelegate;
1452 }
1453
1454 - (void)setPolicyDelegate:delegate
1455 {
1456     _private->policyDelegate = delegate;
1457     [_private->policyDelegateForwarder release];
1458     _private->policyDelegateForwarder = nil;
1459 }
1460
1461 - policyDelegate
1462 {
1463     return _private->policyDelegate;
1464 }
1465
1466 - (void)setFrameLoadDelegate:delegate
1467 {
1468     _private->frameLoadDelegate = delegate;
1469     [_private->frameLoadDelegateForwarder release];
1470     _private->frameLoadDelegateForwarder = nil;
1471 }
1472
1473 - frameLoadDelegate
1474 {
1475     return _private->frameLoadDelegate;
1476 }
1477
1478 - (WebFrame *)mainFrame
1479 {
1480     // This can be called in initialization, before _private has been set up (3465613)
1481     if (_private != nil) {
1482         return _private->mainFrame;
1483     }
1484     return nil;
1485 }
1486
1487 - (WebBackForwardList *)backForwardList
1488 {
1489     if (_private->useBackForwardList)
1490         return _private->backForwardList;
1491     return nil;
1492 }
1493
1494 - (void)setMaintainsBackForwardList: (BOOL)flag
1495 {
1496     _private->useBackForwardList = flag;
1497 }
1498
1499 - (BOOL)goBack
1500 {
1501     WebHistoryItem *item = [[self backForwardList] backItem];
1502     
1503     if (item){
1504         [self _goToItem: item withLoadType: WebFrameLoadTypeBack];
1505         return YES;
1506     }
1507     return NO;
1508 }
1509
1510 - (BOOL)goForward
1511 {
1512     WebHistoryItem *item = [[self backForwardList] forwardItem];
1513     
1514     if (item){
1515         [self _goToItem: item withLoadType: WebFrameLoadTypeForward];
1516         return YES;
1517     }
1518     return NO;
1519 }
1520
1521 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
1522 {
1523     [self _goToItem: item withLoadType: WebFrameLoadTypeIndexedBackForward];
1524     return YES;
1525 }
1526
1527 - (void)setTextSizeMultiplier:(float)m
1528 {
1529     if (_private->textSizeMultiplier == m) {
1530         return;
1531     }
1532     _private->textSizeMultiplier = m;
1533     [[self mainFrame] _textSizeMultiplierChanged];
1534 }
1535
1536 - (float)textSizeMultiplier
1537 {
1538     return _private->textSizeMultiplier;
1539 }
1540
1541 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
1542 {
1543     NSString *name = [applicationName copy];
1544     [_private->applicationNameForUserAgent release];
1545     _private->applicationNameForUserAgent = name;
1546     if (!_private->userAgentOverridden) {
1547         [_private->userAgent release];
1548         _private->userAgent = nil;
1549     }
1550 }
1551
1552 - (NSString *)applicationNameForUserAgent
1553 {
1554     return [[_private->applicationNameForUserAgent retain] autorelease];
1555 }
1556
1557 - (void)setCustomUserAgent:(NSString *)userAgentString
1558 {
1559     NSString *override = [userAgentString copy];
1560     [_private->userAgent release];
1561     _private->userAgent = override;
1562     _private->userAgentOverridden = override != nil;
1563 }
1564
1565 - (NSString *)customUserAgent
1566 {
1567     return _private->userAgentOverridden ? [[_private->userAgent retain] autorelease] : nil;
1568 }
1569
1570 - (void)setMediaStyle:(NSString *)mediaStyle
1571 {
1572     if (_private->mediaStyle != mediaStyle) {
1573         [_private->mediaStyle release];
1574         _private->mediaStyle = [mediaStyle copy];
1575     }
1576 }
1577
1578 - (NSString *)mediaStyle
1579 {
1580     return _private->mediaStyle;
1581 }
1582
1583 - (BOOL)supportsTextEncoding
1584 {
1585     id documentView = [[[self mainFrame] frameView] documentView];
1586     return [documentView conformsToProtocol:@protocol(WebDocumentText)]
1587         && [documentView supportsTextEncoding];
1588 }
1589
1590 - (void)setCustomTextEncodingName:(NSString *)encoding
1591 {
1592     NSString *oldEncoding = [self customTextEncodingName];
1593     if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) {
1594         return;
1595     }
1596     [[self mainFrame] _reloadAllowingStaleDataWithOverrideEncoding:encoding];
1597 }
1598
1599 - (NSString *)_mainFrameOverrideEncoding
1600 {
1601     WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
1602     if (dataSource == nil) {
1603         dataSource = [[self mainFrame] dataSource];
1604     }
1605     if (dataSource == nil) {
1606         return nil;
1607     }
1608     return [dataSource _overrideEncoding];
1609 }
1610
1611 - (NSString *)customTextEncodingName
1612 {
1613     return [self _mainFrameOverrideEncoding];
1614 }
1615
1616 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
1617 {
1618     return [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
1619 }
1620
1621 - (WebScriptObject *)windowScriptObject
1622 {
1623     return [[[self mainFrame] _bridge] windowScriptObject];
1624 }
1625
1626
1627 // Get the appropriate user-agent string for a particular URL.
1628 // Since we no longer automatically spoof, this no longer requires looking at the URL.
1629 - (NSString *)userAgentForURL:(NSURL *)URL
1630 {
1631     NSString *userAgent = _private->userAgent;
1632     if (userAgent) {
1633         return [[userAgent retain] autorelease];
1634     }
1635     
1636     // FIXME: Some day we will start reporting the actual CPU here instead of hardcoding PPC.
1637
1638     NSString *language = [NSUserDefaults _web_preferredLanguageCode];
1639     id sourceVersion = [[NSBundle bundleForClass:[WebView class]]
1640         objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
1641     NSString *applicationName = _private->applicationNameForUserAgent;
1642
1643     if ([applicationName length]) {
1644         userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
1645             language, sourceVersion, applicationName];
1646     } else {
1647         userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko)",
1648             language, sourceVersion];
1649     }
1650
1651     _private->userAgent = [userAgent retain];
1652     return userAgent;
1653 }
1654
1655 - (void)setHostWindow:(NSWindow *)hostWindow
1656 {
1657     if (hostWindow != _private->hostWindow) {
1658         [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
1659         [_private->hostWindow release];
1660         _private->hostWindow = [hostWindow retain];
1661         [[self mainFrame] _viewDidMoveToHostWindow];
1662     }
1663 }
1664
1665 - (NSWindow *)hostWindow
1666 {
1667     return _private->hostWindow;
1668 }
1669
1670 - (NSDragOperation)dragOperationForDraggingInfo:(id <NSDraggingInfo>)sender
1671 {
1672     // Even though we may not be registered for any drag types, we may still get drag messages forwarded from WebHTMLView,
1673     // so compare the types on the pasteboard against the types we're currently registered for.
1674     NSPoint point = [[self superview] convertPoint:[sender draggingLocation] toView:nil];
1675     if ([_private->draggedTypes count] > 0 && 
1676         [[sender draggingPasteboard] availableTypeFromArray:_private->draggedTypes] != nil &&
1677         ![[self hitTest:point] isKindOfClass:[WebBaseNetscapePluginView class]]) {
1678         return [self _web_dragOperationForDraggingInfo:sender];
1679     }
1680     return NSDragOperationNone;
1681 }
1682
1683 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1684 {
1685     return [self dragOperationForDraggingInfo:sender];
1686 }
1687
1688 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1689 {
1690     return [self dragOperationForDraggingInfo:sender];
1691 }
1692
1693 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1694 {
1695     return YES;
1696 }
1697
1698 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1699 {
1700     return YES;
1701 }
1702
1703 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
1704 {
1705     if ([self dragOperationForDraggingInfo:sender] != NSDragOperationNone) {
1706         NSURL *URL = [[sender draggingPasteboard] _web_bestURL];
1707         if (URL) {
1708             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
1709             [[self mainFrame] loadRequest:request];
1710             [request release];
1711         }
1712     }
1713 }
1714
1715 - (BOOL)acceptsFirstResponder
1716 {
1717     return [[[self mainFrame] frameView] acceptsFirstResponder];
1718 }
1719
1720 - (BOOL)becomeFirstResponder
1721 {
1722     // This works together with setNextKeyView to splice the WebView into
1723     // the key loop similar to the way NSScrollView does this. Note that
1724     // WebFrameView has very similar code.
1725     NSWindow *window = [self window];
1726     WebFrameView *mainFrameView = [[self mainFrame] frameView];
1727     
1728     if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
1729         NSView *previousValidKeyView = [self previousValidKeyView];
1730         if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
1731             [window makeFirstResponder:previousValidKeyView];
1732             return YES;
1733         } else {
1734             return NO;
1735         }
1736     }
1737     
1738     if ([mainFrameView acceptsFirstResponder]) {
1739         [window makeFirstResponder:mainFrameView];
1740         return YES;
1741     } 
1742     
1743     return NO;
1744 }
1745
1746 - (void)setNextKeyView:(NSView *)aView
1747 {
1748     // This works together with becomeFirstResponder to splice the WebView into
1749     // the key loop similar to the way NSScrollView does this. Note that
1750     // WebFrameView has very similar code.
1751     WebFrameView *mainFrameView = [[self mainFrame] frameView];
1752     if (mainFrameView != nil) {
1753         [mainFrameView setNextKeyView:aView];
1754     } else {
1755         [super setNextKeyView:aView];
1756     }
1757 }
1758
1759 // Return the frame holding first responder
1760 - (WebFrame *)_currentFrame
1761 {
1762     // Find the frame holding the first responder, or holding the first form in the doc
1763     NSResponder *resp = [[self window] firstResponder];
1764     if (!resp || ![resp isKindOfClass:[NSView class]] || ![(NSView *)resp isDescendantOf:self]) {
1765         return nil;     // first responder outside our view tree
1766     } else {
1767         WebFrameView *frameView = (WebFrameView *)[(NSView *)resp _web_superviewOfClass:[WebFrameView class]];
1768         return [frameView webFrame];
1769     }
1770 }
1771
1772 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
1773 {
1774     return forward ? [curr _nextFrameWithWrap:wrapFlag]
1775                    : [curr _previousFrameWithWrap:wrapFlag];
1776 }
1777
1778 // Search from the end of the currently selected location, or from the beginning of the
1779 // document if nothing is selected.  Deals with subframes.
1780 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
1781 {
1782     // Get the frame holding the selection, or start with the main frame
1783     WebFrame *startFrame = [self _currentFrame];
1784     if (!startFrame) {
1785         startFrame = [self mainFrame];
1786     }
1787
1788     // Search the first frame, then all the other frames, in order
1789     NSView <WebDocumentSearching> *startSearchView = nil;
1790     BOOL startHasSelection = NO;
1791     WebFrame *frame = startFrame;
1792     do {
1793         id <WebDocumentView> view = [[frame frameView] documentView];
1794         if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
1795             NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
1796
1797             // first time through
1798             if (frame == startFrame) {
1799                 // Remember if start even has a selection, to know if we need to search more later
1800                 if ([searchView isKindOfClass:[WebHTMLView class]]) {
1801                     // optimization for the common case, to avoid making giant string for selection
1802                     startHasSelection = [[startFrame _bridge] selectionStart] != nil;
1803                 } else if ([searchView conformsToProtocol:@protocol(WebDocumentText)]) {
1804                     startHasSelection = [(id <WebDocumentText>)searchView selectedString] != nil;
1805                 }
1806                 startSearchView = searchView;
1807             }
1808             
1809             // Note at this point we are assuming the search will be done top-to-bottom,
1810             // not starting at any selection that exists.  See 3228554.
1811             BOOL success = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:NO];
1812             if (success) {
1813                 [[self window] makeFirstResponder:searchView];
1814                 return YES;
1815             }
1816         }
1817         frame = incrementFrame(frame, forward, wrapFlag);
1818     } while (frame != nil && frame != startFrame);
1819
1820     // Search contents of startFrame, on the other side of the selection that we did earlier.
1821     // We cheat a bit and just research with wrap on
1822     if (wrapFlag && startHasSelection && startSearchView) {
1823         BOOL success = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES];
1824         if (success) {
1825             [[self window] makeFirstResponder:startSearchView];
1826             return YES;
1827         }
1828     }
1829     return NO;
1830 }
1831
1832 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
1833 {
1834     [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
1835     [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
1836 }
1837
1838 - (void)setGroupName:(NSString *)groupName
1839 {
1840     if (groupName != _private->setName){
1841         [_private->setName release];
1842         _private->setName = [groupName copy];
1843         [WebViewSets addWebView:self toSetNamed:_private->setName];
1844     }
1845 }
1846
1847 - (NSString *)groupName
1848 {
1849     return _private->setName;
1850 }
1851
1852 - (double)estimatedProgress
1853 {
1854     return _private->progressValue;
1855 }
1856
1857 - (NSArray *)pasteboardTypesForSelection
1858 {
1859     NSView <WebDocumentView> *documentView = [[[[self _bridgeForCurrentSelection] webFrame] frameView] documentView];
1860     if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
1861         return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
1862     }
1863     return [NSArray array];
1864 }
1865
1866 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1867 {
1868     WebBridge *bridge = [self _bridgeForCurrentSelection];
1869     if ([bridge haveSelection]) {
1870         NSView <WebDocumentView> *documentView = [[[bridge webFrame] frameView] documentView];
1871         if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
1872             [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
1873         }
1874     }
1875 }
1876
1877 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
1878 {
1879     if ([element objectForKey:WebElementImageURLKey] != nil) {
1880         return [NSPasteboard _web_writableTypesForImage];
1881     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
1882         return [NSPasteboard _web_writableTypesForURL];
1883     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
1884         return [self pasteboardTypesForSelection];
1885     }
1886     return [NSArray array];
1887 }
1888
1889 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1890 {
1891     if ([element objectForKey:WebElementImageURLKey] != nil) {
1892         [self _writeImageElement:element withPasteboardTypes:types toPasteboard:pasteboard];
1893     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
1894         [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
1895     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
1896         [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
1897     }
1898 }
1899
1900 @end
1901
1902 @implementation WebView (WebIBActions)
1903
1904 - (IBAction)takeStringURLFrom: sender
1905 {
1906     NSString *URLString = [sender stringValue];
1907     
1908     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
1909 }
1910
1911 - (BOOL)canGoBack
1912 {
1913     return [[self backForwardList] backItem] != nil;
1914 }
1915
1916 - (BOOL)canGoForward
1917 {
1918     return [[self backForwardList] forwardItem] != nil;
1919 }
1920
1921 - (IBAction)goBack:(id)sender
1922 {
1923     [self goBack];
1924 }
1925
1926 - (IBAction)goForward:(id)sender
1927 {
1928     [self goForward];
1929 }
1930
1931 - (IBAction)stopLoading:(id)sender
1932 {
1933     [[self mainFrame] stopLoading];
1934 }
1935
1936 - (IBAction)reload:(id)sender
1937 {
1938     [[self mainFrame] reload];
1939 }
1940
1941 #define MinimumTextSizeMultiplier       0.5
1942 #define MaximumTextSizeMultiplier       3.0
1943 #define TextSizeMultiplierRatio         1.2
1944
1945 - (BOOL)canMakeTextSmaller
1946 {
1947     if ([[self mainFrame] dataSource] == nil) {
1948         return NO;
1949     }
1950     // FIXME: This will prevent text sizing in subframes if the main frame doesn't support it
1951     if (![[[[self mainFrame] frameView] documentView] conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
1952         return NO;
1953     }
1954     if ([self textSizeMultiplier]/TextSizeMultiplierRatio < MinimumTextSizeMultiplier) {
1955         return NO;
1956     }
1957     return YES;
1958 }
1959
1960 - (BOOL)canMakeTextLarger
1961 {
1962     if ([[self mainFrame] dataSource] == nil) {
1963         return NO;
1964     }
1965     // FIXME: This will prevent text sizing in subframes if the main frame doesn't support it
1966     if (![[[[self mainFrame] frameView] documentView] conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
1967         return NO;
1968     }
1969     if ([self textSizeMultiplier]*TextSizeMultiplierRatio > MaximumTextSizeMultiplier) {
1970         return NO;
1971     }
1972     return YES;
1973 }
1974
1975 - (IBAction)makeTextSmaller:(id)sender
1976 {
1977     if (![self canMakeTextSmaller]) {
1978         return;
1979     }
1980     [self setTextSizeMultiplier:[self textSizeMultiplier]/TextSizeMultiplierRatio];
1981 }
1982
1983 - (IBAction)makeTextLarger:(id)sender
1984 {
1985     if (![self canMakeTextLarger]) {
1986         return;
1987     }
1988     [self setTextSizeMultiplier:[self textSizeMultiplier]*TextSizeMultiplierRatio];
1989 }
1990
1991 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
1992 {
1993     SEL action = [item action];
1994
1995     if (action == @selector(goBack:)) {
1996         return [self canGoBack];
1997     } else if (action == @selector(goForward:)) {
1998         return [self canGoForward];
1999     } else if (action == @selector(makeTextLarger:)) {
2000         return [self canMakeTextLarger];
2001     } else if (action == @selector(makeTextSmaller:)) {
2002         return [self canMakeTextSmaller];
2003     } else if (action == @selector(reload:)) {
2004         return [[self mainFrame] dataSource] != nil;
2005     } else if (action == @selector(stopLoading:)) {
2006         return [self _isLoading];
2007     }
2008
2009     return YES;
2010 }
2011
2012
2013 @end
2014
2015
2016 @implementation WebView (WebPendingPublic)
2017
2018 - (void)setMainFrameURL:(NSString *)URLString
2019 {
2020     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2021 }
2022
2023 - (NSString *)mainFrameURL
2024 {
2025     WebDataSource *ds;
2026     ds = [[self mainFrame] provisionalDataSource];
2027     if (!ds)
2028         ds = [[self mainFrame] dataSource];
2029     return [[[ds request] URL] _web_originalDataAsString];
2030 }
2031
2032 - (BOOL)isLoading
2033 {
2034     LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2035     return [self _isLoading];
2036 }
2037
2038 - (NSString *)mainFrameTitle
2039 {
2040     NSString *mainFrameTitle = [[[self mainFrame] dataSource] pageTitle];
2041     return (mainFrameTitle != nil) ? mainFrameTitle : @"";
2042 }
2043
2044 - (NSImage *)mainFrameIcon
2045 {
2046     return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2047 }
2048
2049 - (void)setDrawsBackground:(BOOL)drawsBackground
2050 {
2051     if (_private->drawsBackground == drawsBackground)
2052         return;
2053     _private->drawsBackground = drawsBackground;
2054     [[self mainFrame] _updateDrawsBackground];
2055 }
2056
2057 - (BOOL)drawsBackground
2058 {
2059     return _private->drawsBackground;
2060 }
2061
2062 @end
2063
2064 @implementation WebView (WebViewPrintingPrivate)
2065
2066 - (float)_headerHeight
2067 {
2068     if ([[self UIDelegate] respondsToSelector:@selector(webViewHeaderHeight:)]) {
2069         return [[self UIDelegate] webViewHeaderHeight:self];
2070     }
2071     
2072 #ifdef DEBUG_HEADER_AND_FOOTER
2073     return 25;
2074 #else
2075     return 0;
2076 #endif
2077 }
2078
2079 - (float)_footerHeight
2080 {
2081     if ([[self UIDelegate] respondsToSelector:@selector(webViewFooterHeight:)]) {
2082         return [[self UIDelegate] webViewFooterHeight:self];
2083     }
2084     
2085 #ifdef DEBUG_HEADER_AND_FOOTER
2086     return 50;
2087 #else
2088     return 0;
2089 #endif
2090 }
2091
2092 - (void)_drawHeaderInRect:(NSRect)rect
2093 {
2094 #ifdef DEBUG_HEADER_AND_FOOTER
2095     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2096     [currentContext saveGraphicsState];
2097     [[NSColor yellowColor] set];
2098     NSRectFill(rect);
2099     [currentContext restoreGraphicsState];
2100 #endif
2101     
2102     if ([[self UIDelegate] respondsToSelector:@selector(webView:drawHeaderInRect:)]) {
2103         NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2104         [currentContext saveGraphicsState];
2105         NSRectClip(rect);
2106         [[self UIDelegate] webView:self drawHeaderInRect:rect]; 
2107         [currentContext restoreGraphicsState];
2108     }
2109 }
2110
2111 - (void)_drawFooterInRect:(NSRect)rect
2112 {
2113 #ifdef DEBUG_HEADER_AND_FOOTER
2114     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2115     [currentContext saveGraphicsState];
2116     [[NSColor cyanColor] set];
2117     NSRectFill(rect);
2118     [currentContext restoreGraphicsState];
2119 #endif
2120     
2121     if ([[self UIDelegate] respondsToSelector:@selector(webView:drawFooterInRect:)]) {
2122         NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2123         [currentContext saveGraphicsState];
2124         NSRectClip(rect);
2125         [[self UIDelegate] webView:self drawFooterInRect:rect];
2126         [currentContext restoreGraphicsState];
2127     }
2128 }
2129
2130 - (void)_adjustPrintingMarginsForHeaderAndFooter
2131 {
2132     NSPrintOperation *op = [NSPrintOperation currentOperation];
2133     NSPrintInfo *info = [op printInfo];
2134     float scale = [op _web_pageSetupScaleFactor];
2135     [info setTopMargin:[info topMargin] + [self _headerHeight]*scale];
2136     [info setBottomMargin:[info bottomMargin] + [self _footerHeight]*scale];
2137 }
2138
2139 - (void)_drawHeaderAndFooter
2140 {
2141     // The header and footer rect height scales with the page, but the width is always
2142     // all the way across the printed page (inset by printing margins).
2143     NSPrintOperation *op = [NSPrintOperation currentOperation];
2144     float scale = [op _web_pageSetupScaleFactor];
2145     NSPrintInfo *printInfo = [op printInfo];
2146     NSSize paperSize = [printInfo paperSize];
2147     float headerFooterLeft = [printInfo leftMargin]/scale;
2148     float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
2149     NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , 
2150                                    headerFooterWidth, [self _footerHeight]);
2151     NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, 
2152                                    headerFooterWidth, [self _headerHeight]);
2153     
2154     [self _drawHeaderInRect:headerRect];
2155     [self _drawFooterInRect:footerRect];
2156 }
2157 @end
2158
2159 @implementation WebView (WebDebugBinding)
2160
2161 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
2162 {
2163     LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
2164     [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
2165 }
2166
2167 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
2168 {
2169     LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
2170     [super removeObserver:anObserver forKeyPath:keyPath];
2171 }
2172
2173 @end
2174
2175 //==========================================================================================
2176 // Editing
2177
2178 @implementation WebView (WebViewEditingInternal)
2179
2180 - (void)_alterCurrentSelection:(WebSelectionAlteration)alteration direction:(WebSelectionDirection)direction granularity:(WebSelectionGranularity)granularity
2181 {
2182     WebBridge *bridge = [self _bridgeForCurrentSelection];
2183     DOMRange *proposedRange = [bridge rangeByAlteringCurrentSelection:alteration direction:direction granularity:granularity];
2184     if ([[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:[self selectedDOMRange] toDOMRange:proposedRange affinity:[bridge selectionAffinity] stillSelecting:NO]) {
2185         [bridge alterCurrentSelection:alteration direction:direction granularity:granularity];
2186         [bridge ensureCaretVisible];
2187     }
2188 }
2189
2190 - (WebBridge *)_bridgeForCurrentSelection
2191 {
2192     // FIXME: This needs to be changed to deal properly with subframes.
2193     return [[self mainFrame] _bridge];
2194 }
2195
2196 - (BOOL)_currentSelectionIsEditable
2197 {
2198     return [[self _bridgeForCurrentSelection] isSelectionEditable];
2199 }
2200
2201 @end
2202
2203 @implementation WebView (WebViewCSS)
2204
2205 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
2206 {
2207     // FIXME: is this the best level for this conversion?
2208     if (pseudoElement == nil) {
2209         pseudoElement = @"";
2210     }
2211     return [[self DOMDocument] getComputedStyle:element :pseudoElement];
2212 }
2213
2214 @end
2215
2216 @implementation WebView (WebInternal)
2217
2218 - (BOOL)_isLoading
2219 {
2220     WebFrame *mainFrame = [self mainFrame];
2221     return [[mainFrame dataSource] isLoading]
2222         || [[mainFrame provisionalDataSource] isLoading];
2223 }
2224
2225 static NSFont *_fontFromStyle(DOMCSSStyleDeclaration *style)
2226 {
2227     // FIXME: can't get at CSS_PROP_FONT_FAMILY and such from cssproperties.h in WebCore
2228     // because that header file isn't available to WebKit. Is that a problem?
2229     // FIXME: calling [DOMCSSStyleDeclaration fontFamily] doesn't work yet, returns nil.
2230     // FIXME: calling [DOMCSSStyleDeclaration fontSize] doesn't work yet, returns nil.
2231     // FIXME: is there SPI/API for converting a fontSize string into a numeric value?
2232     // FIXME: calling [DOMCSSStyleDeclaration font] doesn't work yet, fails WebCore assertion
2233     ERROR("unimplemented");
2234     return nil;
2235 }
2236
2237 - (void)_updateFontPanel
2238 {
2239     // FIXME: NSTextView bails out if becoming or resigning first responder, for which it has ivar flags. Not
2240     // sure if we need to do something similar.
2241     
2242     if (![self _currentSelectionIsEditable]) {
2243         return;
2244     }
2245     
2246     NSWindow *window = [self window];
2247     // FIXME: is this first-responder check correct? What happens if a subframe is editable and is first responder?
2248     if ([NSApp keyWindow] != window || [window firstResponder] != [[[self mainFrame] frameView] documentView]) {
2249         return;
2250     }
2251     
2252     BOOL onlyOneFontInSelection = YES;
2253     DOMCSSStyleDeclaration *style = nil;
2254     NSFont *font = nil;
2255     
2256     if (![[self _bridgeForCurrentSelection] haveSelection]) {
2257         style = [self typingStyle];
2258         font = _fontFromStyle(style);
2259         // FIXME: We're currently thinking that typingStyle will always specify a font, but we need to
2260         // make sure that it's implemented that way when it is implemented.
2261     } else {
2262         // FIXME: This code is being reached after backspacing with only an insertion
2263         // point showing; this must be a bug in haveSelection or underlying code.
2264         DOMRange *selection = [self selectedDOMRange];
2265         
2266         DOMNode *firstSelectedElement = [selection startContainer];
2267         while (firstSelectedElement != nil && ![firstSelectedElement isKindOfClass:[DOMElement class]]) {
2268             firstSelectedElement = [firstSelectedElement parentNode];
2269         }
2270         ASSERT([firstSelectedElement isKindOfClass:[DOMElement class]]);
2271         
2272         font = [[self _bridgeForCurrentSelection] renderedFontForNode:firstSelectedElement];
2273         style = [self computedStyleForElement:(DOMElement *)firstSelectedElement pseudoElement:nil];
2274         
2275         // Iterate through all selected elements to see if fonts or attributes change.
2276         if ([selection startContainer] != [selection endContainer]) {
2277             DOMNode *lastSelectedElement = [selection endContainer];
2278             while (lastSelectedElement != nil && ![lastSelectedElement isKindOfClass:[DOMElement class]]) {
2279                 lastSelectedElement = [lastSelectedElement parentNode];
2280             }
2281             ASSERT([lastSelectedElement isKindOfClass:[DOMElement class]]);
2282             
2283             // FIXME: The "&& NO" prevents createNodeIterator from being called, which is nice because
2284             // it's not actually defined yet.
2285             if (lastSelectedElement != firstSelectedElement && NO) {
2286                 DOMNodeIterator *iterator = [[self DOMDocument] createNodeIterator:firstSelectedElement
2287                                                                                   :DOM_SHOW_ELEMENT
2288                                                                                   :nil
2289                                                                                   :NO];
2290                 DOMNode *element = [iterator nextNode];
2291                 ASSERT(element == firstSelectedElement);
2292                 
2293                 for (; element != lastSelectedElement; element = [iterator nextNode]) {
2294                     ASSERT([element isKindOfClass:[DOMElement class]]);
2295                     
2296                     NSFont *otherFont = [[self _bridgeForCurrentSelection] renderedFontForNode:element];
2297                     if (![font isEqual:otherFont]) {
2298                         onlyOneFontInSelection = NO;
2299                         break;
2300                     }
2301                 }
2302                 
2303                 // Since our iterator is autoreleased, we needn't call [iterator detach]
2304             }
2305         }
2306     }
2307     
2308     // FIXME: for now, return a bogus font that distinguishes the empty selection from the non-empty
2309     // selection. We should be able to remove this once the rest of this code works properly.
2310     if (font == nil) {
2311         if (![[self _bridgeForCurrentSelection] haveSelection]) {
2312             font = [NSFont toolTipsFontOfSize:17];
2313         } else {
2314             font = [NSFont menuFontOfSize:23];
2315         }
2316     }
2317     ASSERT(font != nil);
2318         
2319     NSFontManager *fm = [NSFontManager sharedFontManager];
2320     [fm setSelectedFont:font isMultiple:!onlyOneFontInSelection];
2321     // FIXME: we don't keep track of selected attributes, or set them on the font panel. This
2322     // appears to have no effect on the UI. E.g., underlined text in Mail or TextEdit is
2323     // not reflected in the font panel. Maybe someday this will change.
2324 }
2325
2326 @end
2327
2328 @implementation WebView (WebViewEditing)
2329
2330 - (void)_editingKeyDown:(NSEvent *)event
2331 {   
2332     // Work around this bug:
2333     // <rdar://problem/3630640>: "Calling interpretKeyEvents: in a custom text view can fail to process keys right after app startup"
2334     [NSKeyBindingManager sharedKeyBindingManager];
2335     
2336     // Now process the key normally
2337     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
2338 }
2339
2340 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
2341 {
2342     [[self _bridgeForCurrentSelection] setSelectedDOMRange:range affinity:selectionAffinity];
2343 }
2344
2345 - (DOMRange *)selectedDOMRange
2346 {
2347     return [[self _bridgeForCurrentSelection] selectedDOMRange];
2348 }
2349
2350 - (NSSelectionAffinity)selectionAffinity
2351 {
2352     return [[self _bridgeForCurrentSelection] selectionAffinity];
2353 }
2354
2355 - (void)setEditable:(BOOL)flag
2356 {
2357     _private->editable = flag;
2358 }
2359
2360 - (BOOL)isEditable
2361 {
2362     return _private->editable;
2363 }
2364
2365 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
2366 {
2367     ERROR("unimplemented");
2368 }
2369
2370 - (DOMCSSStyleDeclaration *)typingStyle
2371 {
2372     ERROR("unimplemented");
2373     return nil;
2374 }
2375
2376 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
2377 {
2378     ERROR("unimplemented");
2379 }
2380
2381 - (BOOL)smartInsertDeleteEnabled
2382 {
2383     ERROR("unimplemented");
2384     return NO;
2385 }
2386
2387 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
2388 {
2389     ERROR("unimplemented");
2390 }
2391
2392 - (BOOL)isContinuousSpellCheckingEnabled
2393 {
2394     ERROR("unimplemented");
2395     return NO;
2396 }
2397
2398 - (int)spellCheckerDocumentTag
2399 {
2400     ERROR("unimplemented");
2401     return 0;
2402 }
2403
2404 - (NSUndoManager *)undoManager
2405 {
2406     NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
2407     if (undoManager) {
2408         return undoManager;
2409     }
2410     return [super undoManager];
2411 }
2412
2413 - (void)setEditingDelegate:(id)delegate
2414 {
2415     if (_private->editingDelegate == delegate)
2416         return;
2417
2418     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
2419
2420     // remove notifications from current delegate
2421     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
2422     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
2423     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
2424     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
2425     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
2426     
2427     _private->editingDelegate = delegate;
2428     [_private->editingDelegateForwarder release];
2429     _private->editingDelegateForwarder = nil;
2430     
2431     // add notifications for new delegate
2432     [defaultCenter addObserver:_private->editingDelegate selector:@selector(webViewDidBeginEditing:) name:WebViewDidBeginEditingNotification object:self];
2433     [defaultCenter addObserver:_private->editingDelegate selector:@selector(webViewDidChange:) name:WebViewDidChangeNotification object:self];
2434     [defaultCenter addObserver:_private->editingDelegate selector:@selector(webViewDidEndEditing:) name:WebViewDidEndEditingNotification object:self];
2435     [defaultCenter addObserver:_private->editingDelegate selector:@selector(webViewDidChangeTypingStyle:) name:WebViewDidChangeTypingStyleNotification object:self];
2436     [defaultCenter addObserver:_private->editingDelegate selector:@selector(webViewDidChangeSelection:) name:WebViewDidChangeSelectionNotification object:self];    
2437 }
2438
2439 - (id)editingDelegate
2440 {
2441     return _private->editingDelegate;
2442 }
2443
2444 - (DOMDocument *)DOMDocument
2445 {
2446     return [[self _bridgeForCurrentSelection] DOMDocument];
2447 }
2448
2449 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
2450 {
2451     DOMCSSStyleDeclaration *decl = [[self DOMDocument] createCSSStyleDeclaration];
2452     [decl setCssText:text];
2453     return decl;
2454 }
2455
2456 @end
2457
2458 @implementation WebView (WebViewUndoableEditing)
2459
2460 - (void)replaceSelectionWithNode:(DOMNode *)node
2461 {
2462     [[self _bridgeForCurrentSelection] replaceSelectionWithNode:node];
2463 }    
2464
2465 - (void)replaceSelectionWithText:(NSString *)text
2466 {
2467     [[self _bridgeForCurrentSelection] replaceSelectionWithText:text];
2468 }
2469
2470 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
2471 {
2472     [[self _bridgeForCurrentSelection] replaceSelectionWithMarkupString:markupString baseURLString:nil];
2473 }
2474
2475 - (void)replaceSelectionWithArchive:(WebArchive *)archive
2476 {
2477     WebBridge *bridge = [self _bridgeForCurrentSelection];
2478     [[[bridge webFrame] dataSource] _replaceSelectionWithArchive:archive];
2479 }
2480
2481 - (void)deleteSelection
2482 {
2483     [[self _bridgeForCurrentSelection] deleteSelection];
2484 }
2485     
2486 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
2487 {
2488     [[self _bridgeForCurrentSelection] applyStyle:style];
2489 }
2490
2491 @end
2492
2493
2494 /*!
2495     @implementation WebView (WebViewEditingActions)
2496 */
2497 @implementation WebView (WebViewEditingActions)
2498
2499 - (void)centerSelectionInVisibleArea:(id)sender
2500 {
2501     if ([self _currentSelectionIsEditable]) {
2502         ERROR("unimplemented");
2503         return;
2504     }
2505     [[self nextResponder] tryToPerform:@selector(centerSelectionInVisibleArea:) with:sender];
2506 }
2507
2508 - (void)moveBackward:(id)sender
2509 {
2510     if ([self _currentSelectionIsEditable]) {
2511         ERROR("unimplemented");
2512         return;
2513     }
2514     [[self nextResponder] tryToPerform:@selector(moveBackward:) with:sender];
2515 }
2516
2517 - (void)moveBackwardAndModifySelection:(id)sender
2518 {
2519     if ([self _currentSelectionIsEditable]) {
2520         ERROR("unimplemented");
2521         return;
2522     }
2523     [[self nextResponder] tryToPerform:@selector(moveBackwardAndModifySelection:) with:sender];
2524 }
2525
2526 - (void)moveDown:(id)sender
2527 {
2528     if ([self _currentSelectionIsEditable]) {
2529         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectDown granularity:WebSelectByCharacter];
2530         return;
2531     }
2532     [[self nextResponder] tryToPerform:@selector(moveDown:) with:sender];
2533 }
2534
2535 - (void)moveDownAndModifySelection:(id)sender
2536 {
2537     if ([self _currentSelectionIsEditable]) {
2538         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectDown granularity:WebSelectByCharacter];
2539         return;
2540     }
2541     [[self nextResponder] tryToPerform:@selector(moveDownAndModifySelection:) with:sender];
2542 }
2543
2544 - (void)moveForward:(id)sender
2545 {
2546     if ([self _currentSelectionIsEditable]) {
2547         ERROR("unimplemented");
2548         return;
2549     }
2550     [[self nextResponder] tryToPerform:@selector(moveForward:) with:sender];
2551 }
2552
2553 - (void)moveForwardAndModifySelection:(id)sender
2554 {
2555     if ([self _currentSelectionIsEditable]) {
2556         ERROR("unimplemented");
2557         return;
2558     }
2559     [[self nextResponder] tryToPerform:@selector(moveForwardAndModifySelection:) with:sender];
2560 }
2561
2562 - (void)moveLeft:(id)sender
2563 {
2564     if ([self _currentSelectionIsEditable]) {
2565         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectLeft granularity:WebSelectByCharacter];
2566         return;
2567     }
2568     [[self nextResponder] tryToPerform:@selector(moveLeft:) with:sender];
2569 }
2570
2571 - (void)moveLeftAndModifySelection:(id)sender
2572 {
2573     if ([self _currentSelectionIsEditable]) {
2574         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectLeft granularity:WebSelectByCharacter];
2575         return;
2576     }
2577     [[self nextResponder] tryToPerform:@selector(moveLeftAndModifySelection:) with:sender];
2578 }
2579
2580 - (void)moveRight:(id)sender
2581 {
2582     if ([self _currentSelectionIsEditable]) {
2583         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectRight granularity:WebSelectByCharacter];
2584         return;
2585     }
2586     [[self nextResponder] tryToPerform:@selector(moveRight:) with:sender];
2587 }
2588
2589 - (void)moveRightAndModifySelection:(id)sender
2590 {
2591     if ([self _currentSelectionIsEditable]) {
2592         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectRight granularity:WebSelectByCharacter];
2593         return;
2594     }
2595     [[self nextResponder] tryToPerform:@selector(moveRightAndModifySelection:) with:sender];
2596 }
2597
2598 - (void)moveToBeginningOfDocument:(id)sender
2599 {
2600     if ([self _currentSelectionIsEditable]) {
2601         ERROR("unimplemented");
2602         return;
2603     }
2604     [[self nextResponder] tryToPerform:@selector(moveToBeginningOfDocument:) with:sender];
2605 }
2606
2607 - (void)moveToBeginningOfLine:(id)sender
2608 {
2609     if ([self _currentSelectionIsEditable]) {
2610         ERROR("unimplemented");
2611         return;
2612     }
2613     [[self nextResponder] tryToPerform:@selector(moveToBeginningOfLine:) with:sender];
2614 }
2615
2616 - (void)moveToBeginningOfParagraph:(id)sender
2617 {
2618     if ([self _currentSelectionIsEditable]) {
2619         ERROR("unimplemented");
2620         return;
2621     }
2622     [[self nextResponder] tryToPerform:@selector(moveToBeginningOfParagraph:) with:sender];
2623 }
2624
2625 - (void)moveToEndOfDocument:(id)sender
2626 {
2627     if ([self _currentSelectionIsEditable]) {
2628         ERROR("unimplemented");
2629         return;
2630     }
2631     [[self nextResponder] tryToPerform:@selector(moveToEndOfDocument:) with:sender];
2632 }
2633
2634 - (void)moveToEndOfLine:(id)sender
2635 {
2636     if ([self _currentSelectionIsEditable]) {
2637         ERROR("unimplemented");
2638         return;
2639     }
2640     [[self nextResponder] tryToPerform:@selector(moveToEndOfLine:) with:sender];
2641 }
2642
2643 - (void)moveToEndOfParagraph:(id)sender
2644 {
2645     if ([self _currentSelectionIsEditable]) {
2646         ERROR("unimplemented");
2647         return;
2648     }
2649     [[self nextResponder] tryToPerform:@selector(moveToEndOfParagraph:) with:sender];
2650 }
2651
2652 - (void)moveUp:(id)sender
2653 {
2654     if ([self _currentSelectionIsEditable]) {
2655         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectUp granularity:WebSelectByCharacter];
2656         return;
2657     }
2658     [[self nextResponder] tryToPerform:@selector(moveUp:) with:sender];
2659 }
2660
2661 - (void)moveUpAndModifySelection:(id)sender
2662 {
2663     if ([self _currentSelectionIsEditable]) {
2664         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectUp granularity:WebSelectByCharacter];
2665         return;
2666     }
2667     [[self nextResponder] tryToPerform:@selector(moveUpAndModifySelection:) with:sender];
2668 }
2669
2670 - (void)moveWordBackward:(id)sender
2671 {
2672     if ([self _currentSelectionIsEditable]) {
2673         ERROR("unimplemented");
2674         return;
2675     }
2676     [[self nextResponder] tryToPerform:@selector(moveWordBackward:) with:sender];
2677 }
2678
2679 - (void)moveWordBackwardAndModifySelection:(id)sender
2680 {
2681     if ([self _currentSelectionIsEditable]) {
2682         ERROR("unimplemented");
2683         return;
2684     }
2685     [[self nextResponder] tryToPerform:@selector(moveWordBackwardAndModifySelection:) with:sender];
2686 }
2687
2688 - (void)moveWordForward:(id)sender
2689 {
2690     if ([self _currentSelectionIsEditable]) {
2691         ERROR("unimplemented");
2692         return;
2693     }
2694     [[self nextResponder] tryToPerform:@selector(moveWordForward:) with:sender];
2695 }
2696
2697 - (void)moveWordForwardAndModifySelection:(id)sender
2698 {
2699     if ([self _currentSelectionIsEditable]) {
2700         ERROR("unimplemented");
2701         return;
2702     }
2703     [[self nextResponder] tryToPerform:@selector(moveWordForwardAndModifySelection:) with:sender];
2704 }
2705
2706 - (void)moveWordLeft:(id)sender
2707 {
2708     if ([self _currentSelectionIsEditable]) {
2709         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectLeft granularity:WebSelectByWord];
2710         return;
2711     }
2712     [[self nextResponder] tryToPerform:@selector(moveWordLeft:) with:sender];
2713 }
2714
2715 - (void)moveWordLeftAndModifySelection:(id)sender
2716 {
2717     if ([self _currentSelectionIsEditable]) {
2718         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectLeft granularity:WebSelectByWord];
2719         return;
2720     }
2721     [[self nextResponder] tryToPerform:@selector(moveWordLeftAndModifySelection:) with:sender];
2722 }
2723
2724 - (void)moveWordRight:(id)sender
2725 {
2726     if ([self _currentSelectionIsEditable]) {
2727         [self _alterCurrentSelection:WebSelectByMoving direction:WebSelectRight granularity:WebSelectByWord];
2728         return;
2729     }
2730     [[self nextResponder] tryToPerform:@selector(moveWordRight:) with:sender];
2731 }
2732
2733 - (void)moveWordRightAndModifySelection:(id)sender
2734 {
2735     if ([self _currentSelectionIsEditable]) {
2736         [self _alterCurrentSelection:WebSelectByExtending direction:WebSelectRight granularity:WebSelectByWord];
2737         return;
2738     }
2739     [[self nextResponder] tryToPerform:@selector(moveWordRightAndModifySelection:) with:sender];
2740 }
2741
2742 - (void)pageDown:(id)sender
2743 {
2744     if ([self _currentSelectionIsEditable]) {
2745         ERROR("unimplemented");
2746         return;
2747     }
2748     [[self nextResponder] tryToPerform:@selector(pageDown:) with:sender];
2749 }
2750
2751 - (void)pageUp:(id)sender
2752 {
2753     if ([self _currentSelectionIsEditable]) {
2754         ERROR("unimplemented");
2755         return;
2756     }
2757     [[self nextResponder] tryToPerform:@selector(pageUp:) with:sender];
2758 }
2759
2760 - (void)scrollLineDown:(id)sender
2761 {
2762     if ([self _currentSelectionIsEditable]) {
2763         ERROR("unimplemented");
2764         return;
2765     }
2766     [[self nextResponder] tryToPerform:@selector(scrollLineDown:) with:sender];
2767 }
2768
2769 - (void)scrollLineUp:(id)sender
2770 {
2771     if ([self _currentSelectionIsEditable]) {
2772         ERROR("unimplemented");
2773         return;
2774     }
2775     [[self nextResponder] tryToPerform:@selector(scrollLineUp:) with:sender];
2776 }
2777
2778
2779     /* Selections */
2780
2781 - (void)selectAll:(id)sender
2782 {
2783     if ([self _currentSelectionIsEditable]) {
2784         ERROR("unimplemented");
2785         return;
2786     }
2787     [[self nextResponder] tryToPerform:@selector(selectAll:) with:sender];
2788 }
2789
2790 - (void)selectParagraph:(id)sender
2791 {
2792     if ([self _currentSelectionIsEditable]) {
2793         ERROR("unimplemented");
2794         return;
2795     }
2796     [[self nextResponder] tryToPerform:@selector(selectParagraph:) with:sender];
2797 }
2798
2799 - (void)selectLine:(id)sender
2800 {
2801     if ([self _currentSelectionIsEditable]) {
2802         ERROR("unimplemented");
2803         return;
2804     }
2805     [[self nextResponder] tryToPerform:@selector(selectLine:) with:sender];
2806 }
2807
2808 - (void)selectWord:(id)sender
2809 {
2810     if ([self _currentSelectionIsEditable]) {
2811         ERROR("unimplemented");
2812         return;
2813     }
2814     [[self nextResponder] tryToPerform:@selector(selectWord:) with:sender];
2815 }
2816
2817
2818     /* "Edit menu" actions */
2819
2820 - (void)copy:(id)sender
2821 {
2822     if ([self _currentSelectionIsEditable]) {
2823         id <WebDocumentView> view = [[[self mainFrame] frameView] documentView];
2824         if ([view isKindOfClass:[WebHTMLView class]]) {
2825             [(WebHTMLView *)view copy:nil];
2826         }
2827         return;
2828     }
2829     [[self nextResponder] tryToPerform:@selector(copy:) with:sender];
2830 }
2831
2832 - (void)cut:(id)sender
2833 {
2834     if ([self _currentSelectionIsEditable]) {
2835         id <WebDocumentView> view = [[[self mainFrame] frameView] documentView];
2836         if ([view isKindOfClass:[WebHTMLView class]]) {
2837             [(WebHTMLView *)view cut:nil];
2838         }
2839         return;
2840     }
2841     [[self nextResponder] tryToPerform:@selector(cut:) with:sender];
2842 }
2843
2844 - (void)paste:(id)sender
2845 {
2846     if ([self _currentSelectionIsEditable]) {
2847         id <WebDocumentView> view = [[[self mainFrame] frameView] documentView];
2848         if ([view isKindOfClass:[WebHTMLView class]]) {
2849             [(WebHTMLView *)view paste:nil];
2850         }
2851         return;
2852     }
2853     [[self nextResponder] tryToPerform:@selector(paste:) with:sender];
2854 }
2855
2856 - (void)copyFont:(id)sender
2857 {
2858     if ([self _currentSelectionIsEditable]) {
2859         ERROR("unimplemented");
2860         return;
2861     }
2862     [[self nextResponder] tryToPerform:@selector(copyFont:) with:sender];
2863 }
2864
2865 - (void)pasteFont:(id)sender
2866 {
2867     if ([self _currentSelectionIsEditable]) {
2868         ERROR("unimplemented");
2869         return;
2870     }
2871     [[self nextResponder] tryToPerform:@selector(pasteFont:) with:sender];
2872 }
2873
2874 - (void)delete:(id)sender
2875 {
2876     if ([self _currentSelectionIsEditable]) {
2877         ERROR("unimplemented");
2878         return;
2879     }
2880     [[self nextResponder] tryToPerform:@selector(delete:) with:sender];
2881 }
2882
2883 - (void)pasteAsPlainText:(id)sender
2884 {
2885     if ([self _currentSelectionIsEditable]) {
2886         ERROR("unimplemented");
2887         return;
2888     }
2889     [[self nextResponder] tryToPerform:@selector(pasteAsPlainText:) with:sender];
2890 }
2891
2892 - (void)pasteAsRichText:(id)sender
2893 {
2894     if ([self _currentSelectionIsEditable]) {
2895         ERROR("unimplemented");
2896         return;
2897     }
2898     [[self nextResponder] tryToPerform:@selector(pasteAsRichText:) with:sender];
2899 }
2900
2901
2902     /* Fonts */
2903
2904 - (void)changeFont:(id)sender
2905 {
2906     if ([self _currentSelectionIsEditable]) {
2907         ERROR("unimplemented");
2908         return;
2909     }
2910     [[self nextResponder] tryToPerform:@selector(changeFont:) with:sender];
2911 }
2912
2913 - (void)changeAttributes:(id)sender
2914 {
2915     if ([self _currentSelectionIsEditable]) {
2916         ERROR("unimplemented");
2917         return;
2918     }
2919     [[self nextResponder] tryToPerform:@selector(changeAttributes:) with:sender];
2920 }
2921
2922 - (void)changeDocumentBackgroundColor:(id)sender
2923 {
2924     if ([self _currentSelectionIsEditable]) {
2925         ERROR("unimplemented");
2926         return;
2927     }
2928     [[self nextResponder] tryToPerform:@selector(changeDocumentBackgroundColor:) with:sender];
2929 }
2930
2931
2932     /* Colors */
2933
2934 - (void)changeColor:(id)sender
2935 {
2936     if ([self _currentSelectionIsEditable]) {
2937         ERROR("unimplemented");
2938         return;
2939     }
2940     [[self nextResponder] tryToPerform:@selector(changeColor:) with:sender];
2941 }
2942
2943
2944         /* Alignment */
2945
2946 - (void)alignCenter:(id)sender
2947 {
2948     if ([self _currentSelectionIsEditable]) {
2949         ERROR("unimplemented");
2950         return;
2951     }
2952     [[self nextResponder] tryToPerform:@selector(alignCenter:) with:sender];
2953 }
2954
2955 - (void)alignJustified:(id)sender
2956 {
2957     if ([self _currentSelectionIsEditable]) {
2958         ERROR("unimplemented");
2959         return;
2960     }
2961     [[self nextResponder] tryToPerform:@selector(alignJustified:) with:sender];
2962 }
2963
2964 - (void)alignLeft:(id)sender
2965 {
2966     if ([self _currentSelectionIsEditable]) {
2967         ERROR("unimplemented");
2968         return;
2969     }
2970     [[self nextResponder] tryToPerform:@selector(alignLeft:) with:sender];
2971 }
2972
2973 - (void)alignRight:(id)sender
2974 {
2975     if ([self _currentSelectionIsEditable]) {
2976         ERROR("unimplemented");
2977         return;
2978     }
2979     [[self nextResponder] tryToPerform:@selector(alignRight:) with:sender];
2980 }
2981
2982
2983     /* Insertions and Indentations */
2984
2985 - (void)indent:(id)sender
2986 {
2987     if ([self _currentSelectionIsEditable]) {
2988         ERROR("unimplemented");
2989         return;
2990     }
2991     [[self nextResponder] tryToPerform:@selector(indent:) with:sender];
2992 }
2993
2994 - (void)insertTab:(id)sender
2995 {
2996     if ([self _currentSelectionIsEditable]) {
2997         ERROR("unimplemented");
2998         return;
2999     }
3000     [[self nextResponder] tryToPerform:@selector(insertTab:) with:sender];
3001 }
3002
3003 - (void)insertBacktab:(id)sender
3004 {
3005     if ([self _currentSelectionIsEditable]) {
3006         ERROR("unimplemented");
3007         return;
3008     }
3009     [[self nextResponder] tryToPerform:@selector(insertBacktab:) with:sender];
3010 }
3011
3012 - (void)insertNewline:(id)sender
3013 {
3014     if ([self _currentSelectionIsEditable]) {
3015         WebBridge *bridge = [self _bridgeForCurrentSelection];
3016         // Perhaps we should make this delegate call sensitive to the real DOM operation we actually do.
3017         if ([[self _editingDelegateForwarder] webView:self shouldInsertText:@"\n" replacingDOMRange:[self selectedDOMRange] givenAction:WebViewInsertActionTyped]) {
3018             [bridge replaceSelectionWithNewline];
3019             [bridge ensureCaretVisible];
3020         }
3021         return;
3022     }
3023     [[self nextResponder] tryToPerform:@selector(insertNewline:) with:sender];
3024 }
3025
3026 - (void)insertParagraphSeparator:(id)sender
3027 {
3028     if ([self _currentSelectionIsEditable]) {
3029         ERROR("unimplemented");
3030         return;
3031     }
3032     [[self nextResponder] tryToPerform:@selector(insertParagraphSeparator:) with:sender];
3033 }
3034
3035
3036     /* Case changes */
3037
3038 - (void)changeCaseOfLetter:(id)sender
3039 {
3040     if ([self _currentSelectionIsEditable]) {
3041         ERROR("unimplemented");
3042         return;
3043     }
3044     [[self nextResponder] tryToPerform:@selector(changeCaseOfLetter:) with:sender];
3045 }
3046
3047 - (void)uppercaseWord:(id)sender
3048 {
3049     if ([self _currentSelectionIsEditable]) {
3050         ERROR("unimplemented");
3051         return;
3052     }
3053     [[self nextResponder] tryToPerform:@selector(uppercaseWord:) with:sender];
3054 }
3055
3056 - (void)lowercaseWord:(id)sender
3057 {
3058     if ([self _currentSelectionIsEditable]) {
3059         ERROR("unimplemented");
3060         return;
3061     }
3062     [[self nextResponder] tryToPerform:@selector(lowercaseWord:) with:sender];
3063 }
3064
3065 - (void)capitalizeWord:(id)sender
3066 {
3067     if ([self _currentSelectionIsEditable]) {
3068         ERROR("unimplemented");
3069         return;
3070     }
3071     [[self nextResponder] tryToPerform:@selector(capitalizeWord:) with:sender];
3072 }
3073
3074
3075     /* Deletions */
3076
3077 - (void)deleteForward:(id)sender
3078 {
3079     if ([self _currentSelectionIsEditable]) {
3080         ERROR("unimplemented");
3081         return;
3082     }
3083     [[self nextResponder] tryToPerform:@selector(deleteForward:) with:sender];
3084 }
3085
3086 - (void)deleteBackward:(id)sender
3087 {
3088     if ([self _currentSelectionIsEditable]) {
3089         WebBridge *bridge = [self _bridgeForCurrentSelection];
3090         if ([[self _editingDelegateForwarder] webView:self shouldDeleteDOMRange:[self selectedDOMRange]]) {
3091             [bridge deleteKeyPressed];
3092             [bridge ensureCaretVisible];
3093         }
3094         return;
3095     }
3096     [[self nextResponder] tryToPerform:@selector(deleteBackward:) with:sender];
3097 }
3098
3099 - (void)deleteBackwardByDecomposingPreviousCharacter:(id)sender
3100 {
3101     if ([self _currentSelectionIsEditable]) {
3102         ERROR("unimplemented");
3103         return;
3104     }
3105     [[self nextResponder] tryToPerform:@selector(deleteBackwardByDecomposingPreviousCharacter:) with:sender];
3106 }
3107
3108 - (void)deleteWordForward:(id)sender
3109 {
3110     if ([self _currentSelectionIsEditable]) {
3111         ERROR("unimplemented");
3112         return;
3113     }
3114     [[self nextResponder] tryToPerform:@selector(deleteWordForward:) with:sender];
3115 }
3116
3117 - (void)deleteWordBackward:(id)sender
3118 {
3119     if ([self _currentSelectionIsEditable]) {
3120         ERROR("unimplemented");
3121         return;
3122     }
3123     [[self nextResponder] tryToPerform:@selector(deleteWordBackward:) with:sender];
3124 }
3125
3126 - (void)deleteToBeginningOfLine:(id)sender
3127 {
3128     if ([self _currentSelectionIsEditable]) {
3129         ERROR("unimplemented");
3130         return;
3131     }
3132     [[self nextResponder] tryToPerform:@selector(deleteToBeginningOfLine:) with:sender];
3133 }
3134
3135 - (void)deleteToEndOfLine:(id)sender
3136 {
3137     if ([self _currentSelectionIsEditable]) {
3138         ERROR("unimplemented");
3139         return;
3140     }
3141     [[self nextResponder] tryToPerform:@selector(deleteToEndOfLine:) with:sender];
3142 }
3143
3144 - (void)deleteToBeginningOfParagraph:(id)sender
3145 {
3146     if ([self _currentSelectionIsEditable]) {
3147         ERROR("unimplemented");
3148         return;
3149     }
3150     [[self nextResponder] tryToPerform:@selector(deleteToBeginningOfParagraph:) with:sender];
3151 }
3152
3153 - (void)deleteToEndOfParagraph:(id)sender
3154 {
3155     if ([self _currentSelectionIsEditable]) {
3156         ERROR("unimplemented");
3157         return;
3158     }
3159     [[self nextResponder] tryToPerform:@selector(deleteToEndOfParagraph:) with:sender];
3160 }
3161
3162
3163     /* Completion */
3164
3165 - (void)complete:(id)sender
3166 {
3167     if ([self _currentSelectionIsEditable]) {
3168         ERROR("unimplemented");
3169         return;
3170     }
3171     [[self nextResponder] tryToPerform:@selector(complete:) with:sender];
3172 }
3173
3174
3175     /* Spelling */
3176
3177 - (void)checkSpelling:(id)sender
3178 {
3179     if ([self _currentSelectionIsEditable]) {
3180         ERROR("unimplemented");
3181         return;
3182     }
3183     [[self nextResponder] tryToPerform:@selector(checkSpelling:) with:sender];
3184 }
3185
3186 - (void)showGuessPanel:(id)sender
3187 {
3188     if ([self _currentSelectionIsEditable]) {
3189         ERROR("unimplemented");
3190         return;
3191     }
3192     [[self nextResponder] tryToPerform:@selector(showGuessPanel:) with:sender];
3193 }
3194
3195
3196     /* Finding */
3197     
3198 - (void)performFindPanelAction:(id)sender
3199 {
3200     if ([self _currentSelectionIsEditable]) {
3201         ERROR("unimplemented");
3202         return;
3203     }
3204     [[self nextResponder] tryToPerform:@selector(performFindPanelAction:) with:sender];
3205 }
3206
3207
3208         /* Speech */
3209
3210 - (void)startSpeaking:(id)sender
3211 {
3212     if ([self _currentSelectionIsEditable]) {
3213         ERROR("unimplemented");
3214         return;
3215     }
3216     [[self nextResponder] tryToPerform:@selector(startSpeaking:) with:sender];
3217 }
3218
3219 - (void)stopSpeaking:(id)sender
3220 {
3221     if ([self _currentSelectionIsEditable]) {
3222         ERROR("unimplemented");
3223         return;
3224     }
3225     [[self nextResponder] tryToPerform:@selector(stopSpeaking:) with:sender];
3226 }
3227
3228         /* Text input */
3229
3230 - (void)insertText:(NSString *)text
3231 {
3232     if ([self _currentSelectionIsEditable]) {
3233         WebBridge *bridge = [self _bridgeForCurrentSelection];
3234         if ([[self _editingDelegateForwarder] webView:self shouldInsertText:text replacingDOMRange:[self selectedDOMRange] givenAction:WebViewInsertActionTyped]) {
3235             [bridge replaceSelectionWithText:text];
3236             [bridge ensureCaretVisible];
3237         }
3238         return;
3239     }
3240     [[self nextResponder] tryToPerform:@selector(insertText:) with:text];
3241 }
3242
3243 @end
3244
3245 @implementation WebView (JavaScriptBinding)
3246 - (void)_bindObject:(id)object withName:(NSString *)name toFrame:(WebFrame *)frame
3247 {
3248     if (!frame)
3249         [[[self mainFrame] _bridge] bindObject:object withName:name];
3250     else {
3251         [[frame _bridge] bindObject:object withName:name];
3252     }
3253 }
3254 @end