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