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