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