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