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