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