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