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