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