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