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