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