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