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