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