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