Reviewed by Geoff.
[WebKit-https.git] / WebKit / WebView / WebView.m
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebViewInternal.h"
30
31 #import <JavaScriptCore/Assertions.h>
32 #import "WebBackForwardList.h"
33 #import "WebBaseNetscapePluginView.h"
34 #import "WebDOMOperationsPrivate.h"
35 #import "WebDashboardRegion.h"
36 #import "WebDataProtocol.h"
37 #import "WebDataSourceInternal.h"
38 #import "WebDefaultEditingDelegate.h"
39 #import "WebDefaultFrameLoadDelegate.h"
40 #import "WebDefaultPolicyDelegate.h"
41 #import "WebDefaultResourceLoadDelegate.h"
42 #import "WebDefaultScriptDebugDelegate.h"
43 #import "WebDefaultUIDelegate.h"
44 #import "WebDocument.h"
45 #import "WebDocumentInternal.h"
46 #import "WebDownload.h"
47 #import "WebDownloadInternal.h"
48 #import "WebDynamicScrollBarsView.h"
49 #import "WebEditingDelegate.h"
50 #import "WebFormDelegatePrivate.h"
51 #import "WebFrameBridge.h"
52 #import "WebFrameInternal.h"
53 #import "WebFramePrivate.h"
54 #import "WebFrameViewInternal.h"
55 #import "WebHTMLRepresentation.h"
56 #import "WebHTMLViewInternal.h"
57 #import "WebHistoryItemPrivate.h"
58 #import "WebIconDatabase.h"
59 #import "WebInspector.h"
60 #import "WebKitErrors.h"
61 #import "WebKitLogging.h"
62 #import "WebKitNSStringExtras.h"
63 #import "WebKitStatisticsPrivate.h"
64 #import "WebLocalizableStrings.h"
65 #import "WebNSDataExtras.h"
66 #import "WebNSDataExtrasPrivate.h"
67 #import "WebNSDictionaryExtras.h"
68 #import "WebNSEventExtras.h"
69 #import "WebNSObjectExtras.h"
70 #import "WebNSPasteboardExtras.h"
71 #import "WebNSPrintOperationExtras.h"
72 #import "WebNSURLExtras.h"
73 #import "WebNSURLRequestExtras.h"
74 #import "WebNSUserDefaultsExtras.h"
75 #import "WebNSViewExtras.h"
76 #import "WebPageBridge.h"
77 #import "WebPluginDatabase.h"
78 #import "WebPolicyDelegate.h"
79 #import "WebPreferencesPrivate.h"
80 #import "WebResourceLoadDelegate.h"
81 #import "WebScriptDebugDelegatePrivate.h"
82 #import "WebScriptDebugServerPrivate.h"
83 #import "WebUIDelegate.h"
84 #import "WebUIDelegatePrivate.h"
85 #import <CoreFoundation/CFSet.h>
86 #import <Foundation/NSURLConnection.h>
87 #import <WebCore/WebCoreEncodings.h>
88 #import <WebCore/WebCoreFrameBridge.h>
89 #import <WebCore/WebCoreSettings.h>
90 #import <WebCore/WebCoreView.h>
91 #import <WebKit/DOM.h>
92 #import <WebKit/DOMPrivate.h>
93 #import <WebKit/DOMExtensions.h>
94 #import <WebKitSystemInterface.h>
95 #import <objc/objc-runtime.h>
96
97 #import <WebCore/WebCoreTextRenderer.h>
98
99 #if __ppc__ || __ppc64__
100 #define PROCESSOR "PPC"
101 #elif __i386__ || __x86_64__
102 #define PROCESSOR "Intel"
103 #else
104 #error Unknown architecture
105 #endif
106
107 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
108 macro(alignCenter) \
109 macro(alignJustified) \
110 macro(alignLeft) \
111 macro(alignRight) \
112 macro(capitalizeWord) \
113 macro(centerSelectionInVisibleArea) \
114 macro(changeAttributes) \
115 macro(changeColor) \
116 macro(changeDocumentBackgroundColor) \
117 macro(changeFont) \
118 macro(checkSpelling) \
119 macro(complete) \
120 macro(copy) \
121 macro(copyFont) \
122 macro(cut) \
123 macro(delete) \
124 macro(deleteBackward) \
125 macro(deleteBackwardByDecomposingPreviousCharacter) \
126 macro(deleteForward) \
127 macro(deleteToBeginningOfLine) \
128 macro(deleteToBeginningOfParagraph) \
129 macro(deleteToEndOfLine) \
130 macro(deleteToEndOfParagraph) \
131 macro(deleteWordBackward) \
132 macro(deleteWordForward) \
133 macro(ignoreSpelling) \
134 macro(indent) \
135 macro(insertBacktab) \
136 macro(insertNewline) \
137 macro(insertNewlineIgnoringFieldEditor) \
138 macro(insertParagraphSeparator) \
139 macro(insertTab) \
140 macro(insertTabIgnoringFieldEditor) \
141 macro(lowercaseWord) \
142 macro(moveBackward) \
143 macro(moveBackwardAndModifySelection) \
144 macro(moveDown) \
145 macro(moveDownAndModifySelection) \
146 macro(moveForward) \
147 macro(moveForwardAndModifySelection) \
148 macro(moveLeft) \
149 macro(moveLeftAndModifySelection) \
150 macro(moveRight) \
151 macro(moveRightAndModifySelection) \
152 macro(moveToBeginningOfDocument) \
153 macro(moveToBeginningOfDocumentAndModifySelection) \
154 macro(moveToBeginningOfSentence) \
155 macro(moveToBeginningOfSentenceAndModifySelection) \
156 macro(moveToBeginningOfLine) \
157 macro(moveToBeginningOfLineAndModifySelection) \
158 macro(moveToBeginningOfParagraph) \
159 macro(moveToBeginningOfParagraphAndModifySelection) \
160 macro(moveToEndOfDocument) \
161 macro(moveToEndOfDocumentAndModifySelection) \
162 macro(moveToEndOfLine) \
163 macro(moveToEndOfLineAndModifySelection) \
164 macro(moveToEndOfParagraph) \
165 macro(moveToEndOfParagraphAndModifySelection) \
166 macro(moveToEndOfSentence) \
167 macro(moveToEndOfSentenceAndModifySelection) \
168 macro(moveUp) \
169 macro(moveUpAndModifySelection) \
170 macro(moveWordBackward) \
171 macro(moveWordBackwardAndModifySelection) \
172 macro(moveWordForward) \
173 macro(moveWordForwardAndModifySelection) \
174 macro(moveWordLeft) \
175 macro(moveWordLeftAndModifySelection) \
176 macro(moveWordRight) \
177 macro(moveWordRightAndModifySelection) \
178 macro(pageDown) \
179 macro(pageUp) \
180 macro(paste) \
181 macro(pasteAsPlainText) \
182 macro(pasteAsRichText) \
183 macro(pasteFont) \
184 macro(performFindPanelAction) \
185 macro(scrollLineDown) \
186 macro(scrollLineUp) \
187 macro(scrollPageDown) \
188 macro(scrollPageUp) \
189 macro(scrollToBeginningOfDocument) \
190 macro(scrollToEndOfDocument) \
191 macro(selectAll) \
192 macro(selectWord) \
193 macro(selectSentence) \
194 macro(selectLine) \
195 macro(selectParagraph) \
196 macro(showGuessPanel) \
197 macro(startSpeaking) \
198 macro(stopSpeaking) \
199 macro(subscript) \
200 macro(superscript) \
201 macro(underline) \
202 macro(unscript) \
203 macro(uppercaseWord) \
204 macro(yank) \
205 macro(yankAndSelect) \
206
207 @interface NSSpellChecker (AppKitSecretsIKnow)
208 - (void)_preflightChosenSpellServer;
209 @end
210
211 @interface NSView (AppKitSecretsIKnow)
212 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
213 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
214 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
215 @end
216
217 @interface WebViewPrivate : NSObject
218 {
219 @public
220     WebPageBridge *_pageBridge;
221     
222     id UIDelegate;
223     id UIDelegateForwarder;
224     id resourceProgressDelegate;
225     id resourceProgressDelegateForwarder;
226     id downloadDelegate;
227     id policyDelegate;
228     id policyDelegateForwarder;
229     id frameLoadDelegate;
230     id frameLoadDelegateForwarder;
231     id <WebFormDelegate> formDelegate;
232     id editingDelegate;
233     id editingDelegateForwarder;
234     id scriptDebugDelegate;
235     id scriptDebugDelegateForwarder;
236     
237     WebBackForwardList *backForwardList;
238     BOOL useBackForwardList;
239     
240     float textSizeMultiplier;
241
242     NSString *applicationNameForUserAgent;
243     NSString *userAgent;
244     BOOL userAgentOverridden;
245     
246     BOOL defersCallbacks;
247
248     WebPreferences *preferences;
249     WebCoreSettings *settings;
250         
251     BOOL lastElementWasNonNil;
252
253     NSWindow *hostWindow;
254
255     int programmaticFocusCount;
256     
257     WebResourceDelegateImplementationCache resourceLoadDelegateImplementations;
258
259     long long totalPageAndResourceBytesToLoad;
260     long long totalBytesReceived;
261     double progressValue;
262     double lastNotifiedProgressValue;
263     double lastNotifiedProgressTime;
264     double progressNotificationInterval;
265     double progressNotificationTimeInterval;
266     BOOL finalProgressChangedSent;
267     WebFrame *originatingProgressFrame;
268     
269     int numProgressTrackedFrames;
270     NSMutableDictionary *progressItems;
271     
272     void *observationInfo;
273     
274     BOOL mainFrameDocumentReady;
275     BOOL drawsBackground;
276     BOOL editable;
277     BOOL initiatedDrag;
278         
279     NSString *mediaStyle;
280     
281     NSView <WebDocumentDragging> *draggingDocumentView;
282     unsigned int dragDestinationActionMask;
283     
284     BOOL hasSpellCheckerDocumentTag;
285     WebNSInteger spellCheckerDocumentTag;
286
287     BOOL continuousSpellCheckingEnabled;
288     BOOL smartInsertDeleteEnabled;
289     
290     BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
291     BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
292     BOOL dashboardBehaviorAlwaysAcceptsFirstMouse;
293     BOOL dashboardBehaviorAllowWheelScrolling;
294     
295     BOOL selectWordBeforeMenuEvent;
296     
297     WebPluginDatabase *pluginDatabase;
298 }
299 @end
300
301 @interface WebView (WebFileInternal)
302 - (WebFrame *)_selectedOrMainFrame;
303 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame;
304 - (BOOL)_isLoading;
305 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
306 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point;
307 - (WebFrame *)_focusedFrame;
308 + (void)_preflightSpellChecker;
309 - (BOOL)_continuousCheckingAllowed;
310 - (NSResponder *)_responderForResponderOperations;
311 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor;
312 @end
313
314 NSString *WebElementDOMNodeKey =            @"WebElementDOMNode";
315 NSString *WebElementFrameKey =              @"WebElementFrame";
316 NSString *WebElementImageKey =              @"WebElementImage";
317 NSString *WebElementImageAltStringKey =     @"WebElementImageAltString";
318 NSString *WebElementImageRectKey =          @"WebElementImageRect";
319 NSString *WebElementImageURLKey =           @"WebElementImageURL";
320 NSString *WebElementIsSelectedKey =         @"WebElementIsSelected";
321 NSString *WebElementTitleKey =              @"WebElementTitle";
322 NSString *WebElementLinkURLKey =            @"WebElementLinkURL";
323 NSString *WebElementLinkTargetFrameKey =    @"WebElementTargetFrame";
324 NSString *WebElementLinkLabelKey =          @"WebElementLinkLabel";
325 NSString *WebElementLinkTitleKey =          @"WebElementLinkTitle";
326
327 NSString *WebViewProgressStartedNotification =          @"WebProgressStartedNotification";
328 NSString *WebViewProgressEstimateChangedNotification =  @"WebProgressEstimateChangedNotification";
329 NSString *WebViewProgressFinishedNotification =         @"WebProgressFinishedNotification";
330
331 NSString * const WebViewDidBeginEditingNotification =         @"WebViewDidBeginEditingNotification";
332 NSString * const WebViewDidChangeNotification =               @"WebViewDidChangeNotification";
333 NSString * const WebViewDidEndEditingNotification =           @"WebViewDidEndEditingNotification";
334 NSString * const WebViewDidChangeTypingStyleNotification =    @"WebViewDidChangeTypingStyleNotification";
335 NSString * const WebViewDidChangeSelectionNotification =      @"WebViewDidChangeSelectionNotification";
336
337 enum { WebViewVersion = 2 };
338
339 #define timedLayoutSize 4096
340
341 static NSMutableSet *schemesWithRepresentationsSet;
342
343 NSString *_WebCanGoBackKey =            @"canGoBack";
344 NSString *_WebCanGoForwardKey =         @"canGoForward";
345 NSString *_WebEstimatedProgressKey =    @"estimatedProgress";
346 NSString *_WebIsLoadingKey =            @"isLoading";
347 NSString *_WebMainFrameIconKey =        @"mainFrameIcon";
348 NSString *_WebMainFrameTitleKey =       @"mainFrameTitle";
349 NSString *_WebMainFrameURLKey =         @"mainFrameURL";
350 NSString *_WebMainFrameDocumentKey =    @"mainFrameDocument";
351
352 @interface WebProgressItem : NSObject
353 {
354 @public
355     long long bytesReceived;
356     long long estimatedLength;
357 }
358 @end
359
360 @implementation WebProgressItem
361 @end
362
363 @implementation WebViewPrivate
364
365 - init 
366 {
367     self = [super init];
368     if (!self)
369         return nil;
370     
371     backForwardList = [[WebBackForwardList alloc] init];
372     textSizeMultiplier = 1;
373     progressNotificationInterval = 0.02;
374     progressNotificationTimeInterval = 0.1;
375     settings = [[WebCoreSettings alloc] init];
376     dashboardBehaviorAllowWheelScrolling = YES;
377
378     return self;
379 }
380
381 - (void)dealloc
382 {
383     ASSERT(!_pageBridge);
384     ASSERT(draggingDocumentView == nil);
385     
386     [backForwardList release];
387     [applicationNameForUserAgent release];
388     [userAgent release];
389     
390     [preferences release];
391     [settings release];
392     [hostWindow release];
393     
394     [policyDelegateForwarder release];
395     [resourceProgressDelegateForwarder release];
396     [UIDelegateForwarder release];
397     [frameLoadDelegateForwarder release];
398     [editingDelegateForwarder release];
399     [scriptDebugDelegateForwarder release];
400     
401     [progressItems release];
402         
403     [mediaStyle release];
404     
405     [super dealloc];
406 }
407
408 @end
409
410 @implementation WebView (AllWebViews)
411
412 static CFSetCallBacks NonRetainingSetCallbacks = {
413     0,
414     NULL,
415     NULL,
416     CFCopyDescription,
417     CFEqual,
418     CFHash
419 };
420
421 static CFMutableSetRef allWebViewsSet;
422
423 + (void)_makeAllWebViewsPerformSelector:(SEL)selector
424 {
425     if (!allWebViewsSet)
426         return;
427
428     [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
429 }
430
431 - (void)_removeFromAllWebViewsSet
432 {
433     if (allWebViewsSet)
434         CFSetRemoveValue(allWebViewsSet, self);
435 }
436
437 - (void)_addToAllWebViewsSet
438 {
439     if (!allWebViewsSet)
440         allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
441
442     CFSetSetValue(allWebViewsSet, self);
443 }
444
445 @end
446
447 @implementation WebView (WebPrivate)
448
449 #ifdef DEBUG_WIDGET_DRAWING
450 static bool debugWidget = true;
451 - (void)drawRect:(NSRect)rect
452 {
453     [[NSColor blueColor] set];
454     NSRectFill (rect);
455     
456     NSRect htmlViewRect = [[[[self mainFrame] frameView] documentView] frame];
457
458     if (debugWidget) {
459         while (debugWidget) {
460             sleep (1);
461         }
462     }
463
464     NSLog (@"%s:   rect:  (%0.f,%0.f) %0.f %0.f, htmlViewRect:  (%0.f,%0.f) %0.f %0.f\n", 
465         __PRETTY_FUNCTION__, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
466         htmlViewRect.origin.x, htmlViewRect.origin.y, htmlViewRect.size.width, htmlViewRect.size.height
467         );
468
469     [super drawRect:rect];
470 }
471 #endif
472
473 + (BOOL)_developerExtrasEnabled
474 {
475 #ifdef NDEBUG
476     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
477     BOOL enableDebugger = [defaults boolForKey:@"WebKitDeveloperExtras"];
478     if (!enableDebugger)
479         enableDebugger = [defaults boolForKey:@"IncludeDebugMenu"];
480     return enableDebugger;
481 #else
482     return YES; // always enable in debug builds
483 #endif
484 }
485
486 + (BOOL)_scriptDebuggerEnabled
487 {
488 #ifdef NDEBUG
489     return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitScriptDebuggerEnabled"];
490 #else
491     return YES; // always enable in debug builds
492 #endif
493 }
494
495 + (NSArray *)_supportedMIMETypes
496 {
497     // Load the plug-in DB allowing plug-ins to install types.
498     [WebPluginDatabase installedPlugins];
499     return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
500 }
501
502 + (NSArray *)_supportedFileExtensions
503 {
504     NSMutableSet *extensions = [[NSMutableSet alloc] init];
505     NSArray *MIMETypes = [self _supportedMIMETypes];
506     NSEnumerator *enumerator = [MIMETypes objectEnumerator];
507     NSString *MIMEType;
508     while ((MIMEType = [enumerator nextObject]) != nil) {
509         NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
510         if (extensionsForType) {
511             [extensions addObjectsFromArray:extensionsForType];
512         }
513     }
514     NSArray *uniqueExtensions = [extensions allObjects];
515     [extensions release];
516     return uniqueExtensions;
517 }
518
519 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
520 {
521     MIMEType = [MIMEType lowercaseString];
522     Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
523     Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
524     
525     if (!viewClass || !repClass) {
526         // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
527         // Load the plug-in DB allowing plug-ins to install types.
528         [WebPluginDatabase installedPlugins];
529             
530         // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
531         viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
532         repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
533     }
534     
535     if (viewClass && repClass) {
536         // Special-case WebHTMLView for text types that shouldn't be shown.
537         if (viewClass == [WebHTMLView class] &&
538             repClass == [WebHTMLRepresentation class] &&
539             [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) {
540             return NO;
541         }
542         if (vClass)
543             *vClass = viewClass;
544         if (rClass)
545             *rClass = repClass;
546         return YES;
547     }
548     
549     return NO;
550 }
551
552 - (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
553 {
554     if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType])
555         return YES;
556
557     if (_private->pluginDatabase) {
558         WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
559         if (pluginPackage) {
560             if (vClass)
561                 *vClass = [WebHTMLView class];
562             if (rClass)
563                 *rClass = [WebHTMLRepresentation class];
564             return YES;
565         }
566     }
567     
568     return NO;
569 }
570
571 + (void)_setAlwaysUseATSU:(BOOL)f
572 {
573     WebCoreSetAlwaysUseATSU(f);
574 }
575
576 + (BOOL)canShowFile:(NSString *)path
577 {
578     return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
579 }
580
581 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
582 {
583     return WKGetPreferredExtensionForMIMEType(type);
584 }
585
586 - (void)_close
587 {
588     [self _removeFromAllWebViewsSet];
589     [self setGroupName:nil];
590
591     // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
592     [self removeDragCaret];
593     
594     [[self mainFrame] _detachFromParent];
595     [_private->_pageBridge release];
596     _private->_pageBridge = nil;
597     
598     // Clear the page cache so we call destroy on all the plug-ins in the page cache to break any retain cycles.
599     // See comment in [WebHistoryItem _releaseAllPendingPageCaches] for more information.
600     [_private->backForwardList _clearPageCache];
601     
602     if (_private->hasSpellCheckerDocumentTag) {
603         [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
604         _private->hasSpellCheckerDocumentTag = NO;
605     }
606     
607     if (_private->pluginDatabase) {
608         [_private->pluginDatabase close];
609         [_private->pluginDatabase release];
610         _private->pluginDatabase = nil;
611     }
612 }
613
614 + (NSString *)_MIMETypeForFile:(NSString *)path
615 {
616     NSString *extension = [path pathExtension];
617     NSString *MIMEType = nil;
618
619     // Get the MIME type from the extension.
620     if ([extension length] != 0) {
621         MIMEType = WKGetMIMETypeForExtension(extension);
622     }
623
624     // If we can't get a known MIME type from the extension, sniff.
625     if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
626         NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
627         NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
628         [handle closeFile];
629         if ([data length] != 0) {
630             MIMEType = [data _webkit_guessedMIMEType];
631         }
632         if ([MIMEType length] == 0) {
633             MIMEType = @"application/octet-stream";
634         }
635     }
636
637     return MIMEType;
638 }
639
640 - (void)_downloadURL:(NSURL *)URL
641 {
642     ASSERT(URL);
643     
644     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
645     [WebDownload _downloadWithRequest:request
646                              delegate:_private->downloadDelegate
647                             directory:nil];
648     [request release];
649 }
650
651 - (BOOL)defersCallbacks
652 {
653     return _private->defersCallbacks;
654 }
655
656 - (void)setDefersCallbacks:(BOOL)defers
657 {
658     if (defers == _private->defersCallbacks) {
659         return;
660     }
661
662     _private->defersCallbacks = defers;
663     [[self mainFrame] _defersCallbacksChanged];
664 }
665
666 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
667 {
668     id wd = [self UIDelegate];
669     WebView *newWindowWebView = nil;
670     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
671         newWindowWebView = [wd webView:self createWebViewWithRequest:request];
672     else {
673         newWindowWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:self createWebViewWithRequest: request];
674     }
675
676     [[newWindowWebView _UIDelegateForwarder] webViewShow: newWindowWebView];
677
678     return newWindowWebView;
679 }
680
681 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
682 {
683     NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate]
684           webView:self contextMenuItemsForElement:element defaultMenuItems:items];
685     NSArray *menuItems = defaultMenuItems;
686     NSMenu *menu = nil;
687     unsigned i;
688
689     DOMNode* node = [element objectForKey:WebElementDOMNodeKey];
690     BOOL elementIsTextField = [node isKindOfClass:[DOMHTMLInputElement class]] && [(DOMHTMLInputElement*)node _isTextField];
691     BOOL elementIsTextArea = [node isKindOfClass:[DOMHTMLTextAreaElement class]];
692     if (_private->UIDelegate && !elementIsTextField && !elementIsTextArea) {
693         id cd = _private->UIDelegate;
694         
695         if ([cd respondsToSelector:@selector(webView:contextMenuItemsForElement:defaultMenuItems:)]) {
696             menuItems = [cd webView:self contextMenuItemsForElement:element defaultMenuItems:defaultMenuItems];
697
698             // Versions of Mail compiled with older WebKits will end up without three context menu items, though
699             // with the separators between them. Here we check for that problem and reinsert the three missing
700             // items. This shouldn't affect any clients other than Mail since the tags for the three items
701             // were not public API. We can remove this code when we no longer support previously-built versions
702             // of Mail on Tiger. See 4498606 for more details.
703             if (([[defaultMenuItems objectAtIndex:0] tag] == WebMenuItemTagSearchInSpotlight) && ([[menuItems objectAtIndex:0] isSeparatorItem])) {
704                 ASSERT([[menuItems objectAtIndex:1] isSeparatorItem]);
705                 ASSERT([[defaultMenuItems objectAtIndex:1] tag] == WebMenuItemTagSearchWeb);
706                 ASSERT([[defaultMenuItems objectAtIndex:2] isSeparatorItem]);
707                 ASSERT([[defaultMenuItems objectAtIndex:3] tag] == WebMenuItemTagLookUpInDictionary);
708                 ASSERT([[defaultMenuItems objectAtIndex:4] isSeparatorItem]);
709                 NSMutableArray *mutableMenuItems = [NSMutableArray arrayWithArray:menuItems];
710                 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:0] atIndex:0];
711                 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:1] atIndex:1];
712                 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:3] atIndex:3];
713                 menuItems = mutableMenuItems;
714             }
715         }
716     } 
717
718     if (menuItems && [menuItems count] > 0) {
719         menu = [[[NSMenu alloc] init] autorelease];
720
721         for (i=0; i<[menuItems count]; i++) {
722             [menu addItem:[menuItems objectAtIndex:i]];
723         }
724     }
725
726     // optionally add the Inspect Element menu item it if preference is set or in debug builds
727     // and only showing the menu item if we are working with a WebHTMLView
728     WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
729     if ([WebView _developerExtrasEnabled] && [[[webFrame frameView] documentView] isKindOfClass:[WebHTMLView class]]) {
730         if (!menu)
731             menu = [[[NSMenu alloc] init] autorelease];
732         else if ([menu numberOfItems])
733             [menu addItem:[NSMenuItem separatorItem]];
734         NSMenuItem *menuItem = [[[NSMenuItem alloc] init] autorelease];
735         [menuItem setAction:@selector(_inspectElement:)];
736         [menuItem setTitle:UI_STRING("Inspect Element", "Inspect Element context menu item")];
737         [menuItem setRepresentedObject:element];
738         [menu addItem:menuItem];
739     }
740
741     return menu;
742 }
743
744 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(WebNSUInteger)modifierFlags
745 {
746     // When the mouse isn't over this view at all, we'll get called with a dictionary of nil over
747     // and over again. So it's a good idea to catch that here and not send multiple calls to the delegate
748     // for that case.
749     
750     if (dictionary && _private->lastElementWasNonNil) {
751         [[self _UIDelegateForwarder] webView:self mouseDidMoveOverElement:dictionary modifierFlags:modifierFlags];
752     }
753     _private->lastElementWasNonNil = dictionary != nil;
754 }
755
756 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
757 {
758     // We never go back/forward on a per-frame basis, so the target must be the main frame
759     //ASSERT([item target] == nil || [self _findFrameNamed:[item target]] == [self mainFrame]);
760
761     // abort any current load if we're going back/forward
762     [[self mainFrame] stopLoading];
763     [[self mainFrame] _goToItem:item withLoadType:type];
764 }
765
766 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
767 {
768     // It turns out the right combination of behavior is done with the back/forward load
769     // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
770     // in the back forward list, and go to the current one.
771
772     WebBackForwardList *bfList = [self backForwardList];
773     ASSERT(![bfList currentItem]);      // destination list should be empty
774
775     WebBackForwardList *otherBFList = [otherView backForwardList];
776     if (![otherBFList currentItem]) {
777         return;         // empty back forward list, bail
778     }
779
780     WebHistoryItem *newItemToGoTo = nil;
781     int lastItemIndex = [otherBFList forwardListCount];
782     int i;
783     for (i = -[otherBFList backListCount]; i <= lastItemIndex; i++) {
784         if (i == 0) {
785             // If this item is showing , save away its current scroll and form state,
786             // since that might have changed since loading and it is normally not saved
787             // until we leave that page.
788             [[otherView mainFrame] _saveDocumentAndScrollState];
789         }
790         WebHistoryItem *newItem = [[otherBFList itemAtIndex:i] copy];
791         [bfList addItem:newItem];
792         if (i == 0) {
793             newItemToGoTo = newItem;
794         }
795     }
796     
797     [self _goToItem:newItemToGoTo withLoadType:WebFrameLoadTypeIndexedBackForward];
798 }
799
800 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
801 {
802     _private->formDelegate = delegate;
803 }
804
805 - (id<WebFormDelegate>)_formDelegate
806 {
807     if (!_private->formDelegate) {
808         // create lazily, to give the client a chance to set one before we bother to alloc the shared one
809         _private->formDelegate = [WebFormDelegate _sharedWebFormDelegate];
810     }
811     return _private->formDelegate;
812 }
813
814 - (WebCoreSettings *)_settings
815 {
816     return _private->settings;
817 }
818
819 - (void)_updateWebCoreSettingsFromPreferences:(WebPreferences *)preferences
820 {
821     [_private->settings setCursiveFontFamily:[preferences cursiveFontFamily]];
822     [_private->settings setDefaultFixedFontSize:[preferences defaultFixedFontSize]];
823     [_private->settings setDefaultFontSize:[preferences defaultFontSize]];
824     [_private->settings setDefaultTextEncoding:[preferences defaultTextEncodingName]];
825     [_private->settings setFantasyFontFamily:[preferences fantasyFontFamily]];
826     [_private->settings setFixedFontFamily:[preferences fixedFontFamily]];
827     [_private->settings setJavaEnabled:[preferences isJavaEnabled]];
828     [_private->settings setJavaScriptEnabled:[preferences isJavaScriptEnabled]];
829     [_private->settings setJavaScriptCanOpenWindowsAutomatically:[preferences javaScriptCanOpenWindowsAutomatically]];
830     [_private->settings setMinimumFontSize:[preferences minimumFontSize]];
831     [_private->settings setMinimumLogicalFontSize:[preferences minimumLogicalFontSize]];
832     [_private->settings setPluginsEnabled:[preferences arePlugInsEnabled]];
833     [_private->settings setPrivateBrowsingEnabled:[preferences privateBrowsingEnabled]];
834     [_private->settings setSansSerifFontFamily:[preferences sansSerifFontFamily]];
835     [_private->settings setSerifFontFamily:[preferences serifFontFamily]];
836     [_private->settings setStandardFontFamily:[preferences standardFontFamily]];
837     [_private->settings setWillLoadImagesAutomatically:[preferences loadsImagesAutomatically]];
838
839     if ([preferences userStyleSheetEnabled]) {
840         [_private->settings setUserStyleSheetLocation:[[preferences userStyleSheetLocation] _web_originalDataAsString]];
841     } else {
842         [_private->settings setUserStyleSheetLocation:@""];
843     }
844     [_private->settings setShouldPrintBackgrounds:[preferences shouldPrintBackgrounds]];
845     [_private->settings setTextAreasAreResizable:[preferences textAreasAreResizable]];
846 }
847
848 - (void)_preferencesChangedNotification: (NSNotification *)notification
849 {
850     WebPreferences *preferences = (WebPreferences *)[notification object];
851     
852     ASSERT(preferences == [self preferences]);
853     if (!_private->userAgentOverridden) {
854         [_private->userAgent release];
855         _private->userAgent = nil;
856     }
857     [self _updateWebCoreSettingsFromPreferences: preferences];
858 }
859
860 - _frameLoadDelegateForwarder
861 {
862     if (!_private->frameLoadDelegateForwarder)
863         _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self frameLoadDelegate]  defaultTarget: [WebDefaultFrameLoadDelegate sharedFrameLoadDelegate] templateClass: [WebDefaultFrameLoadDelegate class]];
864     return _private->frameLoadDelegateForwarder;
865 }
866
867 - _resourceLoadDelegateForwarder
868 {
869     if (!_private->resourceProgressDelegateForwarder)
870         _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
871     return _private->resourceProgressDelegateForwarder;
872 }
873
874 - (void)_cacheResourceLoadDelegateImplementations
875 {
876     WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
877     id delegate = [self resourceLoadDelegate];
878
879     cache->delegateImplementsDidCancelAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:)];
880     cache->delegateImplementsDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)];
881     cache->delegateImplementsDidFinishLoadingFromDataSource = [delegate respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)];
882     cache->delegateImplementsDidReceiveContentLength = [delegate respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)];
883     cache->delegateImplementsDidReceiveResponse = [delegate respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)];
884     cache->delegateImplementsWillSendRequest = [delegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)];
885     cache->delegateImplementsIdentifierForRequest = [delegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)];
886 }
887
888 - (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
889 {
890     return _private->resourceLoadDelegateImplementations;
891 }
892
893 - _policyDelegateForwarder
894 {
895     if (!_private->policyDelegateForwarder)
896         _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
897     return _private->policyDelegateForwarder;
898 }
899
900 - _UIDelegateForwarder
901 {
902     if (!_private->UIDelegateForwarder)
903         _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self UIDelegate] defaultTarget: [WebDefaultUIDelegate sharedUIDelegate] templateClass: [WebDefaultUIDelegate class]];
904     return _private->UIDelegateForwarder;
905 }
906
907 - _editingDelegateForwarder
908 {
909     // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
910     // Not sure if that is a bug or not.
911     if (!_private)
912         return nil;
913     if (!_private->editingDelegateForwarder)
914         _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self editingDelegate] defaultTarget: [WebDefaultEditingDelegate sharedEditingDelegate] templateClass: [WebDefaultEditingDelegate class]];
915     return _private->editingDelegateForwarder;
916 }
917
918 - _scriptDebugDelegateForwarder
919 {
920     if (!_private->scriptDebugDelegateForwarder)
921         _private->scriptDebugDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self scriptDebugDelegate] defaultTarget: [WebDefaultScriptDebugDelegate sharedScriptDebugDelegate] templateClass: [WebDefaultScriptDebugDelegate class]];
922     return _private->scriptDebugDelegateForwarder;
923 }
924
925 - (void)_closeWindow
926 {
927     [[self _UIDelegateForwarder] webViewClose:self];
928 }
929
930 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
931 {
932     [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
933     [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
934 }
935
936 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
937 {
938     NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
939     [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
940
941     // This is used to make _representationExistsForURLScheme faster.
942     // Without this set, we'd have to create the MIME type each time.
943     if (schemesWithRepresentationsSet == nil) {
944         schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
945     }
946     [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
947 }
948
949 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
950 {
951     return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
952 }
953
954 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
955 {
956     return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
957 }
958
959 + (BOOL)_canHandleRequest:(NSURLRequest *)request
960 {
961     if ([NSURLConnection canHandleRequest:request]) {
962         return YES;
963     }
964     
965     // We're always willing to load alternate content for unreachable URLs
966     if ([request _webDataRequestUnreachableURL]) {
967         return YES;
968     }
969
970     return [self _representationExistsForURLScheme:[[request URL] scheme]];
971 }
972
973 + (NSString *)_decodeData:(NSData *)data
974 {
975     return [WebCoreEncodings decodeData:data];
976 }
977
978 - (void)_pushPerformingProgrammaticFocus
979 {
980     _private->programmaticFocusCount++;
981 }
982
983 - (void)_popPerformingProgrammaticFocus
984 {
985     _private->programmaticFocusCount--;
986 }
987
988 - (BOOL)_isPerformingProgrammaticFocus
989 {
990     return _private->programmaticFocusCount != 0;
991 }
992
993 #define UnknownTotalBytes -1
994 #define WebProgressItemDefaultEstimatedLength 1024*16
995
996 - (void)_didChangeValueForKey: (NSString *)key
997 {
998     LOG (Bindings, "calling didChangeValueForKey: %@", key);
999     [self didChangeValueForKey: key];
1000 }
1001
1002 - (void)_willChangeValueForKey: (NSString *)key
1003 {
1004     LOG (Bindings, "calling willChangeValueForKey: %@", key);
1005     [self willChangeValueForKey: key];
1006 }
1007
1008 // Always start progress at INITIAL_PROGRESS_VALUE. This helps provide feedback as 
1009 // soon as a load starts.
1010 #define INITIAL_PROGRESS_VALUE 0.1
1011 // Similarly, always leave space at the end. This helps show the user that we're not done
1012 // until we're done.
1013 #define FINAL_PROGRESS_VALUE 1.0 - INITIAL_PROGRESS_VALUE
1014
1015 - (void)_resetProgress
1016 {
1017     [_private->progressItems release];
1018     _private->progressItems = nil;
1019     _private->totalPageAndResourceBytesToLoad = 0;
1020     _private->totalBytesReceived = 0;
1021     _private->progressValue = 0;
1022     _private->lastNotifiedProgressValue = 0;
1023     _private->lastNotifiedProgressTime = 0;
1024     _private->finalProgressChangedSent = NO;
1025     _private->numProgressTrackedFrames = 0;
1026     [_private->originatingProgressFrame release];
1027     _private->originatingProgressFrame = nil;
1028 }
1029 - (void)_progressStarted:(WebFrame *)frame
1030 {
1031     LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1032     [self _willChangeValueForKey: @"estimatedProgress"];
1033     if (_private->numProgressTrackedFrames == 0 || _private->originatingProgressFrame == frame){
1034         [self _resetProgress];
1035         _private->progressValue = INITIAL_PROGRESS_VALUE;
1036         _private->originatingProgressFrame = [frame retain];
1037         [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:self];
1038     }
1039     _private->numProgressTrackedFrames++;
1040     [self _didChangeValueForKey: @"estimatedProgress"];
1041 }
1042
1043 - (void)_finalProgressComplete
1044 {
1045     LOG (Progress, "");
1046
1047     // Before resetting progress value be sure to send client a least one notification
1048     // with final progress value.
1049     if (!_private->finalProgressChangedSent) {
1050         _private->progressValue = 1;
1051         [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1052     }
1053     
1054     [self _resetProgress];
1055     
1056     [self setMainFrameDocumentReady:YES];   // make sure this is turned on at this point
1057     [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:self];
1058 }
1059
1060 - (void)_progressCompleted:(WebFrame *)frame
1061 {    
1062     LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1063
1064     if (_private->numProgressTrackedFrames <= 0)
1065         return;
1066
1067     [self _willChangeValueForKey: @"estimatedProgress"];
1068
1069     _private->numProgressTrackedFrames--;
1070     if (_private->numProgressTrackedFrames == 0 ||
1071         (frame == _private->originatingProgressFrame && _private->numProgressTrackedFrames != 0)){
1072         [self _finalProgressComplete];
1073     }
1074     [self _didChangeValueForKey: @"estimatedProgress"];
1075 }
1076
1077 - (void)_incrementProgressForIdentifier:(id)identifier response:(NSURLResponse *)response;
1078 {
1079     if (!identifier)
1080         return;
1081
1082     LOG (Progress, "_private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1083     
1084     if (_private->numProgressTrackedFrames <= 0)
1085         return;
1086         
1087     WebProgressItem *item = [[WebProgressItem alloc] init];
1088
1089     if (!item)
1090         return;
1091
1092     long long length = [response expectedContentLength];
1093     if (length < 0){
1094         length = WebProgressItemDefaultEstimatedLength;
1095     }
1096     item->estimatedLength = length;
1097     _private->totalPageAndResourceBytesToLoad += length;
1098     
1099     if (!_private->progressItems)
1100         _private->progressItems = [[NSMutableDictionary alloc] init];
1101         
1102     [_private->progressItems _webkit_setObject:item forUncopiedKey:identifier];
1103     [item release];
1104 }
1105
1106 - (void)_incrementProgressForIdentifier:(id)identifier data:(NSData *)data
1107 {
1108     if (!identifier)
1109         return;
1110
1111     WebProgressItem *item = [_private->progressItems objectForKey:identifier];
1112
1113     if (!item)
1114         return;
1115
1116     [self _willChangeValueForKey: @"estimatedProgress"];
1117
1118     unsigned bytesReceived = [data length];
1119     double increment, percentOfRemainingBytes;
1120     long long remainingBytes, estimatedBytesForPendingRequests;
1121
1122     item->bytesReceived += bytesReceived;
1123     if (item->bytesReceived > item->estimatedLength){
1124         _private->totalPageAndResourceBytesToLoad += ((item->bytesReceived*2) - item->estimatedLength);
1125         item->estimatedLength = item->bytesReceived*2;
1126     }
1127     
1128     int numPendingOrLoadingRequests = [_private->originatingProgressFrame _numPendingOrLoadingRequests:YES];
1129     estimatedBytesForPendingRequests = WebProgressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
1130     remainingBytes = ((_private->totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - _private->totalBytesReceived);
1131     percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
1132
1133     // Treat the first layout as the half-way point.
1134     double maxProgressValue = [_private->originatingProgressFrame _firstLayoutDone]
1135         ? FINAL_PROGRESS_VALUE
1136         : .5;
1137     increment = (maxProgressValue - _private->progressValue) * percentOfRemainingBytes;
1138     _private->progressValue += increment;
1139     if (_private->progressValue > maxProgressValue)
1140         _private->progressValue = maxProgressValue;
1141     ASSERT(_private->progressValue >= INITIAL_PROGRESS_VALUE);
1142
1143     _private->totalBytesReceived += bytesReceived;
1144
1145     double now = CFAbsoluteTimeGetCurrent();
1146     double notifiedProgressTimeDelta = now - _private->lastNotifiedProgressTime;
1147     
1148     LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
1149     double notificationProgressDelta = _private->progressValue - _private->lastNotifiedProgressValue;
1150     if ((notificationProgressDelta >= _private->progressNotificationInterval ||
1151             notifiedProgressTimeDelta >= _private->progressNotificationTimeInterval) &&
1152             _private->numProgressTrackedFrames > 0) {
1153         if (!_private->finalProgressChangedSent) {
1154             if (_private->progressValue == 1)
1155                 _private->finalProgressChangedSent = YES;
1156             [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1157             _private->lastNotifiedProgressValue = _private->progressValue;
1158             _private->lastNotifiedProgressTime = now;
1159         }
1160     }
1161
1162     [self _didChangeValueForKey: @"estimatedProgress"];
1163 }
1164
1165 - (void)_completeProgressForIdentifier:(id)identifier
1166 {
1167     WebProgressItem *item = [_private->progressItems objectForKey:identifier];
1168
1169     if (!item)
1170         return;
1171         
1172     // Adjust the total expected bytes to account for any overage/underage.
1173     long long delta = item->bytesReceived - item->estimatedLength;
1174     _private->totalPageAndResourceBytesToLoad += delta;
1175     item->estimatedLength = item->bytesReceived;
1176 }
1177
1178 // Required to prevent automatic observer notifications.
1179 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1180     return NO;
1181 }
1182
1183 - (NSArray *)_declaredKeys {
1184     static NSArray *declaredKeys = nil;
1185     
1186     if (!declaredKeys) {
1187         declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1188     }
1189
1190     return declaredKeys;
1191 }
1192
1193 - (void)setObservationInfo:(void *)info
1194 {
1195     _private->observationInfo = info;
1196 }
1197
1198 - (void *)observationInfo
1199 {
1200     return _private->observationInfo;
1201 }
1202
1203 - (void)_willChangeBackForwardKeys
1204 {
1205     [self _willChangeValueForKey: _WebCanGoBackKey];
1206     [self _willChangeValueForKey: _WebCanGoForwardKey];
1207 }
1208
1209 - (void)_didChangeBackForwardKeys
1210 {
1211     [self _didChangeValueForKey: _WebCanGoBackKey];
1212     [self _didChangeValueForKey: _WebCanGoForwardKey];
1213 }
1214
1215 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1216 {
1217     [self _willChangeBackForwardKeys];
1218     if (frame == [self mainFrame]){
1219         // Force an observer update by sending a will/did.
1220         [self _willChangeValueForKey: _WebIsLoadingKey];
1221         [self _didChangeValueForKey: _WebIsLoadingKey];
1222
1223         [self _willChangeValueForKey: _WebMainFrameURLKey];
1224     }
1225     [NSApp setWindowsNeedUpdate:YES];
1226 }
1227
1228 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1229 {
1230     if (frame == [self mainFrame]){
1231         [self _didChangeValueForKey: _WebMainFrameURLKey];
1232     }
1233     [NSApp setWindowsNeedUpdate:YES];
1234 }
1235
1236 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1237 {
1238     [self _didChangeBackForwardKeys];
1239     if (frame == [self mainFrame]){
1240         // Force an observer update by sending a will/did.
1241         [self _willChangeValueForKey: _WebIsLoadingKey];
1242         [self _didChangeValueForKey: _WebIsLoadingKey];
1243     }
1244     [NSApp setWindowsNeedUpdate:YES];
1245 }
1246
1247 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1248 {
1249     [self _didChangeBackForwardKeys];
1250     if (frame == [self mainFrame]){
1251         // Force an observer update by sending a will/did.
1252         [self _willChangeValueForKey: _WebIsLoadingKey];
1253         [self _didChangeValueForKey: _WebIsLoadingKey];
1254     }
1255     [NSApp setWindowsNeedUpdate:YES];
1256 }
1257
1258 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1259 {
1260     [self _didChangeBackForwardKeys];
1261     if (frame == [self mainFrame]){
1262         // Force an observer update by sending a will/did.
1263         [self _willChangeValueForKey: _WebIsLoadingKey];
1264         [self _didChangeValueForKey: _WebIsLoadingKey];
1265         
1266         [self _didChangeValueForKey: _WebMainFrameURLKey];
1267     }
1268     [NSApp setWindowsNeedUpdate:YES];
1269 }
1270
1271 - (void)_reloadForPluginChanges
1272 {
1273     [[self mainFrame] _reloadForPluginChanges];
1274 }
1275
1276 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1277 {
1278     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1279     [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1280     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1281     [request release];
1282     return cachedResponse;
1283 }
1284
1285 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1286 {
1287     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1288     DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1289     [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
1290                         element:domElement
1291                             URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1292                           title:[element objectForKey:WebElementImageAltStringKey] 
1293                         archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1294                           types:types];
1295 }
1296
1297 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1298 {
1299     [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1300                      andTitle:[element objectForKey:WebElementLinkLabelKey]
1301                         types:types];
1302 }
1303
1304 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1305 {
1306     _private->initiatedDrag = initiatedDrag;
1307 }
1308
1309 #define DASHBOARD_CONTROL_LABEL @"control"
1310
1311 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1312 {
1313     // Add scroller regions for NSScroller and KWQScrollBar
1314     int i, count = [views count];
1315     
1316     for (i = 0; i < count; i++) {
1317         NSView *aView = [views objectAtIndex:i];
1318         
1319         if ([aView isKindOfClass:[NSScroller class]] ||
1320             [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1321             NSRect bounds = [aView bounds];
1322             NSRect adjustedBounds;
1323             adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1324             adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1325             
1326             // AppKit has horrible hack of placing absent scrollers at -100,-100
1327             if (adjustedBounds.origin.y == -100)
1328                 continue;
1329             adjustedBounds.size = bounds.size;
1330             NSRect clip = [aView visibleRect];
1331             NSRect adjustedClip;
1332             adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1333             adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1334             adjustedClip.size = clip.size;
1335             WebDashboardRegion *aRegion = 
1336                         [[[WebDashboardRegion alloc] initWithRect:adjustedBounds 
1337                                     clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1338             NSMutableArray *scrollerRegions;
1339             scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1340             if (!scrollerRegions) {
1341                 scrollerRegions = [NSMutableArray array];
1342                 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1343             }
1344             [scrollerRegions addObject:aRegion];
1345         }
1346         [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1347     }
1348 }
1349
1350 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1351 {
1352     [self _addScrollerDashboardRegions:regions from:[self subviews]];
1353 }
1354
1355 - (NSDictionary *)_dashboardRegions
1356 {
1357     // Only return regions from main frame.
1358     NSMutableDictionary *regions = [[[self mainFrame] _bridge] dashboardRegions];
1359     [self _addScrollerDashboardRegions:regions];
1360     return regions;
1361 }
1362
1363 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag;
1364 {
1365     switch (behavior) {
1366         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1367             _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1368             break;
1369         }
1370         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1371             _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1372             break;
1373         }
1374         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1375             _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1376             break;
1377         }
1378         case WebDashboardBehaviorAllowWheelScrolling: {
1379             _private->dashboardBehaviorAllowWheelScrolling = flag;
1380             break;
1381         }
1382     }
1383 }
1384
1385 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1386 {
1387     switch (behavior) {
1388         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1389             return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1390         }
1391         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1392             return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1393         }
1394         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1395             return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1396         }
1397         case WebDashboardBehaviorAllowWheelScrolling: {
1398             return _private->dashboardBehaviorAllowWheelScrolling;
1399         }
1400     }
1401     return NO;
1402 }
1403
1404 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
1405 {
1406     [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:self resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:dataSource];
1407 }
1408
1409 + (void)_setShouldUseFontSmoothing:(BOOL)f
1410 {
1411     WebCoreSetShouldUseFontSmoothing(f);
1412 }
1413
1414 + (BOOL)_shouldUseFontSmoothing
1415 {
1416     return WebCoreShouldUseFontSmoothing();
1417 }
1418
1419 + (NSString *)_minimumRequiredSafariBuildNumber
1420 {
1421     return @"420+";
1422 }
1423
1424 - (void)setAlwaysShowVerticalScroller:(BOOL)flag
1425 {
1426     WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1427     if (flag) {
1428         [scrollview setVerticalScrollingMode:WebCoreScrollBarAlwaysOn];
1429         [scrollview setVerticalScrollingModeLocked:YES];
1430     } else {
1431         [scrollview setVerticalScrollingModeLocked:NO];
1432         [scrollview setVerticalScrollingMode:WebCoreScrollBarAuto];
1433     }
1434 }
1435
1436 - (BOOL)alwaysShowVerticalScroller
1437 {
1438     WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1439     return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == WebCoreScrollBarAlwaysOn;
1440 }
1441
1442 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag
1443 {
1444     WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1445     if (flag) {
1446         [scrollview setHorizontalScrollingMode:WebCoreScrollBarAlwaysOn];
1447         [scrollview setHorizontalScrollingModeLocked:YES];
1448     } else {
1449         [scrollview setHorizontalScrollingModeLocked:NO];
1450         [scrollview setHorizontalScrollingMode:WebCoreScrollBarAuto];
1451     }
1452 }
1453
1454 - (BOOL)alwaysShowHorizontalScroller
1455 {
1456     WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1457     return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == WebCoreScrollBarAlwaysOn;
1458 }
1459
1460 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
1461 {
1462     if (!_private->pluginDatabase)
1463         _private->pluginDatabase = [[WebPluginDatabase alloc] init];
1464         
1465     [_private->pluginDatabase setPlugInPaths:newPaths];
1466     [_private->pluginDatabase refresh];
1467 }
1468
1469 - (void)_attachScriptDebuggerToAllFrames
1470 {
1471     WebFrame *frame = [self mainFrame];
1472     do {
1473         [frame _attachScriptDebugger];
1474         frame = [frame _nextFrameWithWrap:NO];
1475     } while (frame);
1476 }
1477
1478 - (void)_detachScriptDebuggerFromAllFrames
1479 {
1480     WebFrame *frame = [self mainFrame];
1481     do {
1482         [frame _detachScriptDebugger];
1483         frame = [frame _nextFrameWithWrap:NO];
1484     } while (frame);
1485 }
1486
1487 @end
1488
1489
1490 @implementation _WebSafeForwarder
1491
1492 - initWithTarget: t defaultTarget: dt templateClass: (Class)aClass
1493 {
1494     self = [super init];
1495     if (!self)
1496         return nil;
1497     
1498     target = t;         // Non retained.
1499     defaultTarget = dt;
1500     templateClass = aClass;
1501     return self;
1502 }
1503
1504
1505 // Used to send messages to delegates that implement informal protocols.
1506 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
1507 {
1508     return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
1509 }
1510
1511 #ifndef NDEBUG
1512 NSMutableDictionary *countInvocations;
1513 #endif
1514
1515 - (void)forwardInvocation:(NSInvocation *)anInvocation
1516 {
1517 #ifndef NDEBUG
1518     if (!countInvocations){
1519         countInvocations = [[NSMutableDictionary alloc] init];
1520     }
1521     NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
1522     if (!count)
1523         count = [NSNumber numberWithInt: 1];
1524     else
1525         count = [NSNumber numberWithInt: [count intValue] + 1];
1526     [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
1527 #endif
1528     if ([target respondsToSelector: [anInvocation selector]])
1529         [anInvocation invokeWithTarget: target];
1530     else if ([defaultTarget respondsToSelector: [anInvocation selector]])
1531         [anInvocation invokeWithTarget: defaultTarget];
1532     // Do nothing quietly if method not implemented.
1533 }
1534
1535 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1536 {
1537     return [templateClass instanceMethodSignatureForSelector: aSelector];
1538 }
1539
1540 @end
1541
1542 @implementation WebView
1543
1544 #if REMOVE_SAFARI_DOM_TREE_DEBUG_ITEM
1545 // this prevents open source users from crashing when using the Show DOM Tree menu item in Safari
1546 // FIXME: remove this when it is no longer needed to prevent Safari from crashing
1547 +(void)initialize
1548 {
1549     static BOOL tooLate = NO;
1550     if (!tooLate) {
1551         if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeDebugMenu"])
1552             [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_finishedLaunching) name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1553         tooLate = YES;
1554     }
1555 }
1556
1557 +(void)_finishedLaunching
1558 {
1559     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_removeDOMTreeMenuItem:) name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1560     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1561 }
1562
1563 +(void)_removeDOMTreeMenuItem:(NSNotification *)notification
1564 {
1565     NSMenu *debugMenu = [[[[NSApp mainMenu] itemArray] lastObject] submenu];
1566     NSMenuItem *domTree = [debugMenu itemWithTitle:@"Show DOM Tree"];
1567     if (domTree)
1568         [debugMenu removeItem:domTree];
1569     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1570 }
1571 #endif
1572
1573 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1574 {
1575     return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1576 }
1577
1578 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
1579 {
1580     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
1581     if (pluginPackage)
1582         return pluginPackage;
1583     
1584     if (_private->pluginDatabase)
1585         return [_private->pluginDatabase pluginForMIMEType:MIMEType];
1586     
1587     return nil;
1588 }
1589
1590 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
1591 {
1592     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForExtension:extension];
1593     if (pluginPackage)
1594         return pluginPackage;
1595     
1596     if (_private->pluginDatabase)
1597         return [_private->pluginDatabase pluginForExtension:extension];
1598     
1599     return nil;
1600 }
1601
1602 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
1603 {
1604     if ([[WebPluginDatabase installedPlugins] isMIMETypeRegistered:MIMEType])
1605         return YES;
1606         
1607     if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
1608         return YES;
1609     
1610     return nil;
1611 }
1612
1613 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1614 {
1615     return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1616 }
1617
1618 + (NSArray *)MIMETypesShownAsHTML
1619 {
1620     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1621     NSEnumerator *enumerator = [viewTypes keyEnumerator];
1622     id key;
1623     NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1624     
1625     while ((key = [enumerator nextObject])) {
1626         if ([viewTypes objectForKey:key] == [WebHTMLView class])
1627             [array addObject:key];
1628     }
1629     
1630     return array;
1631 }
1632
1633 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1634 {
1635     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1636     NSEnumerator *enumerator = [viewTypes keyEnumerator];
1637     id key;
1638     while ((key = [enumerator nextObject])) {
1639         if ([viewTypes objectForKey:key] == [WebHTMLView class])
1640             [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1641     }
1642     
1643     int i, count = [MIMETypes count];
1644     for (i = 0; i < count; i++) {
1645         [WebView registerViewClass:[WebHTMLView class] 
1646                 representationClass:[WebHTMLRepresentation class] 
1647                 forMIMEType:[MIMETypes objectAtIndex:i]];
1648     }
1649 }
1650
1651 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1652 {
1653     return [pasteboard _web_bestURL];
1654 }
1655
1656 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1657 {
1658     return [pasteboard stringForType:WebURLNamePboardType];
1659 }
1660
1661 - (void)_registerDraggedTypes
1662 {
1663     NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1664     NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1665     NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1666     [types addObjectsFromArray:URLTypes];
1667     [self registerForDraggedTypes:[types allObjects]];
1668     [types release];
1669 }
1670
1671 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1672 {
1673     _private->mainFrameDocumentReady = NO;
1674     _private->drawsBackground = YES;
1675     _private->smartInsertDeleteEnabled = YES;
1676
1677     NSRect f = [self frame];
1678     WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1679     [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1680     [self addSubview:frameView];
1681     [frameView release];
1682
1683     WebKitInitializeLoggingChannelsIfNecessary();
1684     _private->_pageBridge = [[WebPageBridge alloc] initWithMainFrameName:frameName webView:self frameView:frameView];
1685
1686     [self _addToAllWebViewsSet];
1687     [self setGroupName:groupName];
1688     
1689     // If there's already a next key view (e.g., from a nib), wire it up to our
1690     // contained frame view. In any case, wire our next key view up to the our
1691     // contained frame view. This works together with our becomeFirstResponder 
1692     // and setNextKeyView overrides.
1693     NSView *nextKeyView = [self nextKeyView];
1694     if (nextKeyView != nil && nextKeyView != frameView) {
1695         [frameView setNextKeyView:nextKeyView];
1696     }
1697     [super setNextKeyView:frameView];
1698
1699     ++WebViewCount;
1700
1701     [self _registerDraggedTypes];
1702
1703     // initialize WebScriptDebugServer here so listeners can register before any pages are loaded.
1704     if ([WebView _scriptDebuggerEnabled])
1705         [WebScriptDebugServer sharedScriptDebugServer];
1706
1707     // Update WebCore with preferences.  These values will either come from an archived WebPreferences,
1708     // or from the standard preferences, depending on whether this method was called from initWithCoder:
1709     // or initWithFrame, respectively.
1710     [self _updateWebCoreSettingsFromPreferences: [self preferences]];
1711     
1712     // Register to receive notifications whenever preference values change.
1713     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1714                                                  name:WebPreferencesChangedNotification object:[self preferences]];
1715 }
1716
1717 - (id)initWithFrame:(NSRect)f
1718 {
1719     return [self initWithFrame:f frameName:nil groupName:nil];
1720 }
1721
1722 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName;
1723 {
1724     self = [super initWithFrame:f];
1725     if (!self)
1726         return nil;
1727
1728 #if ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1729     // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1730     // may not work with other WebKit applications.  Unsetting DYLD_FRAMEWORK_PATH removes the
1731     // need for Safari to unset it to prevent it from being passed to applications it launches.
1732     // Unsetting it when a WebView is first created is as good a place as any.
1733     // See <http://bugzilla.opendarwin.org/show_bug.cgi?id=4286> for more details.
1734     if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1735         unsetenv("DYLD_FRAMEWORK_PATH");
1736         unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1737     }
1738 #endif
1739
1740     _private = [[WebViewPrivate alloc] init];
1741     [self _commonInitializationWithFrameName:frameName groupName:groupName];
1742     [self setMaintainsBackForwardList: YES];
1743     return self;
1744 }
1745
1746 - (id)initWithCoder:(NSCoder *)decoder
1747 {
1748     WebView *result = nil;
1749
1750 NS_DURING
1751
1752     NSString *frameName;
1753     NSString *groupName;
1754     WebPreferences *preferences;
1755     BOOL useBackForwardList;
1756
1757     result = [super initWithCoder:decoder];
1758     result->_private = [[WebViewPrivate alloc] init];
1759
1760     // We don't want any of the archived subviews. The subviews will always
1761     // be created in _commonInitializationFrameName:groupName:.
1762     [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1763
1764     if ([decoder allowsKeyedCoding]) {
1765         frameName = [decoder decodeObjectForKey:@"FrameName"];
1766         groupName = [decoder decodeObjectForKey:@"GroupName"];
1767         preferences = [decoder decodeObjectForKey:@"Preferences"];
1768         useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1769     } else {
1770         int version;
1771         [decoder decodeValueOfObjCType:@encode(int) at:&version];
1772         frameName = [decoder decodeObject];
1773         groupName = [decoder decodeObject];
1774         preferences = [decoder decodeObject];
1775         if (version > 1)
1776             [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
1777     }
1778
1779     if (![frameName isKindOfClass:[NSString class]])
1780         frameName = nil;
1781     if (![groupName isKindOfClass:[NSString class]])
1782         groupName = nil;
1783     if (![preferences isKindOfClass:[WebPreferences class]])
1784         preferences = nil;
1785
1786     LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
1787
1788     if (preferences)
1789         [result setPreferences:preferences];
1790     result->_private->useBackForwardList = useBackForwardList;
1791     [result _commonInitializationWithFrameName:frameName groupName:groupName];
1792
1793 NS_HANDLER
1794
1795     result = nil;
1796     [self release];
1797
1798 NS_ENDHANDLER
1799
1800     return result;
1801 }
1802
1803 - (void)encodeWithCoder:(NSCoder *)encoder
1804 {
1805     [super encodeWithCoder:encoder];
1806
1807     if ([encoder allowsKeyedCoding]) {
1808         [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1809         [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1810         [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1811         [encoder encodeBool:_private->useBackForwardList forKey:@"UseBackForwardList"];
1812     } else {
1813         int version = WebViewVersion;
1814         [encoder encodeValueOfObjCType:@encode(int) at:&version];
1815         [encoder encodeObject:[[self mainFrame] name]];
1816         [encoder encodeObject:[self groupName]];
1817         [encoder encodeObject:[self preferences]];
1818         [encoder encodeValuesOfObjCTypes:"c", &_private->useBackForwardList];
1819     }
1820
1821     LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)_private->useBackForwardList);
1822 }
1823
1824 - (void)dealloc
1825 {
1826     [self _close];
1827     
1828     --WebViewCount;
1829     
1830     [[NSNotificationCenter defaultCenter] removeObserver:self];
1831     
1832     [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1833     
1834     [_private release];
1835     // [super dealloc] can end up dispatching against _private (3466082)
1836     _private = nil;
1837
1838     [super dealloc];
1839 }
1840
1841 - (void)finalize
1842 {
1843     [self _close];
1844
1845     --WebViewCount;
1846
1847     [[NSNotificationCenter defaultCenter] removeObserver:self];
1848
1849     [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1850
1851     [super finalize];
1852 }
1853
1854 - (void)setPreferences:(WebPreferences *)prefs
1855 {
1856     if (_private->preferences != prefs) {
1857         [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
1858         [WebPreferences _removeReferenceForIdentifier:[_private->preferences identifier]];
1859         [_private->preferences release];
1860         _private->preferences = [prefs retain];
1861         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1862             name:WebPreferencesChangedNotification object:[self preferences]];
1863         [[NSNotificationCenter defaultCenter]
1864             postNotificationName:WebPreferencesChangedNotification object:prefs userInfo:nil];
1865     }
1866 }
1867
1868 - (WebPreferences *)preferences
1869 {
1870     return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
1871 }
1872
1873 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
1874 {
1875     if (![anIdentifier isEqual:[[self preferences] identifier]]) {
1876         WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
1877         [self setPreferences:prefs];
1878         [prefs release];
1879     }
1880 }
1881
1882 - (NSString *)preferencesIdentifier
1883 {
1884     return [[self preferences] identifier];
1885 }
1886
1887
1888 - (void)setUIDelegate:delegate
1889 {
1890     _private->UIDelegate = delegate;
1891     [_private->UIDelegateForwarder release];
1892     _private->UIDelegateForwarder = nil;
1893 }
1894
1895 - UIDelegate
1896 {
1897     return _private->UIDelegate;
1898 }
1899
1900 - (void)setResourceLoadDelegate: delegate
1901 {
1902     _private->resourceProgressDelegate = delegate;
1903     [_private->resourceProgressDelegateForwarder release];
1904     _private->resourceProgressDelegateForwarder = nil;
1905     [self _cacheResourceLoadDelegateImplementations];
1906 }
1907
1908
1909 - resourceLoadDelegate
1910 {
1911     return _private->resourceProgressDelegate;
1912 }
1913
1914
1915 - (void)setDownloadDelegate: delegate
1916 {
1917     _private->downloadDelegate = delegate;
1918 }
1919
1920
1921 - downloadDelegate
1922 {
1923     return _private->downloadDelegate;
1924 }
1925
1926 - (void)setPolicyDelegate:delegate
1927 {
1928     _private->policyDelegate = delegate;
1929     [_private->policyDelegateForwarder release];
1930     _private->policyDelegateForwarder = nil;
1931 }
1932
1933 - policyDelegate
1934 {
1935     return _private->policyDelegate;
1936 }
1937
1938 - (void)setFrameLoadDelegate:delegate
1939 {
1940     _private->frameLoadDelegate = delegate;
1941     [_private->frameLoadDelegateForwarder release];
1942     _private->frameLoadDelegateForwarder = nil;
1943 }
1944
1945 - frameLoadDelegate
1946 {
1947     return _private->frameLoadDelegate;
1948 }
1949
1950 - (WebFrame *)mainFrame
1951 {
1952     // This can be called in initialization, before _private has been set up (3465613)
1953     if (!_private)
1954         return nil;
1955
1956     return [(WebFrameBridge *)[_private->_pageBridge mainFrame] webFrame];
1957 }
1958
1959 - (WebBackForwardList *)backForwardList
1960 {
1961     if (_private->useBackForwardList)
1962         return _private->backForwardList;
1963     return nil;
1964 }
1965
1966 - (void)setMaintainsBackForwardList: (BOOL)flag
1967 {
1968     _private->useBackForwardList = flag;
1969 }
1970
1971 - (BOOL)goBack
1972 {
1973     WebHistoryItem *item = [[self backForwardList] backItem];
1974     
1975     if (item){
1976         [self _goToItem: item withLoadType: WebFrameLoadTypeBack];
1977         return YES;
1978     }
1979     return NO;
1980 }
1981
1982 - (BOOL)goForward
1983 {
1984     WebHistoryItem *item = [[self backForwardList] forwardItem];
1985     
1986     if (item){
1987         [self _goToItem: item withLoadType: WebFrameLoadTypeForward];
1988         return YES;
1989     }
1990     return NO;
1991 }
1992
1993 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
1994 {
1995     [self _goToItem: item withLoadType: WebFrameLoadTypeIndexedBackForward];
1996     return YES;
1997 }
1998
1999 - (void)setTextSizeMultiplier:(float)m
2000 {
2001     if (_private->textSizeMultiplier == m) {
2002         return;
2003     }
2004     _private->textSizeMultiplier = m;
2005 }
2006
2007 - (float)textSizeMultiplier
2008 {
2009     return _private->textSizeMultiplier;
2010 }
2011
2012 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
2013 {
2014     NSString *name = [applicationName copy];
2015     [_private->applicationNameForUserAgent release];
2016     _private->applicationNameForUserAgent = name;
2017     if (!_private->userAgentOverridden) {
2018         [_private->userAgent release];
2019         _private->userAgent = nil;
2020     }
2021 }
2022
2023 - (NSString *)applicationNameForUserAgent
2024 {
2025     return [[_private->applicationNameForUserAgent retain] autorelease];
2026 }
2027
2028 - (void)setCustomUserAgent:(NSString *)userAgentString
2029 {
2030     NSString *override = [userAgentString copy];
2031     [_private->userAgent release];
2032     _private->userAgent = override;
2033     _private->userAgentOverridden = override != nil;
2034 }
2035
2036 - (NSString *)customUserAgent
2037 {
2038     return _private->userAgentOverridden ? [[_private->userAgent retain] autorelease] : nil;
2039 }
2040
2041 - (void)setMediaStyle:(NSString *)mediaStyle
2042 {
2043     if (_private->mediaStyle != mediaStyle) {
2044         [_private->mediaStyle release];
2045         _private->mediaStyle = [mediaStyle copy];
2046     }
2047 }
2048
2049 - (NSString *)mediaStyle
2050 {
2051     return _private->mediaStyle;
2052 }
2053
2054 - (BOOL)supportsTextEncoding
2055 {
2056     id documentView = [[[self mainFrame] frameView] documentView];
2057     return [documentView conformsToProtocol:@protocol(WebDocumentText)]
2058         && [documentView supportsTextEncoding];
2059 }
2060
2061 - (void)setCustomTextEncodingName:(NSString *)encoding
2062 {
2063     NSString *oldEncoding = [self customTextEncodingName];
2064     if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) {
2065         return;
2066     }
2067     [[self mainFrame] _reloadAllowingStaleDataWithOverrideEncoding:encoding];
2068 }
2069
2070 - (NSString *)_mainFrameOverrideEncoding
2071 {
2072     WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
2073     if (dataSource == nil) {
2074         dataSource = [[self mainFrame] dataSource];
2075     }
2076     if (dataSource == nil) {
2077         return nil;
2078     }
2079     return [dataSource _overrideEncoding];
2080 }
2081
2082 - (NSString *)customTextEncodingName
2083 {
2084     return [self _mainFrameOverrideEncoding];
2085 }
2086
2087 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
2088 {
2089     return [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
2090 }
2091
2092 - (WebScriptObject *)windowScriptObject
2093 {
2094     return [[[self mainFrame] _bridge] windowScriptObject];
2095 }
2096
2097         
2098 // Get the appropriate user-agent string for a particular URL.
2099 // Since we no longer automatically spoof, this no longer requires looking at the URL.
2100 - (NSString *)userAgentForURL:(NSURL *)URL
2101 {
2102     NSString *userAgent = _private->userAgent;
2103     if (userAgent) {
2104         return [[userAgent retain] autorelease];
2105     }
2106     
2107     NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
2108     id sourceVersion = [[NSBundle bundleForClass:[WebView class]]
2109         objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
2110     NSString *applicationName = _private->applicationNameForUserAgent;
2111
2112     if ([applicationName length]) {
2113         userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
2114             language, sourceVersion, applicationName];
2115     } else {
2116         userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko)",
2117             language, sourceVersion];
2118     }
2119
2120     _private->userAgent = [userAgent retain];
2121     return userAgent;
2122 }
2123
2124 - (void)setHostWindow:(NSWindow *)hostWindow
2125 {
2126     if (hostWindow != _private->hostWindow) {
2127         [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
2128         [_private->hostWindow release];
2129         _private->hostWindow = [hostWindow retain];
2130         [[self mainFrame] _viewDidMoveToHostWindow];
2131     }
2132 }
2133
2134 - (NSWindow *)hostWindow
2135 {
2136     return _private->hostWindow;
2137 }
2138
2139 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
2140 {
2141     return [[self _frameViewAtWindowPoint:point] documentView];
2142 }
2143
2144 - (NSView <WebDocumentDragging> *)_draggingDocumentViewAtWindowPoint:(NSPoint)point
2145 {
2146     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:point];
2147     if ([documentView conformsToProtocol:@protocol(WebDocumentDragging)]) {
2148         return (NSView <WebDocumentDragging> *)documentView;
2149     }
2150     return nil;
2151 }
2152
2153 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
2154 {
2155     WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
2156     if (!frameView)
2157         return nil;
2158     NSView <WebDocumentView> *documentView = [frameView documentView];
2159     if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
2160         NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
2161         return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
2162     }
2163     return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
2164 }
2165
2166 - (NSDictionary *)elementAtPoint:(NSPoint)point
2167 {
2168     return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2169 }
2170
2171 - (void)_setDraggingDocumentView:(NSView <WebDocumentDragging> *)newDraggingView
2172 {
2173     if (_private->draggingDocumentView != newDraggingView) {
2174         [_private->draggingDocumentView release];
2175         _private->draggingDocumentView = [newDraggingView retain];
2176     }
2177 }
2178
2179 - (NSDragOperation)_loadingDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2180 {
2181     if (_private->dragDestinationActionMask & WebDragDestinationActionLoad) {
2182         NSPoint windowPoint = [draggingInfo draggingLocation];
2183         NSView *view = [self hitTest:[[self superview] convertPoint:windowPoint toView:nil]];
2184         // Don't accept the drag over a plug-in since plug-ins may want to handle it.
2185         if (![view isKindOfClass:[WebBaseNetscapePluginView class]] && !_private->editable && !_private->initiatedDrag) {
2186             // If not editing or dragging, use _web_dragOperationForDraggingInfo to find a URL to load on the pasteboard.
2187             return [self _web_dragOperationForDraggingInfo:draggingInfo];
2188         }
2189     }
2190     return NSDragOperationNone;
2191 }
2192
2193 - (NSDragOperation)_delegateDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2194 {
2195     NSPoint windowPoint = [draggingInfo draggingLocation];
2196     NSView <WebDocumentDragging> *newDraggingView = [self _draggingDocumentViewAtWindowPoint:windowPoint];
2197     if (_private->draggingDocumentView != newDraggingView) {
2198         [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2199         [self _setDraggingDocumentView:newDraggingView];
2200     }
2201     
2202     _private->dragDestinationActionMask = [[self _UIDelegateForwarder] webView:self dragDestinationActionMaskForDraggingInfo:draggingInfo];
2203     NSDragOperation operation = NSDragOperationNone;
2204     
2205     if (_private->dragDestinationActionMask == WebDragDestinationActionNone) {
2206         [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2207     } else {
2208         operation = [_private->draggingDocumentView draggingUpdatedWithDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask];
2209         if (operation == NSDragOperationNone) {
2210             return [self _loadingDragOperationForDraggingInfo:draggingInfo];
2211         }
2212     }
2213     
2214     return operation;
2215 }
2216
2217 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2218 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. 
2219 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. 
2220 // Forward these calls to the document subview to make its scroll view scroll.
2221 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2222 {
2223     if (![self isEditable])
2224         return;
2225     
2226     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2227     [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2228 }
2229
2230 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2231 {
2232     if (![self isEditable])
2233         return NO;
2234     
2235     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2236     return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2237 }
2238
2239 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2240 {
2241     return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2242 }
2243
2244 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2245 {
2246     return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2247 }
2248
2249 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2250 {
2251     [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2252     [self _setDraggingDocumentView:nil];
2253 }
2254
2255 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2256 {
2257     return YES;
2258 }
2259
2260 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2261 {
2262     ASSERT(_private->draggingDocumentView == [self _draggingDocumentViewAtWindowPoint:[draggingInfo draggingLocation]]);
2263     
2264     if ([_private->draggingDocumentView concludeDragForDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask]) {
2265         [self _setDraggingDocumentView:nil];
2266         return YES;
2267     }
2268     
2269     [self _setDraggingDocumentView:nil];
2270         
2271     if ([self _loadingDragOperationForDraggingInfo:draggingInfo] != NSDragOperationNone) {    
2272         NSURL *URL = [[self class] URLFromPasteboard:[draggingInfo draggingPasteboard]];
2273         if (URL != nil) {
2274             [[self _UIDelegateForwarder] webView:self willPerformDragDestinationAction:WebDragDestinationActionLoad forDraggingInfo:draggingInfo];
2275             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
2276             [[self mainFrame] loadRequest:request];
2277             [request release];
2278             return YES;
2279         }
2280     }
2281     
2282     return NO;
2283 }
2284
2285 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2286 {
2287     NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2288     if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2289         return self;
2290     } else {
2291         return hitView;
2292     }
2293 }
2294
2295 - (BOOL)acceptsFirstResponder
2296 {
2297     return [[[self mainFrame] frameView] acceptsFirstResponder];
2298 }
2299
2300 - (BOOL)becomeFirstResponder
2301 {
2302     // This works together with setNextKeyView to splice the WebView into
2303     // the key loop similar to the way NSScrollView does this. Note that
2304     // WebFrameView has very similar code.
2305     NSWindow *window = [self window];
2306     WebFrameView *mainFrameView = [[self mainFrame] frameView];
2307     
2308     if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2309         NSView *previousValidKeyView = [self previousValidKeyView];
2310         if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2311             [window makeFirstResponder:previousValidKeyView];
2312             return YES;
2313         } else {
2314             return NO;
2315         }
2316     }
2317     
2318     if ([mainFrameView acceptsFirstResponder]) {
2319         [window makeFirstResponder:mainFrameView];
2320         return YES;
2321     } 
2322     
2323     return NO;
2324 }
2325
2326 - (NSView *)_webcore_effectiveFirstResponder
2327 {
2328     WebFrameView *frameView = [[self mainFrame] frameView];
2329     return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2330 }
2331
2332 - (void)setNextKeyView:(NSView *)aView
2333 {
2334     // This works together with becomeFirstResponder to splice the WebView into
2335     // the key loop similar to the way NSScrollView does this. Note that
2336     // WebFrameView has very similar code.
2337     WebFrameView *mainFrameView = [[self mainFrame] frameView];
2338     if (mainFrameView != nil) {
2339         [mainFrameView setNextKeyView:aView];
2340     } else {
2341         [super setNextKeyView:aView];
2342     }
2343 }
2344
2345 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2346 {
2347     return forward ? [curr _nextFrameWithWrap:wrapFlag]
2348                    : [curr _previousFrameWithWrap:wrapFlag];
2349 }
2350
2351 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2352 {
2353     // Get the frame holding the selection, or start with the main frame
2354     WebFrame *startFrame = [self _selectedOrMainFrame];
2355
2356     // Search the first frame, then all the other frames, in order
2357     NSView <WebDocumentSearching> *startSearchView = nil;
2358     BOOL startHasSelection = NO;
2359     WebFrame *frame = startFrame;
2360     do {
2361         id <WebDocumentView> view = [[frame frameView] documentView];
2362         if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2363             NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2364
2365             // first time through
2366             if (frame == startFrame) {
2367                 // Remember if start even has a selection, to know if we need to search more later
2368                 if ([searchView isKindOfClass:[WebHTMLView class]]) {
2369                     // optimization for the common case, to avoid making giant string for selection
2370                     startHasSelection = [[startFrame _bridge] selectedDOMRange] != nil;
2371                 } else if ([searchView conformsToProtocol:@protocol(WebDocumentText)]) {
2372                     startHasSelection = [(id <WebDocumentText>)searchView selectedString] != nil;
2373                 }
2374                 startSearchView = searchView;
2375             }
2376             
2377             if ([searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:NO]) {
2378                 if (frame != startFrame)
2379                     [startFrame _clearSelection];
2380                 [[self window] makeFirstResponder:searchView];
2381                 return YES;
2382             }
2383         }
2384         frame = incrementFrame(frame, forward, wrapFlag);
2385     } while (frame != nil && frame != startFrame);
2386
2387     // Search contents of startFrame, on the other side of the selection that we did earlier.
2388     // We cheat a bit and just research with wrap on
2389     if (wrapFlag && startHasSelection && startSearchView) {
2390         if ([startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]) {
2391             [[self window] makeFirstResponder:startSearchView];
2392             return YES;
2393         }
2394     }
2395     return NO;
2396 }
2397
2398 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2399 {
2400     [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2401     [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2402 }
2403
2404 - (void)setGroupName:(NSString *)groupName
2405 {
2406     [[self _pageBridge] setGroupName:groupName];
2407 }
2408
2409 - (NSString *)groupName
2410 {
2411     return [[self _pageBridge] groupName];
2412 }
2413
2414 - (double)estimatedProgress
2415 {
2416     return _private->progressValue;
2417 }
2418
2419 - (NSArray *)pasteboardTypesForSelection
2420 {
2421     NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
2422     if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2423         return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2424     }
2425     return [NSArray array];
2426 }
2427
2428 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2429 {
2430     WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
2431     if ([bridge selectionState] != WebSelectionStateRange) {
2432         NSView <WebDocumentView> *documentView = [[[bridge webFrame] frameView] documentView];
2433         if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2434             [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2435         }
2436     }
2437 }
2438
2439 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2440 {
2441     if ([element objectForKey:WebElementImageURLKey] != nil) {
2442         return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2443     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2444         return [NSPasteboard _web_writableTypesForURL];
2445     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2446         return [self pasteboardTypesForSelection];
2447     }
2448     return [NSArray array];
2449 }
2450
2451 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2452 {
2453     if ([element objectForKey:WebElementImageURLKey] != nil) {
2454         [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2455     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2456         [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2457     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2458         [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2459     }
2460 }
2461
2462 - (void)moveDragCaretToPoint:(NSPoint)point
2463 {
2464     [[[self mainFrame] _bridge] moveDragCaretToPoint:[self convertPoint:point toView:[[[self mainFrame] frameView] documentView]]];
2465 }
2466
2467 - (void)removeDragCaret
2468 {
2469     [[[self mainFrame] _bridge] removeDragCaret];
2470 }
2471
2472 - (void)_inspectElement:(id)sender
2473 {
2474     NSDictionary *element = [sender representedObject];
2475     WebFrame *frame = [element objectForKey:WebElementFrameKey];
2476     DOMNode *node = [element objectForKey:WebElementDOMNodeKey];
2477     if (!node || !frame)
2478         return;
2479
2480     if ([node nodeType] != DOM_ELEMENT_NODE || [node nodeType] != DOM_DOCUMENT_NODE)
2481         node = [node parentNode];
2482
2483     WebInspector *inspector = [WebInspector sharedWebInspector];
2484     [inspector setWebFrame:frame];
2485     [inspector setFocusedDOMNode:node];
2486
2487     node = [node parentNode];
2488     node = [node parentNode];
2489     if (node) // set the root node to something relatively close to the focused node
2490         [inspector setRootDOMNode:node];
2491
2492     [inspector showWindow:nil];
2493 }
2494 @end
2495
2496 @implementation WebView (WebIBActions)
2497
2498 - (IBAction)takeStringURLFrom: sender
2499 {
2500     NSString *URLString = [sender stringValue];
2501     
2502     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2503 }
2504
2505 - (BOOL)canGoBack
2506 {
2507     return [[self backForwardList] backItem] != nil;
2508 }
2509
2510 - (BOOL)canGoForward
2511 {
2512     return [[self backForwardList] forwardItem] != nil;
2513 }
2514
2515 - (IBAction)goBack:(id)sender
2516 {
2517     [self goBack];
2518 }
2519
2520 - (IBAction)goForward:(id)sender
2521 {
2522     [self goForward];
2523 }
2524
2525 - (IBAction)stopLoading:(id)sender
2526 {
2527     [[self mainFrame] stopLoading];
2528 }
2529
2530 - (IBAction)reload:(id)sender
2531 {
2532     [[self mainFrame] reload];
2533 }
2534
2535 #define MinimumTextSizeMultiplier       0.5
2536 #define MaximumTextSizeMultiplier       3.0
2537 #define TextSizeMultiplierRatio         1.2
2538
2539 - (BOOL)canMakeTextSmaller
2540 {
2541     BOOL canShrinkMore = _private->textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2542     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:0];
2543 }
2544
2545 - (BOOL)canMakeTextLarger
2546 {
2547     BOOL canGrowMore = _private->textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2548     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:0];
2549 }
2550
2551 - (IBAction)makeTextSmaller:(id)sender
2552 {
2553     float newScale = _private->textSizeMultiplier/TextSizeMultiplierRatio;
2554     BOOL canShrinkMore = newScale > MinimumTextSizeMultiplier;
2555     [self _performTextSizingSelector:@selector(_makeTextSmaller:) withObject:sender onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:newScale];
2556 }
2557
2558 - (IBAction)makeTextLarger:(id)sender
2559 {
2560     float newScale = _private->textSizeMultiplier*TextSizeMultiplierRatio;
2561     BOOL canGrowMore = newScale < MaximumTextSizeMultiplier;
2562     [self _performTextSizingSelector:@selector(_makeTextLarger:) withObject:sender onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:newScale];
2563 }
2564
2565 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2566 {
2567     id responder = [self _responderForResponderOperations];
2568     if (responder != self && [responder respondsToSelector:[item action]]) {
2569         if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) {
2570             return [responder validateUserInterfaceItem:item];
2571         }
2572         return YES;
2573     }
2574     return NO;
2575 }
2576
2577 #define VALIDATE(name) \
2578     else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2579
2580 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2581 {
2582     SEL action = [item action];
2583
2584     if (action == @selector(goBack:)) {
2585         return [self canGoBack];
2586     } else if (action == @selector(goForward:)) {
2587         return [self canGoForward];
2588     } else if (action == @selector(makeTextLarger:)) {
2589         return [self canMakeTextLarger];
2590     } else if (action == @selector(makeTextSmaller:)) {
2591         return [self canMakeTextSmaller];
2592     } else if (action == @selector(makeTextStandardSize:)) {
2593         return [self canMakeTextStandardSize];
2594     } else if (action == @selector(reload:)) {
2595         return [[self mainFrame] dataSource] != nil;
2596     } else if (action == @selector(stopLoading:)) {
2597         return [self _isLoading];
2598     } else if (action == @selector(toggleContinuousSpellChecking:)) {
2599         BOOL checkMark = NO;
2600         BOOL retVal = NO;
2601         if ([self isEditable] && [self _continuousCheckingAllowed]) {
2602             checkMark = [self isContinuousSpellCheckingEnabled];
2603             retVal = YES;
2604         }
2605         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2606             NSMenuItem *menuItem = (NSMenuItem *)item;
2607             [menuItem setState:checkMark ? NSOnState : NSOffState];
2608         }
2609         return retVal;
2610     }
2611     FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2612
2613     return YES;
2614 }
2615
2616 @end
2617
2618 @implementation WebView (WebPendingPublic)
2619
2620 - (void)setMainFrameURL:(NSString *)URLString
2621 {
2622     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2623 }
2624
2625 - (NSString *)mainFrameURL
2626 {
2627     WebDataSource *ds;
2628     ds = [[self mainFrame] provisionalDataSource];
2629     if (!ds)
2630         ds = [[self mainFrame] dataSource];
2631     return [[[ds request] URL] _web_originalDataAsString];
2632 }
2633
2634 - (BOOL)isLoading
2635 {
2636     LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2637     return [self _isLoading];
2638 }
2639
2640 - (NSString *)mainFrameTitle
2641 {
2642     NSString *mainFrameTitle = [[[self mainFrame] dataSource] pageTitle];
2643     return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
2644 }
2645
2646 - (NSImage *)mainFrameIcon
2647 {
2648     return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2649 }
2650
2651 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
2652 {
2653     // by setting this to NO, calls to mainFrameDocument are forced to return nil
2654     // setting this to YES lets it return the actual DOMDocument value
2655     // we use this to tell NSTreeController to reset its observers and clear its state
2656     if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
2657         return;
2658     [self _willChangeValueForKey:_WebMainFrameDocumentKey];
2659     _private->mainFrameDocumentReady = mainFrameDocumentReady;
2660     [self _didChangeValueForKey:_WebMainFrameDocumentKey];
2661     // this will cause observers to call mainFrameDocument where this flag will be checked
2662 }
2663
2664 - (DOMDocument *)mainFrameDocument
2665 {
2666     // only return the actual value if the state we're in gives NSTreeController
2667     // enough time to release its observers on the old model
2668     if (_private->mainFrameDocumentReady)
2669         return [[self mainFrame] DOMDocument];
2670     return nil;
2671 }
2672
2673 - (void)setDrawsBackground:(BOOL)drawsBackground
2674 {
2675     if (_private->drawsBackground == drawsBackground)
2676         return;
2677     _private->drawsBackground = drawsBackground;
2678     [[self mainFrame] _updateDrawsBackground];
2679 }
2680
2681 - (BOOL)drawsBackground
2682 {
2683     return _private->drawsBackground;
2684 }
2685
2686 - (void)toggleSmartInsertDelete:(id)sender
2687 {
2688     if ([self isEditable]) {
2689         [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2690     }
2691 }
2692
2693 - (IBAction)toggleContinuousSpellChecking:(id)sender
2694 {
2695     if ([self isEditable]) {
2696         [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2697     }
2698 }
2699
2700 - (BOOL)maintainsInactiveSelection
2701 {
2702     return [self isEditable];
2703 }
2704
2705 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it 
2706 // until the day comes when we're no longer supporting Mail on Tiger.
2707 - (WebFrame *)_frameForCurrentSelection
2708 {
2709     return [self _selectedOrMainFrame];
2710 }
2711
2712 - (WebFrame *)selectedFrame
2713 {
2714     // If the first responder is a view in our tree, we get the frame containing the first responder.
2715     // This is faster than searching the frame hierarchy, and will give us a result even in the case
2716     // where the focused frame doesn't actually contain a selection.
2717     WebFrame *focusedFrame = [self _focusedFrame];
2718     if (focusedFrame)
2719         return focusedFrame;
2720     
2721     // If the first responder is outside of our view tree, we search for a frame containing a selection.
2722     // There should be at most only one of these.
2723     return [[self mainFrame] _findFrameWithSelection];
2724     
2725     return nil;
2726 }
2727
2728 - (BOOL)canMakeTextStandardSize
2729 {
2730     BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0;
2731     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:0];
2732 }
2733
2734 - (IBAction)makeTextStandardSize:(id)sender
2735 {
2736     BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0;
2737     [self _performTextSizingSelector:@selector(_makeTextStandardSize:) withObject:sender onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:1.0];
2738 }
2739
2740 - (void)setScriptDebugDelegate:delegate
2741 {
2742     _private->scriptDebugDelegate = delegate;
2743     [_private->scriptDebugDelegateForwarder release];
2744     _private->scriptDebugDelegateForwarder = nil;
2745     if (delegate)
2746         [self _attachScriptDebuggerToAllFrames];
2747     else
2748         [self _detachScriptDebuggerFromAllFrames];
2749 }
2750
2751 - scriptDebugDelegate
2752 {
2753     return _private->scriptDebugDelegate;
2754 }
2755
2756 - (BOOL)shouldClose
2757 {
2758     WebFrameBridge *bridge = [[self mainFrame] _bridge];
2759     if (!bridge)
2760         return YES;
2761     return [bridge shouldClose];
2762 }
2763
2764 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
2765 {
2766     return [[[self mainFrame] _bridge] aeDescByEvaluatingJavaScriptFromString:script];
2767 }
2768
2769 - (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight
2770 {
2771     WebFrame *frame = [self mainFrame];
2772     unsigned matchCount = 0;
2773     do {
2774         id <WebDocumentView> view = [[frame frameView] documentView];
2775         // FIXME: introduce a protocol, or otherwise make this work with other types
2776         if ([view isKindOfClass:[WebHTMLView class]])
2777             [(WebHTMLView *)view setMarkedTextMatchesAreHighlighted:highlight];
2778             matchCount += [(WebHTMLView *)view markAllMatchesForText:string caseSensitive:caseFlag];
2779
2780         frame = incrementFrame(frame, YES, NO);
2781     } while (frame);
2782     
2783     return matchCount;
2784 }
2785
2786 - (void)unmarkAllTextMatches
2787 {
2788     WebFrame *frame = [self mainFrame];
2789     do {
2790         id <WebDocumentView> view = [[frame frameView] documentView];
2791         // FIXME: introduce a protocol, or otherwise make this work with other types
2792         if ([view isKindOfClass:[WebHTMLView class]])
2793             [(WebHTMLView *)view unmarkAllTextMatches];
2794         
2795         frame = incrementFrame(frame, YES, NO);
2796     } while (frame);
2797 }
2798
2799 - (NSArray *)rectsForTextMatches
2800 {
2801     NSMutableArray *result = [NSMutableArray array];
2802     WebFrame *frame = [self mainFrame];
2803     do {
2804         id <WebDocumentView> view = [[frame frameView] documentView];
2805         // FIXME: introduce a protocol, or otherwise make this work with other types
2806         if ([view isKindOfClass:[WebHTMLView class]]) {
2807             WebHTMLView *htmlView = (WebHTMLView *)view;
2808             NSArray *originalRects = [htmlView rectsForTextMatches];
2809             unsigned rectCount = [originalRects count];
2810             unsigned rectIndex;
2811             NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2812             for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
2813                 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
2814                 if (NSIsEmptyRect(r))
2815                     continue;
2816                 
2817                 // Convert rect to our coordinate system
2818                 r = [htmlView convertRect:r toView:self];
2819                 [result addObject:[NSValue valueWithRect:r]];
2820                 if (rectIndex % 10 == 0)
2821                     [pool drain];
2822             }
2823             [pool release];
2824         }
2825         
2826         frame = incrementFrame(frame, YES, NO);
2827     } while (frame);
2828     
2829     return result;
2830 }
2831
2832 @end
2833
2834 @implementation WebView (WebViewPrintingPrivate)
2835
2836 - (float)_headerHeight
2837 {
2838     if ([[self UIDelegate] respondsToSelector:@selector(webViewHeaderHeight:)]) {
2839         return [[self UIDelegate] webViewHeaderHeight:self];
2840     }
2841     
2842 #ifdef DEBUG_HEADER_AND_FOOTER
2843     return 25;
2844 #else
2845     return 0;
2846 #endif
2847 }
2848
2849 - (float)_footerHeight
2850 {
2851     if ([[self UIDelegate] respondsToSelector:@selector(webViewFooterHeight:)]) {
2852         return [[self UIDelegate] webViewFooterHeight:self];
2853     }
2854     
2855 #ifdef DEBUG_HEADER_AND_FOOTER
2856     return 50;
2857 #else
2858     return 0;
2859 #endif
2860 }
2861
2862 - (void)_drawHeaderInRect:(NSRect)rect
2863 {
2864 #ifdef DEBUG_HEADER_AND_FOOTER
2865     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2866     [currentContext saveGraphicsState];
2867     [[NSColor yellowColor] set];
2868     NSRectFill(rect);
2869     [currentContext restoreGraphicsState];
2870 #endif
2871     
2872     if ([[self UIDelegate] respondsToSelector:@selector(webView:drawHeaderInRect:)]) {
2873         NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2874         [currentContext saveGraphicsState];
2875         NSRectClip(rect);
2876         [[self UIDelegate] webView:self drawHeaderInRect:rect]; 
2877         [currentContext restoreGraphicsState];
2878     }
2879 }
2880
2881 - (void)_drawFooterInRect:(NSRect)rect
2882 {
2883 #ifdef DEBUG_HEADER_AND_FOOTER
2884     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2885     [currentContext saveGraphicsState];
2886     [[NSColor cyanColor] set];
2887     NSRectFill(rect);
2888     [currentContext restoreGraphicsState];
2889 #endif
2890     
2891     if ([[self UIDelegate] respondsToSelector:@selector(webView:drawFooterInRect:)]) {
2892         NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2893         [currentContext saveGraphicsState];
2894         NSRectClip(rect);
2895         [[self UIDelegate] webView:self drawFooterInRect:rect];
2896         [currentContext restoreGraphicsState];
2897     }
2898 }
2899
2900 - (void)_adjustPrintingMarginsForHeaderAndFooter
2901 {
2902     NSPrintOperation *op = [NSPrintOperation currentOperation];
2903     NSPrintInfo *info = [op printInfo];
2904     float scale = [op _web_pageSetupScaleFactor];
2905     [info setTopMargin:[info topMargin] + [self _headerHeight]*scale];
2906     [info setBottomMargin:[info bottomMargin] + [self _footerHeight]*scale];
2907 }
2908
2909 - (void)_drawHeaderAndFooter
2910 {
2911     // The header and footer rect height scales with the page, but the width is always
2912     // all the way across the printed page (inset by printing margins).
2913     NSPrintOperation *op = [NSPrintOperation currentOperation];
2914     float scale = [op _web_pageSetupScaleFactor];
2915     NSPrintInfo *printInfo = [op printInfo];
2916     NSSize paperSize = [printInfo paperSize];
2917     float headerFooterLeft = [printInfo leftMargin]/scale;
2918     float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
2919     NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , 
2920                                    headerFooterWidth, [self _footerHeight]);
2921     NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, 
2922                                    headerFooterWidth, [self _headerHeight]);
2923     
2924     [self _drawHeaderInRect:headerRect];
2925     [self _drawFooterInRect:footerRect];
2926 }
2927 @end
2928
2929 @implementation WebView (WebDebugBinding)
2930
2931 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
2932 {
2933     LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
2934     [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
2935 }
2936
2937 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
2938 {
2939     LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
2940     [super removeObserver:anObserver forKeyPath:keyPath];
2941 }
2942
2943 @end
2944
2945 //==========================================================================================
2946 // Editing
2947
2948 @implementation WebView (WebViewCSS)
2949
2950 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
2951 {
2952     // FIXME: is this the best level for this conversion?
2953     if (pseudoElement == nil) {
2954         pseudoElement = @"";
2955     }
2956     return [[element ownerDocument] getComputedStyle:element :pseudoElement];
2957 }
2958
2959 @end
2960
2961 @implementation WebView (WebViewEditing)
2962
2963 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
2964 {
2965     WebFrameBridge *bridge = [self _bridgeAtPoint:point];
2966     return [bridge editableDOMRangeForPoint:[self convertPoint:point toView:[[[bridge webFrame] frameView] documentView]]];
2967 }
2968
2969 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag;
2970 {
2971     return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
2972 }
2973
2974 - (BOOL)_shouldBeginEditingInDOMRange:(DOMRange *)range
2975 {
2976     return [[self _editingDelegateForwarder] webView:self shouldBeginEditingInDOMRange:range];
2977 }
2978
2979 - (BOOL)_shouldEndEditingInDOMRange:(DOMRange *)range
2980 {
2981     return [[self _editingDelegateForwarder] webView:self shouldEndEditingInDOMRange:range];
2982 }
2983
2984 - (BOOL)_canPaste
2985 {
2986     id documentView = [[[self mainFrame] frameView] documentView];
2987     return [documentView respondsToSelector:@selector(_canPaste)] && [documentView _canPaste];
2988 }
2989
2990 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
2991 {
2992     if (range == nil) {
2993         [[self _bridgeForSelectedOrMainFrame] deselectText];
2994     } else {
2995         // Derive the bridge to use from the range passed in.
2996         // Using _bridgeForSelectedOrMainFrame could give us a different document than
2997         // the one the range uses.
2998         [[[range startContainer] _bridge] setSelectedDOMRange:range affinity:selectionAffinity closeTyping:YES];
2999     }
3000 }
3001
3002 - (DOMRange *)selectedDOMRange
3003 {
3004     return [[self _bridgeForSelectedOrMainFrame] selectedDOMRange];
3005 }
3006
3007 - (NSSelectionAffinity)selectionAffinity
3008 {
3009     return [[self _bridgeForSelectedOrMainFrame] selectionAffinity];
3010 }
3011
3012 - (void)setEditable:(BOOL)flag
3013 {
3014     if (_private->editable != flag) {
3015         _private->editable = flag;
3016         WebFrameBridge *bridge = [[self mainFrame] _bridge];
3017         if (flag) {
3018             [bridge applyEditingStyleToBodyElement];
3019             // If the WebView is made editable and the selection is empty, set it to something.
3020             if ([self selectedDOMRange] == nil)
3021                 [bridge setSelectionFromNone];
3022         }
3023         else {
3024             [bridge removeEditingStyleFromBodyElement];
3025         }
3026     }
3027 }
3028
3029 - (BOOL)isEditable
3030 {
3031     return _private->editable;
3032 }
3033
3034 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
3035 {
3036     // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3037     // change the API to allow this.
3038     [[self _bridgeForSelectedOrMainFrame] setTypingStyle:style withUndoAction:WebUndoActionUnspecified];
3039 }
3040
3041 - (DOMCSSStyleDeclaration *)typingStyle
3042 {
3043     return [[self _bridgeForSelectedOrMainFrame] typingStyle];
3044 }
3045
3046 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
3047 {
3048     _private->smartInsertDeleteEnabled = flag;
3049 }
3050
3051 - (BOOL)smartInsertDeleteEnabled
3052 {
3053     return _private->smartInsertDeleteEnabled;
3054 }
3055
3056 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
3057 {
3058     _private->continuousSpellCheckingEnabled = flag;
3059     if ([self isContinuousSpellCheckingEnabled]) {
3060         [[self class] _preflightSpellChecker];
3061     } else {
3062         [[self mainFrame] _unmarkAllMisspellings];
3063     }
3064 }
3065
3066 - (BOOL)isContinuousSpellCheckingEnabled
3067 {
3068     return _private->continuousSpellCheckingEnabled && [self _continuousCheckingAllowed];
3069 }
3070
3071 - (WebNSInteger)spellCheckerDocumentTag
3072 {
3073     if (!_private->hasSpellCheckerDocumentTag) {
3074         _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
3075         _private->hasSpellCheckerDocumentTag = YES;
3076     }
3077     return _private->spellCheckerDocumentTag;
3078 }
3079
3080 - (NSUndoManager *)undoManager
3081 {
3082     NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
3083     if (undoManager) {
3084         return undoManager;
3085     }
3086     return [super undoManager];
3087 }
3088
3089 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
3090 {
3091     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3092     if ([_private->editingDelegate respondsToSelector:selector])
3093         [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
3094 }
3095
3096 - (void)setEditingDelegate:(id)delegate
3097 {
3098     if (_private->editingDelegate == delegate)
3099         return;
3100
3101     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3102
3103     // remove notifications from current delegate
3104     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
3105     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
3106     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
3107     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
3108     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
3109     
3110     _private->editingDelegate = delegate;
3111     [_private->editingDelegateForwarder release];
3112     _private->editingDelegateForwarder = nil;
3113     
3114     // add notifications for new delegate
3115     [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
3116     [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
3117     [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
3118     [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
3119     [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
3120 }
3121
3122 - (id)editingDelegate
3123 {
3124     return _private->editingDelegate;
3125 }
3126
3127 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
3128 {
3129     // FIXME: Should this really be attached to the document with the current selection?
3130     DOMCSSStyleDeclaration *decl = [[[self _bridgeForSelectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
3131     [decl setCssText:text];
3132     return decl;
3133 }
3134
3135 @end
3136
3137 @implementation WebView (WebViewUndoableEditing)
3138
3139 - (void)replaceSelectionWithNode:(DOMNode *)node
3140 {
3141     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO];
3142 }    
3143
3144 - (void)replaceSelectionWithText:(NSString *)text
3145 {
3146     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
3147 }
3148
3149 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
3150 {
3151     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
3152 }
3153
3154 - (void)replaceSelectionWithArchive:(WebArchive *)archive
3155 {
3156     [[[[self _bridgeForSelectedOrMainFrame] webFrame] dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
3157 }
3158
3159 - (void)deleteSelection
3160 {
3161     WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
3162     [bridge deleteSelectionWithSmartDelete:[(WebHTMLView *)[[[bridge webFrame] frameView] documentView] _canSmartCopyOrDelete]];
3163 }
3164     
3165 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
3166 {
3167     // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3168     // change the API to allow this.
3169     [[self _bridgeForSelectedOrMainFrame] applyStyle:style withUndoAction:WebUndoActionUnspecified];
3170 }
3171
3172 @end
3173
3174 @implementation WebView (WebViewEditingActions)
3175
3176 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
3177 {
3178     static BOOL reentered = NO;
3179     if (reentered) {
3180         [[self nextResponder] tryToPerform:selector with:parameter];
3181         return;
3182     }
3183
3184     // There are two possibilities here.
3185     //
3186     // One is that WebView has been called in its role as part of the responder chain.
3187     // In that case, it's fine to call the first responder and end up calling down the
3188     // responder chain again. Later we will return here with reentered = YES and continue
3189     // past the WebView.
3190     //
3191     // The other is that we are being called directly, in which case we want to pass the
3192     // selector down to the view inside us that can handle it, and continue down the
3193     // responder chain as usual.
3194
3195     // Pass this selector down to the first responder.
3196     NSResponder *responder = [self _responderForResponderOperations];
3197     reentered = YES;
3198     [responder tryToPerform:selector with:parameter];
3199     reentered = NO;
3200 }
3201
3202 #define FORWARD(name) \
3203     - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
3204
3205 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
3206
3207 - (void)insertText:(NSString *)text
3208 {
3209     [self _performResponderOperation:_cmd with:text];
3210 }
3211
3212 @end
3213
3214 @implementation WebView (WebViewEditingInMail)
3215
3216 - (void)_insertNewlineInQuotedContent;
3217 {
3218     [[self _bridgeForSelectedOrMainFrame] insertParagraphSeparatorInQuotedContent];
3219 }
3220
3221 - (BOOL)_selectWordBeforeMenuEvent
3222 {
3223     return _private->selectWordBeforeMenuEvent;
3224 }
3225
3226 - (void)_setSelectWordBeforeMenuEvent:(BOOL)flag
3227 {
3228     _private->selectWordBeforeMenuEvent = flag;
3229 }
3230
3231 @end
3232
3233 static WebFrameView *containingFrameView(NSView *view)
3234 {
3235     while (view && ![view isKindOfClass:[WebFrameView class]])
3236         view = [view superview];
3237     return (WebFrameView *)view;    
3238 }
3239
3240 @implementation WebView (WebFileInternal)
3241
3242 - (WebFrame *)_focusedFrame
3243 {
3244     NSResponder *resp = [[self window] firstResponder];
3245     if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) {
3246         WebFrameView *frameView = containingFrameView((NSView *)resp);
3247         ASSERT(frameView != nil);
3248         return [frameView webFrame];
3249     }
3250     
3251     return nil;
3252 }
3253
3254 - (WebFrame *)_selectedOrMainFrame
3255 {
3256     WebFrame *result = [self selectedFrame];
3257     if (result == nil)
3258         result = [self mainFrame];
3259     return result;
3260 }
3261
3262 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame
3263 {
3264     return [[self _selectedOrMainFrame] _bridge];
3265 }
3266
3267 - (BOOL)_isLoading
3268 {
3269     WebFrame *mainFrame = [self mainFrame];
3270     return [[mainFrame dataSource] isLoading]
3271         || [[mainFrame provisionalDataSource] isLoading];
3272 }
3273
3274 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
3275 {
3276     NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
3277     if (![view isDescendantOf:[[self mainFrame] frameView]])
3278         return nil;
3279     WebFrameView *frameView = containingFrameView(view);
3280     ASSERT(frameView);
3281     return frameView;
3282 }
3283
3284 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point
3285 {
3286     return [[[self _frameViewAtWindowPoint:[self convertPoint:point toView:nil]] webFrame] _bridge];
3287 }
3288
3289 + (void)_preflightSpellCheckerNow:(id)sender
3290 {
3291     [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
3292 }
3293
3294 + (void)_preflightSpellChecker
3295 {
3296     // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3297     if ([NSSpellChecker sharedSpellCheckerExists]) {
3298         [self _preflightSpellCheckerNow:self];
3299     } else {
3300         [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
3301     }
3302 }
3303
3304 - (BOOL)_continuousCheckingAllowed
3305 {
3306     static BOOL allowContinuousSpellChecking = YES;
3307     static BOOL readAllowContinuousSpellCheckingDefault = NO;
3308     if (!readAllowContinuousSpellCheckingDefault) {
3309         if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
3310             allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
3311         }
3312         readAllowContinuousSpellCheckingDefault = YES;
3313     }
3314     return allowContinuousSpellChecking;
3315 }
3316
3317 - (NSResponder *)_responderForResponderOperations
3318 {
3319     NSResponder *responder = [[self window] firstResponder];
3320     WebFrameView *mainFrameView = [[self mainFrame] frameView];
3321     
3322     // If the current responder is outside of the webview, use our main frameView or its
3323     // document view. We also do this for subviews of self that are siblings of the main
3324     // frameView since clients might insert non-webview-related views there (see 4552713).
3325     if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) {
3326         responder = [mainFrameView documentView];
3327         if (!responder)
3328             responder = mainFrameView;
3329     }
3330     return responder;
3331 }
3332
3333 - (void)_searchWithGoogleFromMenu:(id)sender
3334 {
3335     id documentView = [[[self mainFrame] frameView] documentView];
3336     if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3337         return;
3338     }
3339     
3340     NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3341     if ([selectedString length] == 0) {
3342         return;
3343     }
3344     
3345     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
3346     [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
3347     NSMutableString *s = [selectedString mutableCopy];
3348     const unichar nonBreakingSpaceCharacter = 0xA0;
3349     NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1];
3350     [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
3351     [pasteboard setString:s forType:NSStringPboardType];
3352     [s release];
3353     
3354     // FIXME: seems fragile to use the service by name, but this is what AppKit does
3355     NSPerformService(@"Search With Google", pasteboard);
3356 }
3357
3358 - (void)_searchWithSpotlightFromMenu:(id)sender
3359 {
3360     id documentView = [[[self mainFrame] frameView] documentView];
3361     if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3362         return;
3363     }
3364     
3365     NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3366     if ([selectedString length] == 0) {
3367         return;
3368     }
3369
3370     (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions);
3371 }
3372
3373 // Slightly funky method that lets us have one copy of the logic for finding docViews that can do
3374 // text sizing.  It returns whether it found any "suitable" doc views.  It sends sel to any suitable
3375 // doc views, or if sel==0 we do nothing to them.  For doc views that track our size factor, they are
3376 // suitable if doTrackingViews==YES (which in practice means that our size factor isn't at its max or
3377 // min).  For doc views that don't track it, we send them testSel to determine suitablility.  If we
3378 // do find any suitable tracking doc views and newScaleFactor!=0, we will set the common scale factor
3379 // to that new factor before we send sel to any of them. 
3380 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor
3381 {
3382     if ([[self mainFrame] dataSource] == nil) {
3383         return NO;
3384     }
3385     
3386     BOOL foundSome = NO;
3387     NSArray *docViews = [[self mainFrame] _documentViews];
3388     int i;
3389     for (i = [docViews count]-1; i >= 0; i--) {
3390         id docView = [docViews objectAtIndex:i];
3391         if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)]) {
3392             id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
3393             BOOL isSuitable;
3394             if ([sizingDocView _tracksCommonSizeFactor]) {
3395                 isSuitable = doTrackingViews;
3396                 if (isSuitable && newScaleFactor != 0) {
3397                     [self setTextSizeMultiplier:newScaleFactor];
3398                 }
3399             } else {
3400                 // Incantation to perform a selector returning a BOOL.
3401                 isSuitable = ((BOOL(*)(id, SEL))objc_msgSend)(sizingDocView, testSel);
3402             }
3403             
3404             if (isSuitable) {
3405                 if (sel != 0) {
3406                     foundSome = YES;
3407                     [sizingDocView performSelector:sel withObject:arg];
3408                 } else {
3409                     // if we're just called for the benefit of the return value, we can return at first match
3410                     return YES;
3411                 }
3412             }
3413         }
3414     }
3415     
3416     return foundSome;
3417 }
3418
3419 @end
3420
3421 @implementation WebView (WebViewBridge)
3422
3423 - (WebPageBridge *)_pageBridge
3424 {
3425     return _private->_pageBridge;
3426 }
3427
3428 @end