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