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