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