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