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