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