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