WebCore:
[WebKit-https.git] / WebKit / mac / WebView / WebView.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 David Smith (catfish.man@gmail.com)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #import "WebViewInternal.h"
31
32 #import "DOMRangeInternal.h"
33 #import "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 - (BOOL)_needsXcodeVisibilityQuirk
931 {
932     static BOOL checked = NO;
933     static BOOL needsQuirk = NO;
934
935     if (checked)
936         return needsQuirk;
937
938     needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_XCODE_QUIRK)
939         && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Xcode"];
940     checked = YES;
941
942     return needsQuirk;
943 }
944
945 - (void)_preferencesChangedNotification:(NSNotification *)notification
946 {
947     WebPreferences *preferences = (WebPreferences *)[notification object];
948     ASSERT(preferences == [self preferences]);
949
950     if (!_private->userAgentOverridden)
951         *_private->userAgent = String();
952
953     // Cache this value so we don't have to read NSUserDefaults on each page load
954     _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
955
956     // Update corresponding WebCore Settings object.
957     if (!_private->page)
958         return;
959     
960     Settings* settings = _private->page->settings();
961     
962     settings->setCursiveFontFamily([preferences cursiveFontFamily]);
963     settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]);
964     settings->setDefaultFontSize([preferences defaultFontSize]);
965     settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]);
966     settings->setFantasyFontFamily([preferences fantasyFontFamily]);
967     settings->setFixedFontFamily([preferences fixedFontFamily]);
968     settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]);
969     settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]);
970     settings->setJavaEnabled([preferences isJavaEnabled]);
971     settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]);
972     settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]);
973     settings->setMinimumFontSize([preferences minimumFontSize]);
974     settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]);
975     settings->setPluginsEnabled([preferences arePlugInsEnabled]);
976     settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]);
977     settings->setSansSerifFontFamily([preferences sansSerifFontFamily]);
978     settings->setSerifFontFamily([preferences serifFontFamily]);
979     settings->setStandardFontFamily([preferences standardFontFamily]);
980     settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]);
981     settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]);
982     settings->setTextAreasAreResizable([preferences textAreasAreResizable]);
983     settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]);
984     settings->setEditableLinkBehavior(core([preferences editableLinkBehavior]));
985     settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]);
986     settings->setUsesPageCache([self usesPageCache]);
987     settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]);
988     settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]);
989     settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]);
990     if ([preferences userStyleSheetEnabled]) {
991         NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString];
992         settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]);
993     } else
994         settings->setUserStyleSheetLocation([NSURL URLWithString:@""]);
995     settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]);
996     settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]);
997     settings->setNeedsXcodeVisibilityQuirk([self _needsXcodeVisibilityQuirk]);
998 }
999
1000 static inline IMP getMethod(id o, SEL s)
1001 {
1002     return [o respondsToSelector:s] ? [o methodForSelector:s] : 0;
1003 }
1004
1005 - (void)_cacheResourceLoadDelegateImplementations
1006 {
1007     WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
1008     id delegate = _private->resourceProgressDelegate;
1009
1010     if (!delegate) {
1011         bzero(cache, sizeof(WebResourceDelegateImplementationCache));
1012         return;
1013     }
1014
1015     cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1016     cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:));
1017     cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:));
1018     cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:));
1019     cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1020     cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:));
1021     cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:));
1022     cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:));
1023     cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:));
1024     cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:));
1025     cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:));
1026 }
1027
1028 WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *webView)
1029 {
1030     static WebResourceDelegateImplementationCache empty;
1031     if (!webView)
1032         return &empty;
1033     return &webView->_private->resourceLoadDelegateImplementations;
1034 }
1035
1036 - (void)_cacheFrameLoadDelegateImplementations
1037 {
1038     WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations;
1039     id delegate = _private->frameLoadDelegate;
1040
1041     if (!delegate) {
1042         bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache));
1043         return;
1044     }
1045
1046     cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:));
1047     cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:));
1048     cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:));
1049     cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:));
1050     cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:));
1051     cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:));
1052     cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:));
1053     cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:));
1054     cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:));
1055     cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:));
1056     cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:));
1057     cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:));
1058     cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:));
1059     cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:));
1060     cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:));
1061     cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:));
1062     cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:));
1063 }
1064
1065 WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *webView)
1066 {
1067     static WebFrameLoadDelegateImplementationCache empty;
1068     if (!webView)
1069         return &empty;
1070     return &webView->_private->frameLoadDelegateImplementations;
1071 }
1072
1073 - (id)_policyDelegateForwarder
1074 {
1075     if (!_private->policyDelegateForwarder)
1076         _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions];
1077     return _private->policyDelegateForwarder;
1078 }
1079
1080 - (id)_UIDelegateForwarder
1081 {
1082     if (!_private->UIDelegateForwarder)
1083         _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions];
1084     return _private->UIDelegateForwarder;
1085 }
1086
1087 - (id)_editingDelegateForwarder
1088 {
1089     // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
1090     // Not sure if that is a bug or not.
1091     if (!_private)
1092         return nil;
1093
1094     if (!_private->editingDelegateForwarder)
1095         _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions];
1096     return _private->editingDelegateForwarder;
1097 }
1098
1099 - (id)_scriptDebugDelegateForwarder
1100 {
1101     if (!_private->scriptDebugDelegateForwarder)
1102         _private->scriptDebugDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->scriptDebugDelegate defaultTarget:[WebDefaultScriptDebugDelegate sharedScriptDebugDelegate] catchExceptions:_private->catchesDelegateExceptions];
1103     return _private->scriptDebugDelegateForwarder;
1104 }
1105
1106 - (void)_closeWindow
1107 {
1108     [[self _UIDelegateForwarder] webViewClose:self];
1109 }
1110
1111 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
1112 {
1113     [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1114     [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1115     
1116     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1117     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
1118     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1119     MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType);
1120 }
1121
1122 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
1123 {
1124     NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
1125     [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
1126
1127     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1128     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
1129     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1130     if ([viewClass class] == [WebHTMLView class])
1131         MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
1132     
1133     // This is used to make _representationExistsForURLScheme faster.
1134     // Without this set, we'd have to create the MIME type each time.
1135     if (schemesWithRepresentationsSet == nil) {
1136         schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
1137     }
1138     [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
1139 }
1140
1141 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1142 {
1143     return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
1144 }
1145
1146 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1147 {
1148     return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
1149 }
1150
1151 + (BOOL)_canHandleRequest:(NSURLRequest *)request
1152 {
1153     // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed
1154     if (!request)
1155         return NO;
1156
1157     if ([NSURLConnection canHandleRequest:request])
1158         return YES;
1159
1160     NSString *scheme = [[request URL] scheme];
1161
1162     if ([self _representationExistsForURLScheme:scheme])
1163         return YES;
1164         
1165     return ([scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"]);
1166 }
1167
1168 + (NSString *)_decodeData:(NSData *)data
1169 {
1170     HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet
1171     RefPtr<TextResourceDecoder> decoder = new TextResourceDecoder("text/html"); // bookmark files are HTML
1172     String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]);
1173     result += decoder->flush();
1174     return result;
1175 }
1176
1177 - (void)_pushPerformingProgrammaticFocus
1178 {
1179     _private->programmaticFocusCount++;
1180 }
1181
1182 - (void)_popPerformingProgrammaticFocus
1183 {
1184     _private->programmaticFocusCount--;
1185 }
1186
1187 - (BOOL)_isPerformingProgrammaticFocus
1188 {
1189     return _private->programmaticFocusCount != 0;
1190 }
1191
1192 - (void)_didChangeValueForKey: (NSString *)key
1193 {
1194     LOG (Bindings, "calling didChangeValueForKey: %@", key);
1195     [self didChangeValueForKey: key];
1196 }
1197
1198 - (void)_willChangeValueForKey: (NSString *)key
1199 {
1200     LOG (Bindings, "calling willChangeValueForKey: %@", key);
1201     [self willChangeValueForKey: key];
1202 }
1203
1204 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1205     static NSSet *manualNotifyKeys = nil;
1206     if (!manualNotifyKeys)
1207         manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1208             _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1209     if ([manualNotifyKeys containsObject:key])
1210         return NO;
1211     return YES;
1212 }
1213
1214 - (NSArray *)_declaredKeys {
1215     static NSArray *declaredKeys = nil;
1216     if (!declaredKeys)
1217         declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1218             _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1219     return declaredKeys;
1220 }
1221
1222 - (void)setObservationInfo:(void *)info
1223 {
1224     _private->observationInfo = info;
1225 }
1226
1227 - (void *)observationInfo
1228 {
1229     return _private->observationInfo;
1230 }
1231
1232 - (void)_willChangeBackForwardKeys
1233 {
1234     [self _willChangeValueForKey: _WebCanGoBackKey];
1235     [self _willChangeValueForKey: _WebCanGoForwardKey];
1236 }
1237
1238 - (void)_didChangeBackForwardKeys
1239 {
1240     [self _didChangeValueForKey: _WebCanGoBackKey];
1241     [self _didChangeValueForKey: _WebCanGoForwardKey];
1242 }
1243
1244 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1245 {
1246     [self _willChangeBackForwardKeys];
1247     if (frame == [self mainFrame]){
1248         // Force an observer update by sending a will/did.
1249         [self _willChangeValueForKey: _WebIsLoadingKey];
1250         [self _didChangeValueForKey: _WebIsLoadingKey];
1251
1252         [self _willChangeValueForKey: _WebMainFrameURLKey];
1253     }
1254
1255     [NSApp setWindowsNeedUpdate:YES];
1256 }
1257
1258 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1259 {
1260     if (frame == [self mainFrame])
1261         [self _didChangeValueForKey: _WebMainFrameURLKey];
1262     [NSApp setWindowsNeedUpdate:YES];
1263 }
1264
1265 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1266 {
1267     [self _didChangeBackForwardKeys];
1268     if (frame == [self mainFrame]){
1269         // Force an observer update by sending a will/did.
1270         [self _willChangeValueForKey: _WebIsLoadingKey];
1271         [self _didChangeValueForKey: _WebIsLoadingKey];
1272     }
1273     [NSApp setWindowsNeedUpdate:YES];
1274 }
1275
1276 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1277 {
1278     [self _didChangeBackForwardKeys];
1279     if (frame == [self mainFrame]){
1280         // Force an observer update by sending a will/did.
1281         [self _willChangeValueForKey: _WebIsLoadingKey];
1282         [self _didChangeValueForKey: _WebIsLoadingKey];
1283     }
1284     [NSApp setWindowsNeedUpdate:YES];
1285 }
1286
1287 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1288 {
1289     [self _didChangeBackForwardKeys];
1290     if (frame == [self mainFrame]){
1291         // Force an observer update by sending a will/did.
1292         [self _willChangeValueForKey: _WebIsLoadingKey];
1293         [self _didChangeValueForKey: _WebIsLoadingKey];
1294         
1295         [self _didChangeValueForKey: _WebMainFrameURLKey];
1296     }
1297     [NSApp setWindowsNeedUpdate:YES];
1298 }
1299
1300 - (void)_reloadForPluginChanges
1301 {
1302     [[self mainFrame] _reloadForPluginChanges];
1303 }
1304
1305 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1306 {
1307     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1308     [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1309     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1310     [request release];
1311     return cachedResponse;
1312 }
1313
1314 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1315 {
1316     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1317     DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1318     [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
1319                         element:domElement
1320                             URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1321                           title:[element objectForKey:WebElementImageAltStringKey] 
1322                         archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1323                           types:types
1324                          source:nil];
1325 }
1326
1327 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1328 {
1329     [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1330                      andTitle:[element objectForKey:WebElementLinkLabelKey]
1331                         types:types];
1332 }
1333
1334 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1335 {
1336     if (!_private->page)
1337         return;
1338     _private->page->dragController()->setDidInitiateDrag(initiatedDrag);
1339 }
1340
1341 #define DASHBOARD_CONTROL_LABEL @"control"
1342
1343 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1344 {
1345     // Add scroller regions for NSScroller and KWQScrollBar
1346     int i, count = [views count];
1347     
1348     for (i = 0; i < count; i++) {
1349         NSView *aView = [views objectAtIndex:i];
1350         
1351         if ([aView isKindOfClass:[NSScroller class]] ||
1352             [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1353             NSRect bounds = [aView bounds];
1354             NSRect adjustedBounds;
1355             adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1356             adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1357             
1358             // AppKit has horrible hack of placing absent scrollers at -100,-100
1359             if (adjustedBounds.origin.y == -100)
1360                 continue;
1361             adjustedBounds.size = bounds.size;
1362             NSRect clip = [aView visibleRect];
1363             NSRect adjustedClip;
1364             adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1365             adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1366             adjustedClip.size = clip.size;
1367             WebDashboardRegion *aRegion = 
1368                         [[[WebDashboardRegion alloc] initWithRect:adjustedBounds 
1369                                     clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1370             NSMutableArray *scrollerRegions;
1371             scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1372             if (!scrollerRegions) {
1373                 scrollerRegions = [NSMutableArray array];
1374                 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1375             }
1376             [scrollerRegions addObject:aRegion];
1377         }
1378         [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1379     }
1380 }
1381
1382 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1383 {
1384     [self _addScrollerDashboardRegions:regions from:[self subviews]];
1385 }
1386
1387 - (NSDictionary *)_dashboardRegions
1388 {
1389     // Only return regions from main frame.
1390     Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1391     if (!mainFrame)
1392         return nil;
1393     NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary();
1394     [self _addScrollerDashboardRegions:regions];
1395     return regions;
1396 }
1397
1398 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag
1399 {
1400     // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement 
1401     // specific support for the backward compatibility mode flag.
1402     if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page)
1403         _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true);
1404     
1405     switch (behavior) {
1406         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1407             _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1408             break;
1409         }
1410         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1411             _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1412             break;
1413         }
1414         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1415             _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1416             break;
1417         }
1418         case WebDashboardBehaviorAllowWheelScrolling: {
1419             _private->dashboardBehaviorAllowWheelScrolling = flag;
1420             break;
1421         }
1422         case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1423             if (_private->page)
1424                 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag);
1425             break;
1426         }
1427     }
1428 }
1429
1430 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1431 {
1432     switch (behavior) {
1433         case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1434             return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1435         }
1436         case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1437             return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1438         }
1439         case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1440             return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1441         }
1442         case WebDashboardBehaviorAllowWheelScrolling: {
1443             return _private->dashboardBehaviorAllowWheelScrolling;
1444         }
1445         case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1446             return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode();
1447         }
1448     }
1449     return NO;
1450 }
1451
1452 + (void)_setShouldUseFontSmoothing:(BOOL)f
1453 {
1454     WebCoreSetShouldUseFontSmoothing(f);
1455 }
1456
1457 + (BOOL)_shouldUseFontSmoothing
1458 {
1459     return WebCoreShouldUseFontSmoothing();
1460 }
1461
1462 + (void)_setUsesTestModeFocusRingColor:(BOOL)f
1463 {
1464     setUsesTestModeFocusRingColor(f);
1465 }
1466
1467 + (BOOL)_usesTestModeFocusRingColor
1468 {
1469     return usesTestModeFocusRingColor();
1470 }
1471
1472 // This is only used by older versions of Safari and should be removed in a future release. 
1473 + (NSString *)_minimumRequiredSafariBuildNumber
1474 {
1475     return @"420+";
1476 }
1477
1478 - (void)setAlwaysShowVerticalScroller:(BOOL)flag
1479 {
1480     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1481     if (flag) {
1482         [scrollview setVerticalScrollingMode:WebCoreScrollbarAlwaysOn andLock:YES];
1483     } else {
1484         [scrollview setVerticalScrollingModeLocked:NO];
1485         [scrollview setVerticalScrollingMode:WebCoreScrollbarAuto];
1486     }
1487 }
1488
1489 - (BOOL)alwaysShowVerticalScroller
1490 {
1491     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1492     return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == WebCoreScrollbarAlwaysOn;
1493 }
1494
1495 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag
1496 {
1497     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1498     if (flag) {
1499         [scrollview setHorizontalScrollingMode:WebCoreScrollbarAlwaysOn andLock:YES];
1500     } else {
1501         [scrollview setHorizontalScrollingModeLocked:NO];
1502         [scrollview setHorizontalScrollingMode:WebCoreScrollbarAuto];
1503     }
1504 }
1505
1506 - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits
1507 {
1508     Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1509     if (mainFrame)
1510         mainFrame->setProhibitsScrolling(prohibits);
1511 }
1512
1513 - (BOOL)alwaysShowHorizontalScroller
1514 {
1515     WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1516     return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == WebCoreScrollbarAlwaysOn;
1517 }
1518
1519 - (void)_setInViewSourceMode:(BOOL)flag
1520 {
1521     Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1522     if (mainFrame)
1523         mainFrame->setInViewSourceMode(flag);
1524 }
1525
1526 - (BOOL)_inViewSourceMode
1527 {
1528     Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1529     return mainFrame && mainFrame->inViewSourceMode();
1530 }
1531
1532 - (void)_setUseFastImageScalingMode:(BOOL)flag
1533 {
1534     if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) {
1535         _private->page->setInLowQualityImageInterpolationMode(flag);
1536         [self setNeedsDisplay:YES];
1537     }
1538 }
1539
1540 - (BOOL)_inFastImageScalingMode
1541 {
1542     if (_private->page)
1543         return _private->page->inLowQualityImageInterpolationMode();
1544     return NO;
1545 }
1546
1547 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
1548 {
1549     if (!_private->pluginDatabase)
1550         _private->pluginDatabase = [[WebPluginDatabase alloc] init];
1551         
1552     [_private->pluginDatabase setPlugInPaths:newPaths];
1553     [_private->pluginDatabase refresh];
1554 }
1555
1556 - (void)_attachScriptDebuggerToAllFrames
1557 {
1558     for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext())
1559         [kit(frame) _attachScriptDebugger];
1560 }
1561
1562 - (void)_detachScriptDebuggerFromAllFrames
1563 {
1564     for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext())
1565         [kit(frame) _detachScriptDebugger];
1566 }
1567
1568 - (void)setBackgroundColor:(NSColor *)backgroundColor
1569 {
1570     if ([_private->backgroundColor isEqual:backgroundColor])
1571         return;
1572
1573     id old = _private->backgroundColor;
1574     _private->backgroundColor = [backgroundColor retain];
1575     [old release];
1576
1577     [[self mainFrame] _updateBackground];
1578 }
1579
1580 - (NSColor *)backgroundColor
1581 {
1582     return _private->backgroundColor;
1583 }
1584
1585 - (BOOL)defersCallbacks
1586 {
1587     if (!_private->page)
1588         return NO;
1589     return _private->page->defersLoading();
1590 }
1591
1592 - (void)setDefersCallbacks:(BOOL)defer
1593 {
1594     if (!_private->page)
1595         return;
1596     return _private->page->setDefersLoading(defer);
1597 }
1598
1599 // For backwards compatibility with the WebBackForwardList API, we honor both
1600 // a per-WebView and a per-preferences setting for whether to use the page cache.
1601
1602 - (BOOL)usesPageCache
1603 {
1604     return _private->usesPageCache && [[self preferences] usesPageCache];
1605 }
1606
1607 - (void)setUsesPageCache:(BOOL)usesPageCache
1608 {
1609     _private->usesPageCache = usesPageCache;
1610
1611     // Post a notification so the WebCore settings update.
1612     [[self preferences] _postPreferencesChangesNotification];
1613 }
1614
1615 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource 
1616 {
1617     NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window]; 
1618     [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; 
1619
1620
1621 - (void)_clearUndoRedoOperations
1622 {
1623     if (!_private->page)
1624         return;
1625     _private->page->clearUndoRedoOperations();
1626 }
1627
1628 - (void)_setCatchesDelegateExceptions:(BOOL)f
1629 {
1630     _private->catchesDelegateExceptions = f;
1631 }
1632
1633 - (BOOL)_catchesDelegateExceptions
1634 {
1635     return _private->catchesDelegateExceptions;
1636 }
1637
1638 - (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value
1639 {
1640     Frame* coreFrame = [[[self mainFrame] _bridge] _frame];
1641     if (!coreFrame)
1642         return;
1643     coreFrame->editor()->command(name).execute(value);
1644 }
1645
1646 @end
1647
1648 @implementation _WebSafeForwarder
1649
1650 // Used to send messages to delegates that implement informal protocols.
1651
1652 - (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c
1653 {
1654     self = [super init];
1655     if (!self)
1656         return nil;
1657     target = t; // Non retained.
1658     defaultTarget = dt;
1659     catchExceptions = c;
1660     return self;
1661 }
1662
1663 - (void)forwardInvocation:(NSInvocation *)invocation
1664 {
1665     if ([target respondsToSelector:[invocation selector]]) {
1666         if (catchExceptions) {
1667             @try {
1668                 [invocation invokeWithTarget:target];
1669             } @catch(id exception) {
1670                 ReportDiscardedDelegateException([invocation selector], exception);
1671             }
1672         } else
1673             [invocation invokeWithTarget:target];
1674         return;
1675     }
1676
1677     if ([defaultTarget respondsToSelector:[invocation selector]])
1678         [invocation invokeWithTarget:defaultTarget];
1679
1680     // Do nothing quietly if method not implemented.
1681 }
1682
1683 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1684 {
1685     return [defaultTarget methodSignatureForSelector:aSelector];
1686 }
1687
1688 @end
1689
1690 @implementation WebView
1691
1692 + (void)initialize
1693 {
1694     static BOOL initialized = NO;
1695     if (initialized)
1696         return;
1697     initialized = YES;
1698
1699     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp];
1700     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil];
1701     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil];
1702 }
1703
1704 + (void)_applicationWillTerminate
1705 {   
1706     applicationIsTerminating = YES;
1707     if (!pluginDatabaseClientCount)
1708         [WebPluginDatabase closeSharedDatabase];
1709 }
1710
1711 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1712 {
1713     return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1714 }
1715
1716 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
1717 {
1718     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType];
1719     if (pluginPackage)
1720         return pluginPackage;
1721     
1722     if (_private->pluginDatabase)
1723         return [_private->pluginDatabase pluginForMIMEType:MIMEType];
1724     
1725     return nil;
1726 }
1727
1728 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
1729 {
1730     WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension];
1731     if (pluginPackage)
1732         return pluginPackage;
1733     
1734     if (_private->pluginDatabase)
1735         return [_private->pluginDatabase pluginForExtension:extension];
1736     
1737     return nil;
1738 }
1739
1740 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
1741 {
1742     if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType])
1743         return YES;
1744         
1745     if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
1746         return YES;
1747     
1748     return NO;
1749 }
1750
1751 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1752 {
1753     return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1754 }
1755
1756 + (NSArray *)MIMETypesShownAsHTML
1757 {
1758     NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1759     NSEnumerator *enumerator = [viewTypes keyEnumerator];
1760     id key;
1761     NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1762     
1763     while ((key = [enumerator nextObject])) {
1764         if ([viewTypes objectForKey:key] == [WebHTMLView class])
1765             [array addObject:key];
1766     }
1767     
1768     return array;
1769 }
1770
1771 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1772 {
1773     NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy];
1774     NSEnumerator *enumerator = [viewTypes keyEnumerator];
1775     id key;
1776     while ((key = [enumerator nextObject])) {
1777         if ([viewTypes objectForKey:key] == [WebHTMLView class])
1778             [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1779     }
1780     
1781     int i, count = [MIMETypes count];
1782     for (i = 0; i < count; i++) {
1783         [WebView registerViewClass:[WebHTMLView class] 
1784                 representationClass:[WebHTMLRepresentation class] 
1785                 forMIMEType:[MIMETypes objectAtIndex:i]];
1786     }
1787     [viewTypes release];
1788 }
1789
1790 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1791 {
1792     return [pasteboard _web_bestURL];
1793 }
1794
1795 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1796 {
1797     return [pasteboard stringForType:WebURLNamePboardType];
1798 }
1799
1800 + (void)registerURLSchemeAsLocal:(NSString *)protocol
1801 {
1802     FrameLoader::registerURLSchemeAsLocal(protocol);
1803 }
1804
1805 - (void)_registerDraggedTypes
1806 {
1807     NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1808     NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1809     NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1810     [types addObjectsFromArray:URLTypes];
1811     [self registerForDraggedTypes:[types allObjects]];
1812     [types release];
1813 }
1814
1815 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1816 {
1817     WebPreferences *standardPreferences = [WebPreferences standardPreferences];
1818     [standardPreferences willAddToWebView];
1819
1820     _private->preferences = [standardPreferences retain];
1821     _private->catchesDelegateExceptions = YES;
1822     _private->mainFrameDocumentReady = NO;
1823     _private->drawsBackground = YES;
1824     _private->smartInsertDeleteEnabled = YES;
1825     _private->backgroundColor = [[NSColor whiteColor] retain];
1826
1827     NSRect f = [self frame];
1828     WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1829     [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1830     [self addSubview:frameView];
1831     [frameView release];
1832
1833     WebKitInitializeLoggingChannelsIfNecessary();
1834     WebCore::InitializeLoggingChannelsIfNecessary();
1835     [WebHistoryItem initWindowWatcherIfNecessary];
1836     WebKitInitializeDatabasesIfNecessary();
1837
1838     _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self));
1839     [[[WebFrameBridge alloc] initMainFrameWithPage:_private->page frameName:frameName frameView:frameView] release];
1840
1841     [self _addToAllWebViewsSet];
1842     [self setGroupName:groupName];
1843     
1844     // If there's already a next key view (e.g., from a nib), wire it up to our
1845     // contained frame view. In any case, wire our next key view up to the our
1846     // contained frame view. This works together with our becomeFirstResponder 
1847     // and setNextKeyView overrides.
1848     NSView *nextKeyView = [self nextKeyView];
1849     if (nextKeyView != nil && nextKeyView != frameView) {
1850         [frameView setNextKeyView:nextKeyView];
1851     }
1852     [super setNextKeyView:frameView];
1853
1854     ++WebViewCount;
1855
1856     [self _registerDraggedTypes];
1857
1858     // initialize WebScriptDebugServer here so listeners can register before any pages are loaded.
1859     if ([WebView _scriptDebuggerEnabled])
1860         [WebScriptDebugServer sharedScriptDebugServer];
1861
1862     WebPreferences *prefs = [self preferences];
1863     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1864                                                  name:WebPreferencesChangedNotification object:prefs];
1865
1866     // Post a notification so the WebCore settings update.
1867     [[self preferences] _postPreferencesChangesNotification];
1868
1869     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION))
1870         FrameLoader::setRestrictAccessToLocal(false);
1871 }
1872
1873 - (id)initWithFrame:(NSRect)f
1874 {
1875     return [self initWithFrame:f frameName:nil groupName:nil];
1876 }
1877
1878 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName;
1879 {
1880     self = [super initWithFrame:f];
1881     if (!self)
1882         return nil;
1883
1884 #ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1885     // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1886     // may not work with other WebKit applications.  Unsetting DYLD_FRAMEWORK_PATH removes the
1887     // need for Safari to unset it to prevent it from being passed to applications it launches.
1888     // Unsetting it when a WebView is first created is as good a place as any.
1889     // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details.
1890     if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1891         unsetenv("DYLD_FRAMEWORK_PATH");
1892         unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1893     }
1894 #endif
1895
1896     _private = [[WebViewPrivate alloc] init];
1897     [self _commonInitializationWithFrameName:frameName groupName:groupName];
1898     [self setMaintainsBackForwardList: YES];
1899     return self;
1900 }
1901
1902 - (id)initWithCoder:(NSCoder *)decoder
1903 {
1904     WebView *result = nil;
1905
1906     @try {
1907         NSString *frameName;
1908         NSString *groupName;
1909         WebPreferences *preferences;
1910         BOOL useBackForwardList = NO;
1911         BOOL allowsUndo = YES;
1912         
1913         result = [super initWithCoder:decoder];
1914         result->_private = [[WebViewPrivate alloc] init];
1915
1916         // We don't want any of the archived subviews. The subviews will always
1917         // be created in _commonInitializationFrameName:groupName:.
1918         [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1919
1920         if ([decoder allowsKeyedCoding]) {
1921             frameName = [decoder decodeObjectForKey:@"FrameName"];
1922             groupName = [decoder decodeObjectForKey:@"GroupName"];
1923             preferences = [decoder decodeObjectForKey:@"Preferences"];
1924             useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1925             if ([decoder containsValueForKey:@"AllowsUndo"])
1926                 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"];
1927         } else {
1928             int version;
1929             [decoder decodeValueOfObjCType:@encode(int) at:&version];
1930             frameName = [decoder decodeObject];
1931             groupName = [decoder decodeObject];
1932             preferences = [decoder decodeObject];
1933             if (version > 1)
1934                 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
1935             // The allowsUndo field is no longer written out in encodeWithCoder, but since there are
1936             // version 3 NIBs that have this field encoded, we still need to read it in.
1937             if (version == 3)
1938                 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo];
1939         }
1940
1941         if (![frameName isKindOfClass:[NSString class]])
1942             frameName = nil;
1943         if (![groupName isKindOfClass:[NSString class]])
1944             groupName = nil;
1945         if (![preferences isKindOfClass:[WebPreferences class]])
1946             preferences = nil;
1947
1948         LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
1949         [result _commonInitializationWithFrameName:frameName groupName:groupName];
1950         [result page]->backForwardList()->setEnabled(useBackForwardList);
1951         result->_private->allowsUndo = allowsUndo;
1952         if (preferences)
1953             [result setPreferences:preferences];
1954     } @catch (NSException *localException) {
1955         result = nil;
1956         [self release];
1957     }
1958
1959     return result;
1960 }
1961
1962 - (void)encodeWithCoder:(NSCoder *)encoder
1963 {
1964     // Set asside the subviews before we archive. We don't want to archive any subviews.
1965     // The subviews will always be created in _commonInitializationFrameName:groupName:.
1966     id originalSubviews = _subviews;
1967     _subviews = nil;
1968
1969     [super encodeWithCoder:encoder];
1970
1971     // Restore the subviews we set aside.
1972     _subviews = originalSubviews;
1973
1974     BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled();
1975     if ([encoder allowsKeyedCoding]) {
1976         [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1977         [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1978         [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1979         [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"];
1980         [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"];
1981     } else {
1982         int version = WebViewVersion;
1983         [encoder encodeValueOfObjCType:@encode(int) at:&version];
1984         [encoder encodeObject:[[self mainFrame] name]];
1985         [encoder encodeObject:[self groupName]];
1986         [encoder encodeObject:[self preferences]];
1987         [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList];
1988         // DO NOT encode any new fields here, doing so will break older WebKit releases.
1989     }
1990
1991     LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList);
1992 }
1993
1994 - (void)dealloc
1995 {
1996     // call close to ensure we tear-down completely
1997     // this maintains our old behavior for existing applications
1998     [self _close];
1999
2000     --WebViewCount;
2001     
2002     [_private release];
2003     // [super dealloc] can end up dispatching against _private (3466082)
2004     _private = nil;
2005
2006     [super dealloc];
2007 }
2008
2009 - (void)finalize
2010 {
2011     ASSERT(_private->closed);
2012
2013     --WebViewCount;
2014
2015     [super finalize];
2016 }
2017
2018 - (void)close
2019 {
2020     [self _close];
2021 }
2022
2023 - (void)setShouldCloseWithWindow:(BOOL)close
2024 {
2025     _private->shouldCloseWithWindow = close;
2026 }
2027
2028 - (BOOL)shouldCloseWithWindow
2029 {
2030     return _private->shouldCloseWithWindow;
2031 }
2032
2033 - (void)viewWillMoveToWindow:(NSWindow *)window
2034 {
2035     // Don't do anything if we aren't initialized.  This happens when decoding a WebView.
2036     if (!_private)
2037         return;
2038     
2039     if ([self window])
2040         [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
2041
2042     if (window) {
2043         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window];
2044
2045         // Ensure that we will receive the events that WebHTMLView (at least) needs. It's expensive enough
2046         // that we don't want to call it over and over.
2047         [window setAcceptsMouseMovedEvents:YES];
2048         WKSetNSWindowShouldPostEventNotifications(window, YES);
2049     }
2050 }
2051
2052 - (void)_windowWillClose:(NSNotification *)notification
2053 {
2054     if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow])))
2055         [self _close];
2056 }
2057
2058 - (void)setPreferences:(WebPreferences *)prefs
2059 {
2060     if (!prefs)
2061         prefs = [WebPreferences standardPreferences];
2062
2063     if (_private->preferences == prefs)
2064         return;
2065
2066     [prefs willAddToWebView];
2067
2068     WebPreferences *oldPrefs = _private->preferences;
2069
2070     [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
2071     [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]];
2072
2073     _private->preferences = [prefs retain];
2074
2075     // After registering for the notification, post it so the WebCore settings update.
2076     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
2077         name:WebPreferencesChangedNotification object:[self preferences]];
2078     [[self preferences] _postPreferencesChangesNotification];
2079
2080     [oldPrefs didRemoveFromWebView];
2081     [oldPrefs release];
2082 }
2083
2084 - (WebPreferences *)preferences
2085 {
2086     return _private->preferences;
2087 }
2088
2089 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
2090 {
2091     if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) {
2092         WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
2093         [self setPreferences:prefs];
2094         [prefs release];
2095     }
2096 }
2097
2098 - (NSString *)preferencesIdentifier
2099 {
2100     return [[self preferences] identifier];
2101 }
2102
2103
2104 - (void)setUIDelegate:delegate
2105 {
2106     _private->UIDelegate = delegate;
2107     [_private->UIDelegateForwarder release];
2108     _private->UIDelegateForwarder = nil;
2109 }
2110
2111 - UIDelegate
2112 {
2113     return _private->UIDelegate;
2114 }
2115
2116 - (void)setResourceLoadDelegate: delegate
2117 {
2118     _private->resourceProgressDelegate = delegate;
2119     [self _cacheResourceLoadDelegateImplementations];
2120 }
2121
2122 - resourceLoadDelegate
2123 {
2124     return _private->resourceProgressDelegate;
2125 }
2126
2127 - (void)setDownloadDelegate: delegate
2128 {
2129     _private->downloadDelegate = delegate;
2130 }
2131
2132
2133 - downloadDelegate
2134 {
2135     return _private->downloadDelegate;
2136 }
2137
2138 - (void)setPolicyDelegate:delegate
2139 {
2140     _private->policyDelegate = delegate;
2141     [_private->policyDelegateForwarder release];
2142     _private->policyDelegateForwarder = nil;
2143 }
2144
2145 - policyDelegate
2146 {
2147     return _private->policyDelegate;
2148 }
2149
2150 - (void)setFrameLoadDelegate:delegate
2151 {
2152     _private->frameLoadDelegate = delegate;
2153     [self _cacheFrameLoadDelegateImplementations];
2154
2155     // If this delegate wants callbacks for icons, fire up the icon database.
2156     if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc)
2157         [WebIconDatabase sharedIconDatabase];
2158 }
2159
2160 - frameLoadDelegate
2161 {
2162     return _private->frameLoadDelegate;
2163 }
2164
2165 - (WebFrame *)mainFrame
2166 {
2167     // This can be called in initialization, before _private has been set up (3465613)
2168     if (!_private)
2169         return nil;
2170     if (!_private->page)
2171         return nil;
2172     return kit(_private->page->mainFrame());
2173 }
2174
2175 - (WebFrame *)selectedFrame
2176 {
2177     // If the first responder is a view in our tree, we get the frame containing the first responder.
2178     // This is faster than searching the frame hierarchy, and will give us a result even in the case
2179     // where the focused frame doesn't actually contain a selection.
2180     WebFrame *focusedFrame = [self _focusedFrame];
2181     if (focusedFrame)
2182         return focusedFrame;
2183     
2184     // If the first responder is outside of our view tree, we search for a frame containing a selection.
2185     // There should be at most only one of these.
2186     return [[self mainFrame] _findFrameWithSelection];
2187 }
2188
2189 - (WebBackForwardList *)backForwardList
2190 {
2191     if (!_private->page)
2192         return nil;
2193     if (!_private->page->backForwardList()->enabled())
2194         return nil;
2195     return kit(_private->page->backForwardList());
2196 }
2197
2198 - (void)setMaintainsBackForwardList: (BOOL)flag
2199 {
2200     if (!_private->page)
2201         return;
2202     _private->page->backForwardList()->setEnabled(flag);
2203 }
2204
2205 - (BOOL)goBack
2206 {
2207     if (!_private->page)
2208         return NO;
2209     
2210     return _private->page->goBack();
2211 }
2212
2213 - (BOOL)goForward
2214 {
2215     if (!_private->page)
2216         return NO;
2217
2218     return _private->page->goForward();
2219 }
2220
2221 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
2222 {
2223     if (!_private->page)
2224         return NO;
2225
2226     _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward);
2227     return YES;
2228 }
2229
2230 - (void)setTextSizeMultiplier:(float)m
2231 {
2232     // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>)
2233     if (_private->textSizeMultiplier == m)
2234         return;
2235
2236     _private->textSizeMultiplier = m;
2237     [self _notifyTextSizeMultiplierChanged];
2238 }
2239
2240 - (float)textSizeMultiplier
2241 {
2242     return _private->textSizeMultiplier;
2243 }
2244
2245 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
2246 {
2247     NSString *name = [applicationName copy];
2248     [_private->applicationNameForUserAgent release];
2249     _private->applicationNameForUserAgent = name;
2250     if (!_private->userAgentOverridden)
2251         *_private->userAgent = String();
2252 }
2253
2254 - (NSString *)applicationNameForUserAgent
2255 {
2256     return [[_private->applicationNameForUserAgent retain] autorelease];
2257 }
2258
2259 - (void)setCustomUserAgent:(NSString *)userAgentString
2260 {
2261     *_private->userAgent = userAgentString;
2262     _private->userAgentOverridden = userAgentString != nil;
2263 }
2264
2265 - (NSString *)customUserAgent
2266 {
2267     if (!_private->userAgentOverridden)
2268         return nil;
2269     return *_private->userAgent;
2270 }
2271
2272 - (void)setMediaStyle:(NSString *)mediaStyle
2273 {
2274     if (_private->mediaStyle != mediaStyle) {
2275         [_private->mediaStyle release];
2276         _private->mediaStyle = [mediaStyle copy];
2277     }
2278 }
2279
2280 - (NSString *)mediaStyle
2281 {
2282     return _private->mediaStyle;
2283 }
2284
2285 - (BOOL)supportsTextEncoding
2286 {
2287     id documentView = [[[self mainFrame] frameView] documentView];
2288     return [documentView conformsToProtocol:@protocol(WebDocumentText)]
2289         && [documentView supportsTextEncoding];
2290 }
2291
2292 - (void)setCustomTextEncodingName:(NSString *)encoding
2293 {
2294     NSString *oldEncoding = [self customTextEncodingName];
2295     if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding])
2296         return;
2297     FrameLoader* mainFrameLoader = [[self mainFrame] _frameLoader];
2298     if (mainFrameLoader)
2299         mainFrameLoader->reloadAllowingStaleData(encoding);
2300 }
2301
2302 - (NSString *)_mainFrameOverrideEncoding
2303 {
2304     WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
2305     if (dataSource == nil)
2306         dataSource = [[self mainFrame] _dataSource];
2307     if (dataSource == nil)
2308         return nil;
2309     return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding());
2310 }
2311
2312 - (NSString *)customTextEncodingName
2313 {
2314     return [self _mainFrameOverrideEncoding];
2315 }
2316
2317 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
2318 {
2319     // Return statements are only valid in a function but some applications pass in scripts
2320     // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions
2321     // silently ignored the return. If the application is linked against an earlier version
2322     // of WebKit we will strip the return so the script wont fail.
2323     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) {
2324         NSRange returnStringRange = [script rangeOfString:@"return "];
2325         if (returnStringRange.length && !returnStringRange.location)
2326             script = [script substringFromIndex:returnStringRange.location + returnStringRange.length];
2327     }
2328
2329     NSString *result = [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
2330     // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script
2331     // Since there's no way to get rid of the main frame, result will never ever be nil here.
2332     ASSERT(result);
2333
2334     return result;
2335 }
2336
2337 - (WebScriptObject *)windowScriptObject
2338 {
2339     Frame* coreFrame = core([self mainFrame]);
2340     if (!coreFrame)
2341         return nil;
2342     return coreFrame->windowScriptObject();
2343 }
2344
2345 // Get the appropriate user-agent string for a particular URL.
2346 - (NSString *)userAgentForURL:(NSURL *)url
2347 {
2348     return [self _userAgentForURL:KURL([url absoluteURL])];
2349 }
2350
2351 - (void)setHostWindow:(NSWindow *)hostWindow
2352 {
2353     if (!_private->closed && hostWindow != _private->hostWindow) {
2354         [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
2355         if (_private->hostWindow)
2356             [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow];
2357         if (hostWindow)
2358             [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow];
2359         [_private->hostWindow release];
2360         _private->hostWindow = [hostWindow retain];
2361         [[self mainFrame] _viewDidMoveToHostWindow];
2362     }
2363 }
2364
2365 - (NSWindow *)hostWindow
2366 {
2367     return _private->hostWindow;
2368 }
2369
2370 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
2371 {
2372     return [[self _frameViewAtWindowPoint:point] documentView];
2373 }
2374
2375 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
2376 {
2377     WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
2378     if (!frameView)
2379         return nil;
2380     NSView <WebDocumentView> *documentView = [frameView documentView];
2381     if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
2382         NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
2383         return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
2384     }
2385     return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
2386 }
2387
2388 - (NSDictionary *)elementAtPoint:(NSPoint)point
2389 {
2390     return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2391 }
2392
2393 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2394 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. 
2395 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. 
2396 // Forward these calls to the document subview to make its scroll view scroll.
2397 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2398 {
2399     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2400     [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2401 }
2402
2403 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2404 {
2405     NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2406     return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2407 }
2408
2409 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2410 {
2411     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2412     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2413     IntPoint client([draggingInfo draggingLocation]);
2414     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2415     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2416     return core(self)->dragController()->dragEntered(&dragData);
2417 }
2418
2419 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2420 {
2421     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2422     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2423     IntPoint client([draggingInfo draggingLocation]);
2424     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2425     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2426     return core(self)->dragController()->dragUpdated(&dragData);
2427 }
2428
2429 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2430 {
2431     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2432     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2433     IntPoint client([draggingInfo draggingLocation]);
2434     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2435     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2436     core(self)->dragController()->dragExited(&dragData);
2437 }
2438
2439 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2440 {
2441     return YES;
2442 }
2443
2444 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2445 {
2446     NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2447     WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil);
2448     IntPoint client([draggingInfo draggingLocation]);
2449     IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2450     DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2451     return core(self)->dragController()->performDrag(&dragData);
2452 }
2453
2454 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2455 {
2456     NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2457     if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2458         return self;
2459     } else {
2460         return hitView;
2461     }
2462 }
2463
2464 - (BOOL)acceptsFirstResponder
2465 {
2466     return [[[self mainFrame] frameView] acceptsFirstResponder];
2467 }
2468
2469 - (BOOL)becomeFirstResponder
2470 {
2471     if (_private->becomingFirstResponder) {
2472         // Fix for unrepro infinite recursion reported in radar 4448181. If we hit this assert on
2473         // a debug build, we should figure out what causes the problem and do a better fix.
2474         ASSERT_NOT_REACHED();
2475         return NO;
2476     }
2477     
2478     // This works together with setNextKeyView to splice the WebView into
2479     // the key loop similar to the way NSScrollView does this. Note that
2480     // WebFrameView has very similar code.
2481     NSWindow *window = [self window];
2482     WebFrameView *mainFrameView = [[self mainFrame] frameView];
2483
2484     NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming];
2485     BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self);
2486     
2487     if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2488         NSView *previousValidKeyView = [self previousValidKeyView];
2489         if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2490             _private->becomingFirstResponder = YES;
2491             _private->becomingFirstResponderFromOutside = fromOutside;
2492             [window makeFirstResponder:previousValidKeyView];
2493             _private->becomingFirstResponderFromOutside = NO;
2494             _private->becomingFirstResponder = NO;
2495             return YES;
2496         } else {
2497             return NO;
2498         }
2499     }
2500     
2501     if ([mainFrameView acceptsFirstResponder]) {
2502         _private->becomingFirstResponder = YES;
2503         _private->becomingFirstResponderFromOutside = fromOutside;
2504         [window makeFirstResponder:mainFrameView];
2505         _private->becomingFirstResponderFromOutside = NO;
2506         _private->becomingFirstResponder = NO;
2507         return YES;
2508     } 
2509     
2510     return NO;
2511 }
2512
2513 - (NSView *)_webcore_effectiveFirstResponder
2514 {
2515     WebFrameView *frameView = [[self mainFrame] frameView];
2516     return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2517 }
2518
2519 - (void)setNextKeyView:(NSView *)aView
2520 {
2521     // This works together with becomeFirstResponder to splice the WebView into
2522     // the key loop similar to the way NSScrollView does this. Note that
2523     // WebFrameView has very similar code.
2524     WebFrameView *mainFrameView = [[self mainFrame] frameView];
2525     if (mainFrameView != nil) {
2526         [mainFrameView setNextKeyView:aView];
2527     } else {
2528         [super setNextKeyView:aView];
2529     }
2530 }
2531
2532 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2533 {
2534     Frame* coreFrame = core(curr);
2535     return kit(forward
2536         ? coreFrame->tree()->traverseNextWithWrap(wrapFlag)
2537         : coreFrame->tree()->traversePreviousWithWrap(wrapFlag));
2538 }
2539
2540 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2541 {
2542     return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
2543 }
2544
2545 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2546 {
2547     [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2548     [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2549     
2550     // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
2551     // in the WebCore MIMEType registry.  For now we're doing this in a safe, limited manner
2552     // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
2553     if ([viewClass class] == [WebHTMLView class])
2554         MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
2555 }
2556
2557 - (void)setGroupName:(NSString *)groupName
2558 {
2559     if (!_private->page)
2560         return;
2561     _private->page->setGroupName(groupName);
2562 }
2563
2564 - (NSString *)groupName
2565 {
2566     if (!_private->page)
2567         return nil;
2568     return _private->page->groupName();
2569 }
2570
2571 - (double)estimatedProgress
2572 {
2573     if (!_private->page)
2574         return 0.0;
2575
2576     return _private->page->progress()->estimatedProgress();
2577 }
2578
2579 - (NSArray *)pasteboardTypesForSelection
2580 {
2581     NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
2582     if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2583         return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2584     }
2585     return [NSArray array];
2586 }
2587
2588 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2589 {
2590     WebFrame *frame = [self _selectedOrMainFrame];
2591     if (frame && [frame _hasSelection]) {
2592         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2593         if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)])
2594             [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2595     }
2596 }
2597
2598 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2599 {
2600     if ([element objectForKey:WebElementImageURLKey] != nil) {
2601         return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2602     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2603         return [NSPasteboard _web_writableTypesForURL];
2604     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2605         return [self pasteboardTypesForSelection];
2606     }
2607     return [NSArray array];
2608 }
2609
2610 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2611 {
2612     if ([element objectForKey:WebElementImageURLKey] != nil) {
2613         [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2614     } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2615         [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2616     } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2617         [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2618     }
2619 }
2620
2621 - (void)moveDragCaretToPoint:(NSPoint)point
2622 {
2623     if (Page* page = core(self))
2624         page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil]));
2625 }
2626
2627 - (void)removeDragCaret
2628 {
2629     if (Page* page = core(self))
2630         page->dragController()->dragEnded();
2631 }
2632
2633 - (void)setMainFrameURL:(NSString *)URLString
2634 {
2635     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2636 }
2637
2638 - (NSString *)mainFrameURL
2639 {
2640     WebDataSource *ds;
2641     ds = [[self mainFrame] provisionalDataSource];
2642     if (!ds)
2643         ds = [[self mainFrame] _dataSource];
2644     return [[[ds request] URL] _web_originalDataAsString];
2645 }
2646
2647 - (BOOL)isLoading
2648 {
2649     LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2650     return [self _isLoading];
2651 }
2652
2653 - (NSString *)mainFrameTitle
2654 {
2655     NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle];
2656     return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
2657 }
2658
2659 - (NSImage *)mainFrameIcon
2660 {
2661     return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2662 }
2663
2664 - (DOMDocument *)mainFrameDocument
2665 {
2666     // only return the actual value if the state we're in gives NSTreeController
2667     // enough time to release its observers on the old model
2668     if (_private->mainFrameDocumentReady)
2669         return [[self mainFrame] DOMDocument];
2670     return nil;
2671 }
2672
2673 - (void)setDrawsBackground:(BOOL)drawsBackground
2674 {
2675     if (_private->drawsBackground == drawsBackground)
2676         return;
2677     _private->drawsBackground = drawsBackground;
2678     [[self mainFrame] _updateBackground];
2679 }
2680
2681 - (BOOL)drawsBackground
2682 {
2683     return _private->drawsBackground;
2684 }
2685
2686 @end
2687
2688 @implementation WebView (WebIBActions)
2689
2690 - (IBAction)takeStringURLFrom: sender
2691 {
2692     NSString *URLString = [sender stringValue];
2693     
2694     [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2695 }
2696
2697 - (BOOL)canGoBack
2698 {
2699     if (!_private->page)
2700         return NO;
2701
2702     return !!_private->page->backForwardList()->backItem();
2703 }
2704
2705 - (BOOL)canGoForward
2706 {
2707     if (!_private->page)
2708         return NO;
2709
2710     return !!_private->page->backForwardList()->forwardItem();
2711 }
2712
2713 - (IBAction)goBack:(id)sender
2714 {
2715     [self goBack];
2716 }
2717
2718 - (IBAction)goForward:(id)sender
2719 {
2720     [self goForward];
2721 }
2722
2723 - (IBAction)stopLoading:(id)sender
2724 {
2725     [[self mainFrame] stopLoading];
2726 }
2727
2728 - (IBAction)reload:(id)sender
2729 {
2730     [[self mainFrame] reload];
2731 }
2732
2733 #define MinimumTextSizeMultiplier       0.5f
2734 #define MaximumTextSizeMultiplier       3.0f
2735 #define TextSizeMultiplierRatio         1.2f
2736
2737 - (BOOL)canMakeTextSmaller
2738 {
2739     BOOL canShrinkMore = _private->textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2740     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:0];
2741 }
2742
2743 - (BOOL)canMakeTextLarger
2744 {
2745     BOOL canGrowMore = _private->textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2746     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:0];
2747 }
2748
2749 - (IBAction)makeTextSmaller:(id)sender
2750 {
2751     float newScale = _private->textSizeMultiplier / TextSizeMultiplierRatio;
2752     BOOL canShrinkMore = newScale > MinimumTextSizeMultiplier;
2753     [self _performTextSizingSelector:@selector(_makeTextSmaller:) withObject:sender onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:newScale];
2754 }
2755
2756 - (IBAction)makeTextLarger:(id)sender
2757 {
2758     float newScale = _private->textSizeMultiplier*TextSizeMultiplierRatio;
2759     BOOL canGrowMore = newScale < MaximumTextSizeMultiplier;
2760     [self _performTextSizingSelector:@selector(_makeTextLarger:) withObject:sender onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:newScale];
2761 }
2762
2763 - (IBAction)toggleSmartInsertDelete:(id)sender
2764 {
2765     [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2766 }
2767
2768 - (IBAction)toggleContinuousSpellChecking:(id)sender
2769 {
2770     [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2771 }
2772
2773 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2774 {
2775     id responder = [self _responderForResponderOperations];
2776     if (responder != self && [responder respondsToSelector:[item action]]) {
2777         if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)])
2778             return [responder validateUserInterfaceItemWithoutDelegate:item];
2779         if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)])
2780             return [responder validateUserInterfaceItem:item];
2781         return YES;
2782     }
2783     return NO;
2784 }
2785
2786 - (BOOL)canMakeTextStandardSize
2787 {
2788     BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2789     return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:0.0f];
2790 }
2791
2792 - (IBAction)makeTextStandardSize:(id)sender
2793 {
2794     BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2795     [self _performTextSizingSelector:@selector(_makeTextStandardSize:) withObject:sender onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:1.0f];
2796 }
2797
2798 #define VALIDATE(name) \
2799     else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2800
2801 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
2802 {
2803     SEL action = [item action];
2804
2805     if (action == @selector(goBack:)) {
2806         return [self canGoBack];
2807     } else if (action == @selector(goForward:)) {
2808         return [self canGoForward];
2809     } else if (action == @selector(makeTextLarger:)) {
2810         return [self canMakeTextLarger];
2811     } else if (action == @selector(makeTextSmaller:)) {
2812         return [self canMakeTextSmaller];
2813     } else if (action == @selector(makeTextStandardSize:)) {
2814         return [self canMakeTextStandardSize];
2815     } else if (action == @selector(reload:)) {
2816         return [[self mainFrame] _dataSource] != nil;
2817     } else if (action == @selector(stopLoading:)) {
2818         return [self _isLoading];
2819     } else if (action == @selector(toggleContinuousSpellChecking:)) {
2820         BOOL checkMark = NO;
2821         BOOL retVal = NO;
2822         if ([self _continuousCheckingAllowed]) {
2823             checkMark = [self isContinuousSpellCheckingEnabled];
2824             retVal = YES;
2825         }
2826         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2827             NSMenuItem *menuItem = (NSMenuItem *)item;
2828             [menuItem setState:checkMark ? NSOnState : NSOffState];
2829         }
2830         return retVal;
2831 #ifndef BUILDING_ON_TIGER
2832     } else if (action == @selector(toggleGrammarChecking:)) {
2833         BOOL checkMark = [self isGrammarCheckingEnabled];
2834         if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2835             NSMenuItem *menuItem = (NSMenuItem *)item;
2836             [menuItem setState:checkMark ? NSOnState : NSOffState];
2837         }
2838         return YES;
2839 #endif
2840     }
2841     FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2842
2843     return YES;
2844 }
2845
2846 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2847 {
2848     BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
2849     return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
2850 }
2851
2852 @end
2853
2854 @implementation WebView (WebPendingPublic)
2855
2856 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
2857 {
2858     if (_private->closed)
2859         return NO;
2860     
2861     // Get the frame holding the selection, or start with the main frame
2862     WebFrame *startFrame = [self _selectedOrMainFrame];
2863     
2864     // Search the first frame, then all the other frames, in order
2865     NSView <WebDocumentSearching> *startSearchView = nil;
2866     WebFrame *frame = startFrame;
2867     do {
2868         WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag);
2869         
2870         BOOL onlyOneFrame = (frame == nextFrame);
2871         ASSERT(!onlyOneFrame || frame == startFrame);
2872         
2873         id <WebDocumentView> view = [[frame frameView] documentView];
2874         if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2875             NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2876             
2877             if (frame == startFrame)
2878                 startSearchView = searchView;
2879             
2880             BOOL foundString;
2881             // In some cases we have to search some content twice; see comment later in this method.
2882             // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag 
2883             // here, and then bailing out before we get to the code that would search again in the
2884             // same content.
2885             BOOL wrapOnThisPass = wrapFlag && onlyOneFrame;
2886             if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
2887                 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection];
2888             else
2889                 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass];
2890             
2891             if (foundString) {
2892                 if (frame != startFrame)
2893                     [startFrame _clearSelection];
2894                 [[self window] makeFirstResponder:searchView];
2895                 return YES;
2896             }
2897             
2898             if (onlyOneFrame)
2899                 return NO;
2900         }
2901         frame = nextFrame;
2902     } while (frame && frame != startFrame);
2903     
2904     // 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 
2905     // 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 
2906     // 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
2907     // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice.
2908     // To fix this, we'd need to add a mechanism to specify a range in which to search.
2909     if (wrapFlag && startSearchView) {
2910         BOOL foundString;
2911         if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
2912             foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection];
2913         else
2914             foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES];
2915         if (foundString) {
2916             [[self window] makeFirstResponder:startSearchView];
2917             return YES;
2918         }
2919     }
2920     return NO;
2921 }
2922
2923 - (void)setHoverFeedbackSuspended:(BOOL)newValue
2924 {
2925     if (_private->hoverFeedbackSuspended == newValue)
2926         return;
2927     
2928     _private->hoverFeedbackSuspended = newValue;
2929     id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView];
2930     // FIXME: in a perfect world we'd do this in a general way that worked with any document view,
2931     // such as by calling a protocol method or using respondsToSelector or sending a notification.
2932     // But until there is any need for these more general solutions, we'll just hardwire it to work
2933     // with WebHTMLView.
2934     // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not
2935     // on each subframe separately.
2936     if ([documentView isKindOfClass:[WebHTMLView class]])
2937         [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged];
2938 }
2939
2940 - (BOOL)isHoverFeedbackSuspended
2941 {
2942     return _private->hoverFeedbackSuspended;
2943 }
2944
2945 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
2946 {
2947     // by setting this to NO, calls to mainFrameDocument are forced to return nil
2948     // setting this to YES lets it return the actual DOMDocument value
2949     // we use this to tell NSTreeController to reset its observers and clear its state
2950     if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
2951         return;
2952     [self _willChangeValueForKey:_WebMainFrameDocumentKey];
2953     _private->mainFrameDocumentReady = mainFrameDocumentReady;
2954     [self _didChangeValueForKey:_WebMainFrameDocumentKey];
2955     // this will cause observers to call mainFrameDocument where this flag will be checked
2956 }
2957
2958 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it 
2959 // until the day comes when we're no longer supporting Mail on Tiger.
2960 - (WebFrame *)_frameForCurrentSelection
2961 {
2962     return [self _selectedOrMainFrame];
2963 }
2964
2965 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements
2966 {
2967     _private->tabKeyCyclesThroughElementsChanged = YES;
2968     if (_private->page)
2969         _private->page->setTabKeyCyclesThroughElements(cyclesElements);
2970 }
2971
2972 - (BOOL)tabKeyCyclesThroughElements
2973 {
2974     return _private->page && _private->page->tabKeyCyclesThroughElements();
2975 }
2976
2977 - (void)setScriptDebugDelegate:(id)delegate
2978 {
2979     _private->scriptDebugDelegate = delegate;
2980     [_private->scriptDebugDelegateForwarder release];
2981     _private->scriptDebugDelegateForwarder = nil;
2982     if (delegate)
2983         [self _attachScriptDebuggerToAllFrames];
2984     else
2985         [self _detachScriptDebuggerFromAllFrames];
2986 }
2987
2988 - (id)scriptDebugDelegate
2989 {
2990     return _private->scriptDebugDelegate;
2991 }
2992
2993 - (BOOL)shouldClose
2994 {
2995     Frame* coreFrame = core([self mainFrame]);
2996     if (!coreFrame)
2997         return YES;
2998     return coreFrame->shouldClose();
2999 }
3000
3001 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
3002 {
3003     return [[[self mainFrame] _bridge] aeDescByEvaluatingJavaScriptFromString:script];
3004 }
3005
3006 - (BOOL)canMarkAllTextMatches
3007 {
3008     WebFrame *frame = [self mainFrame];
3009     do {
3010         id <WebDocumentView> view = [[frame frameView] documentView];
3011         if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)])
3012             return NO;
3013         
3014         frame = incrementFrame(frame, YES, NO);
3015     } while (frame);
3016     
3017     return YES;
3018 }
3019
3020 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit
3021 {
3022     WebFrame *frame = [self mainFrame];
3023     unsigned matchCount = 0;
3024     do {
3025         id <WebDocumentView> view = [[frame frameView] documentView];
3026         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
3027             [(NSView <WebMultipleTextMatches>*)view  setMarkedTextMatchesAreHighlighted:highlight];
3028         
3029             ASSERT(limit == 0 || matchCount < limit);
3030             matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
3031
3032             // Stop looking if we've reached the limit. A limit of 0 means no limit.
3033             if (limit > 0 && matchCount >= limit)
3034                 break;
3035         }
3036         
3037         frame = incrementFrame(frame, YES, NO);
3038     } while (frame);
3039     
3040     return matchCount;
3041 }
3042
3043 - (void)unmarkAllTextMatches
3044 {
3045     WebFrame *frame = [self mainFrame];
3046     do {
3047         id <WebDocumentView> view = [[frame frameView] documentView];
3048         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)])
3049             [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches];
3050         
3051         frame = incrementFrame(frame, YES, NO);
3052     } while (frame);
3053 }
3054
3055 - (NSArray *)rectsForTextMatches
3056 {
3057     NSMutableArray *result = [NSMutableArray array];
3058     WebFrame *frame = [self mainFrame];
3059     do {
3060         id <WebDocumentView> view = [[frame frameView] documentView];
3061         if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
3062             NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view;
3063             NSRect documentViewVisibleRect = [documentView visibleRect];
3064             NSArray *originalRects = [documentView rectsForTextMatches];
3065             unsigned rectCount = [originalRects count];
3066             unsigned rectIndex;
3067             NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3068             for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
3069                 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
3070                 // Clip rect to document view's visible rect so rect is confined to subframe
3071                 r = NSIntersectionRect(r, documentViewVisibleRect);
3072                 if (NSIsEmptyRect(r))
3073                     continue;
3074                 
3075                 // Convert rect to our coordinate system
3076                 r = [documentView convertRect:r toView:self];
3077                 [result addObject:[NSValue valueWithRect:r]];
3078                 if (rectIndex % 10 == 0) {
3079                     [pool drain];
3080                     pool = [[NSAutoreleasePool alloc] init];
3081                 }
3082             }
3083             [pool drain];
3084         }
3085         
3086         frame = incrementFrame(frame, YES, NO);
3087     } while (frame);
3088     
3089     return result;
3090 }
3091
3092 - (void)scrollDOMRangeToVisible:(DOMRange *)range
3093 {
3094     [[[range startContainer] _bridge] scrollDOMRangeToVisible:range];
3095 }
3096
3097 - (BOOL)allowsUndo
3098 {
3099     return _private->allowsUndo;
3100 }
3101
3102 - (void)setAllowsUndo:(BOOL)flag
3103 {
3104     _private->allowsUndo = flag;
3105 }
3106
3107 @end
3108
3109 @implementation WebView (WebViewPrintingPrivate)
3110
3111 - (float)_headerHeight
3112 {
3113     return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:));
3114 }
3115
3116 - (float)_footerHeight
3117 {
3118     return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:));
3119 }
3120
3121 - (void)_drawHeaderInRect:(NSRect)rect
3122 {
3123 #ifdef DEBUG_HEADER_AND_FOOTER
3124     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3125     [currentContext saveGraphicsState];
3126     [[NSColor yellowColor] set];
3127     NSRectFill(rect);
3128     [currentContext restoreGraphicsState];
3129 #endif
3130
3131     SEL selector = @selector(webView:drawHeaderInRect:);
3132     if (![_private->UIDelegate respondsToSelector:selector])
3133         return;
3134
3135     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3136     [currentContext saveGraphicsState];
3137
3138     NSRectClip(rect);
3139     CallUIDelegate(self, selector, rect);
3140
3141     [currentContext restoreGraphicsState];
3142 }
3143
3144 - (void)_drawFooterInRect:(NSRect)rect
3145 {
3146 #ifdef DEBUG_HEADER_AND_FOOTER
3147     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3148     [currentContext saveGraphicsState];
3149     [[NSColor cyanColor] set];
3150     NSRectFill(rect);
3151     [currentContext restoreGraphicsState];
3152 #endif
3153     
3154     SEL selector = @selector(webView:drawFooterInRect:);
3155     if (![_private->UIDelegate respondsToSelector:selector])
3156         return;
3157
3158     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3159     [currentContext saveGraphicsState];
3160
3161     NSRectClip(rect);
3162     CallUIDelegate(self, selector, rect);
3163
3164     [currentContext restoreGraphicsState];
3165 }
3166
3167 - (void)_adjustPrintingMarginsForHeaderAndFooter
3168 {
3169     NSPrintOperation *op = [NSPrintOperation currentOperation];
3170     NSPrintInfo *info = [op printInfo];
3171     NSMutableDictionary *infoDictionary = [info dictionary];
3172     
3173     // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the
3174     // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087),
3175     // we stash away the unmodified top and bottom margins the first time this method is called, and we read from
3176     // those stashed-away values on subsequent calls.
3177     float originalTopMargin;
3178     float originalBottomMargin;
3179     NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey];
3180     if (!originalTopMarginNumber) {
3181         ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]);
3182         originalTopMargin = [info topMargin];
3183         originalBottomMargin = [info bottomMargin];
3184         [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey];
3185         [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey];
3186     } else {
3187         ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]);
3188         ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]);
3189         originalTopMargin = [originalTopMarginNumber floatValue];
3190         originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue];
3191     }
3192     
3193     float scale = [op _web_pageSetupScaleFactor];
3194     [info setTopMargin:originalTopMargin + [self _headerHeight] * scale];
3195     [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale];
3196 }
3197
3198 - (void)_drawHeaderAndFooter
3199 {
3200     // The header and footer rect height scales with the page, but the width is always
3201     // all the way across the printed page (inset by printing margins).
3202     NSPrintOperation *op = [NSPrintOperation currentOperation];
3203     float scale = [op _web_pageSetupScaleFactor];
3204     NSPrintInfo *printInfo = [op printInfo];
3205     NSSize paperSize = [printInfo paperSize];
3206     float headerFooterLeft = [printInfo leftMargin]/scale;
3207     float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
3208     NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , 
3209                                    headerFooterWidth, [self _footerHeight]);
3210     NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, 
3211                                    headerFooterWidth, [self _headerHeight]);
3212     
3213     [self _drawHeaderInRect:headerRect];
3214     [self _drawFooterInRect:footerRect];
3215 }
3216 @end
3217
3218 @implementation WebView (WebDebugBinding)
3219
3220 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
3221 {
3222     LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
3223     [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
3224 }
3225
3226 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
3227 {
3228     LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
3229     [super removeObserver:anObserver forKeyPath:keyPath];
3230 }
3231
3232 @end
3233
3234 //==========================================================================================
3235 // Editing
3236
3237 @implementation WebView (WebViewCSS)
3238
3239 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
3240 {
3241     // FIXME: is this the best level for this conversion?
3242     if (pseudoElement == nil)
3243         pseudoElement = @"";
3244
3245     return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement];
3246 }
3247
3248 @end
3249
3250 @implementation WebView (WebViewEditing)
3251
3252 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
3253 {
3254     Page* page = core(self);
3255     if (!page)
3256         return nil;
3257     return kit(page->mainFrame()->editor()->rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get());
3258 }
3259
3260 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag;
3261 {
3262     // 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
3263     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"])
3264         return YES;
3265     return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
3266 }
3267
3268 - (BOOL)maintainsInactiveSelection
3269 {
3270     return NO;
3271 }
3272
3273 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
3274 {
3275     Frame* coreFrame = core([self _selectedOrMainFrame]);
3276     if (!coreFrame)
3277         return;
3278
3279     if (range == nil)
3280         coreFrame->selectionController()->clear();
3281     else {
3282         // Derive the frame to use from the range passed in.
3283         // Using _bridgeForSelectedOrMainFrame could give us a different document than
3284         // the one the range uses.
3285         coreFrame = core([range startContainer])->document()->frame();
3286         if (!coreFrame)
3287             return;
3288
3289         coreFrame->selectionController()->setSelectedRange([range _range], core(selectionAffinity), true);
3290     }
3291 }
3292
3293 - (DOMRange *)selectedDOMRange
3294 {
3295     Frame* coreFrame = core([self _selectedOrMainFrame]);
3296     if (!coreFrame)
3297         return nil;
3298     return kit(coreFrame->selectionController()->toRange().get());
3299 }
3300
3301 - (NSSelectionAffinity)selectionAffinity
3302 {
3303     Frame* coreFrame = core([self _selectedOrMainFrame]);
3304     if (!coreFrame)
3305         return NSSelectionAffinityDownstream;
3306     return kit(coreFrame->selectionController()->affinity());
3307 }
3308
3309 - (void)setEditable:(BOOL)flag
3310 {
3311     if (_private->editable != flag) {
3312         _private->editable = flag;
3313         if (!_private->tabKeyCyclesThroughElementsChanged && _private->page)
3314             _private->page->setTabKeyCyclesThroughElements(!flag);
3315         Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
3316         if (mainFrame) {
3317             if (flag) {
3318                 mainFrame->applyEditingStyleToBodyElement();
3319                 // If the WebView is made editable and the selection is empty, set it to something.
3320                 if (![self selectedDOMRange])
3321                     mainFrame->setSelectionFromNone();
3322             } else
3323                 mainFrame->removeEditingStyleFromBodyElement();
3324         }
3325     }
3326 }
3327
3328 - (BOOL)isEditable
3329 {
3330     return _private->editable;
3331 }
3332
3333 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
3334 {
3335     // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3336     // change the API to allow this.
3337     [[self _bridgeForSelectedOrMainFrame] setTypingStyle:style withUndoAction:EditActionUnspecified];
3338 }
3339
3340 - (DOMCSSStyleDeclaration *)typingStyle
3341 {
3342     return [[self _bridgeForSelectedOrMainFrame] typingStyle];
3343 }
3344
3345 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
3346 {
3347     _private->smartInsertDeleteEnabled = flag;
3348 }
3349
3350 - (BOOL)smartInsertDeleteEnabled
3351 {
3352     return _private->smartInsertDeleteEnabled;
3353 }
3354
3355 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
3356 {
3357     if (continuousSpellCheckingEnabled != flag) {
3358         continuousSpellCheckingEnabled = flag;
3359         [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled];
3360     }
3361     
3362     if ([self isContinuousSpellCheckingEnabled]) {
3363         [[self class] _preflightSpellChecker];
3364     } else {
3365         [[self mainFrame] _unmarkAllMisspellings];
3366     }
3367 }
3368
3369 - (BOOL)isContinuousSpellCheckingEnabled
3370 {
3371     return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]);
3372 }
3373
3374 - (NSInteger)spellCheckerDocumentTag
3375 {
3376     if (!_private->hasSpellCheckerDocumentTag) {
3377         _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
3378         _private->hasSpellCheckerDocumentTag = YES;
3379     }
3380     return _private->spellCheckerDocumentTag;
3381 }
3382
3383 - (NSUndoManager *)undoManager
3384 {
3385     if (!_private->allowsUndo)
3386         return nil;
3387
3388     NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
3389     if (undoManager)
3390         return undoManager;
3391
3392     return [super undoManager];
3393 }
3394
3395 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
3396 {
3397     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3398     if ([_private->editingDelegate respondsToSelector:selector])
3399         [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
3400 }
3401
3402 - (void)setEditingDelegate:(id)delegate
3403 {
3404     if (_private->editingDelegate == delegate)
3405         return;
3406
3407     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3408
3409     // remove notifications from current delegate
3410     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
3411     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
3412     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
3413     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
3414     [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
3415     
3416     _private->editingDelegate = delegate;
3417     [_private->editingDelegateForwarder release];
3418     _private->editingDelegateForwarder = nil;
3419     
3420     // add notifications for new delegate
3421     [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
3422     [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
3423     [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
3424     [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
3425     [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
3426 }
3427
3428 - (id)editingDelegate
3429 {
3430     return _private->editingDelegate;
3431 }
3432
3433 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
3434 {
3435     // FIXME: Should this really be attached to the document with the current selection?
3436     DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
3437     [decl setCssText:text];
3438     return decl;
3439 }
3440
3441 @end
3442
3443 @implementation WebView (WebViewGrammarChecking)
3444
3445 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze
3446 - (BOOL)isGrammarCheckingEnabled
3447 {
3448 #ifdef BUILDING_ON_TIGER
3449     return NO;
3450 #else
3451     return grammarCheckingEnabled;
3452 #endif
3453 }
3454
3455 #ifndef BUILDING_ON_TIGER
3456 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze
3457 - (void)setGrammarCheckingEnabled:(BOOL)flag
3458 {
3459     if (grammarCheckingEnabled == flag)
3460         return;
3461     
3462     grammarCheckingEnabled = flag;
3463     [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled];    
3464     
3465     // FIXME 4811447: workaround for lack of API
3466     NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
3467     if ([spellChecker respondsToSelector:@selector(_updateGrammar)])
3468         [spellChecker performSelector:@selector(_updateGrammar)];
3469     
3470     // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
3471     // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
3472     
3473     if (![self isGrammarCheckingEnabled])
3474         [[self mainFrame] _unmarkAllBadGrammar];
3475 }
3476
3477 // FIXME: This method should be merged into WebIBActions when we're not in API freeze
3478 - (void)toggleGrammarChecking:(id)sender
3479 {
3480     [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]];
3481 }
3482 #endif
3483
3484 @end
3485
3486 @implementation WebView (WebViewUndoableEditing)
3487
3488 - (void)replaceSelectionWithNode:(DOMNode *)node
3489 {
3490     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO];
3491 }    
3492
3493 - (void)replaceSelectionWithText:(NSString *)text
3494 {
3495     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
3496 }
3497
3498 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
3499 {
3500     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
3501 }
3502
3503 - (void)replaceSelectionWithArchive:(WebArchive *)archive
3504 {
3505     [[[[self _bridgeForSelectedOrMainFrame] webFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
3506 }
3507
3508 - (void)deleteSelection
3509 {
3510     WebFrame *webFrame = [self _selectedOrMainFrame];
3511     Frame* coreFrame = core(webFrame);
3512     if (coreFrame)
3513         coreFrame->editor()->deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]);
3514 }
3515     
3516 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
3517 {
3518     // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3519     // change the API to allow this.
3520     WebFrame *webFrame = [self _selectedOrMainFrame];
3521     Frame* coreFrame = core(webFrame);
3522     if (coreFrame)
3523         coreFrame->editor()->applyStyle(core(style));
3524 }
3525
3526 @end
3527
3528 @implementation WebView (WebViewEditingActions)
3529
3530 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
3531 {
3532     static BOOL reentered = NO;
3533     if (reentered) {
3534         [[self nextResponder] tryToPerform:selector with:parameter];
3535         return;
3536     }
3537
3538     // There are two possibilities here.
3539     //
3540     // One is that WebView has been called in its role as part of the responder chain.
3541     // In that case, it's fine to call the first responder and end up calling down the
3542     // responder chain again. Later we will return here with reentered = YES and continue
3543     // past the WebView.
3544     //
3545     // The other is that we are being called directly, in which case we want to pass the
3546     // selector down to the view inside us that can handle it, and continue down the
3547     // responder chain as usual.
3548
3549     // Pass this selector down to the first responder.
3550     NSResponder *responder = [self _responderForResponderOperations];
3551     reentered = YES;
3552     [responder tryToPerform:selector with:parameter];
3553     reentered = NO;
3554 }
3555
3556 #define FORWARD(name) \
3557     - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
3558
3559 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
3560
3561 - (void)insertText:(NSString *)text
3562 {
3563     [self _performResponderOperation:_cmd with:text];
3564 }
3565
3566 @end
3567
3568 @implementation WebView (WebViewEditingInMail)
3569
3570 - (void)_insertNewlineInQuotedContent;
3571 {
3572     [[self _bridgeForSelectedOrMainFrame] insertParagraphSeparatorInQuotedContent];
3573 }
3574
3575 - (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle
3576 {
3577     [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle];
3578 }
3579
3580 @end
3581
3582 static WebFrameView *containingFrameView(NSView *view)
3583 {
3584     while (view && ![view isKindOfClass:[WebFrameView class]])
3585         view = [view superview];
3586     return (WebFrameView *)view;    
3587 }
3588
3589 @implementation WebView (WebFileInternal)
3590
3591 + (void)_setCacheModel:(WebCacheModel)cacheModel
3592 {
3593     if (s_didSetCacheModel && cacheModel == s_cacheModel)
3594         return;
3595
3596     NSString *nsurlCacheDirectory = [(NSString *)WKCopyFoundationCacheDirectory() autorelease];
3597     if (!nsurlCacheDirectory)
3598         nsurlCacheDirectory = NSHomeDirectory();
3599
3600     // As a fudge factor, use 1000 instead of 1024, in case the reported byte 
3601     // count doesn't align exactly to a megabyte boundary.
3602     vm_size_t memSize = WebMemorySize() / 1024 / 1000;
3603     unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000;
3604     NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
3605
3606     unsigned cacheTotalCapacity = 0;
3607     unsigned cacheMinDeadCapacity = 0;
3608     unsigned cacheMaxDeadCapacity = 0;
3609
3610     unsigned pageCacheCapacity = 0;
3611
3612     NSUInteger nsurlCacheMemoryCapacity = 0;
3613     NSUInteger nsurlCacheDiskCapacity = 0;
3614
3615     switch (cacheModel) {
3616     case WebCacheModelDocumentViewer: {
3617         // Page cache capacity (in pages)
3618         pageCacheCapacity = 0;
3619
3620         // Object cache capacities (in bytes)
3621         if (memSize >= 4096)
3622             cacheTotalCapacity = 256 * 1024 * 1024;
3623         else if (memSize >= 3072)
3624             cacheTotalCapacity = 192 * 1024 * 1024;
3625         else if (memSize >= 2048)
3626             cacheTotalCapacity = 128 * 1024 * 1024;
3627         else if (memSize >= 1536)
3628             cacheTotalCapacity = 86 * 1024 * 1024;
3629         else if (memSize >= 1024)
3630             cacheTotalCapacity = 64 * 1024 * 1024;
3631         else if (memSize >= 512)
3632             cacheTotalCapacity = 32 * 1024 * 1024;
3633         else if (memSize >= 256)
3634             cacheTotalCapacity = 16 * 1024 * 1024; 
3635
3636         cacheMinDeadCapacity = 0;
3637         cacheMaxDeadCapacity = 0;
3638
3639         // Foundation memory cache capacity (in bytes)
3640         nsurlCacheMemoryCapacity = 0;
3641
3642         // Foundation disk cache capacity (in bytes)
3643         nsurlCacheDiskCapacity = [nsurlCache diskCapacity];
3644
3645         break;
3646     }
3647     case WebCacheModelDocumentBrowser: {
3648         // Page cache capacity (in pages)
3649         if (memSize >= 1024)
3650             pageCacheCapacity = 3;
3651         else if (memSize >= 512)
3652             pageCacheCapacity = 2;
3653         else if (memSize >= 256)
3654             pageCacheCapacity = 1;
3655         else
3656             pageCacheCapacity = 0;
3657
3658         // Object cache capacities (in bytes)
3659         if (memSize >= 4096)
3660             cacheTotalCapacity = 256 * 1024 * 1024;
3661         else if (memSize >= 3072)
3662             cacheTotalCapacity = 192 * 1024 * 1024;
3663         else if (memSize >= 2048)
3664             cacheTotalCapacity = 128 * 1024 * 1024;
3665         else if (memSize >= 1536)
3666             cacheTotalCapacity = 86 * 1024 * 1024;
3667         else if (memSize >= 1024)
3668             cacheTotalCapacity = 64 * 1024 * 1024;
3669         else if (memSize >= 512)
3670             cacheTotalCapacity = 32 * 1024 * 1024;
3671         else if (memSize >= 256)
3672             cacheTotalCapacity = 16 * 1024 * 1024; 
3673
3674         cacheMinDeadCapacity = cacheTotalCapacity / 8;
3675         cacheMaxDeadCapacity = cacheTotalCapacity / 4;
3676
3677         // Foundation memory cache capacity (in bytes)
3678         if (memSize >= 2048)
3679             nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
3680         else if (memSize >= 1024)
3681             nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
3682         else if (memSize >= 512)
3683             nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
3684         else