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