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