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