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