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