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