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