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