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