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