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