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