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