2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import <WebKit/WebViewInternal.h>
31 #import <WebKit/DOM.h>
32 #import <WebKit/DOMExtensions.h>
33 #import <WebKit/WebAssertions.h>
34 #import <WebKit/WebBackForwardList.h>
35 #import <WebKit/WebBaseNetscapePluginView.h>
36 #import <WebKit/WebBridge.h>
37 #import <WebKit/WebControllerSets.h>
38 #import <WebKit/WebDashboardRegion.h>
39 #import <WebKit/WebDataProtocol.h>
40 #import <WebKit/WebDataSourcePrivate.h>
41 #import <WebKit/WebDefaultEditingDelegate.h>
42 #import <WebKit/WebDefaultFrameLoadDelegate.h>
43 #import <WebKit/WebDefaultPolicyDelegate.h>
44 #import <WebKit/WebDefaultResourceLoadDelegate.h>
45 #import <WebKit/WebDefaultUIDelegate.h>
46 #import <WebKit/WebDOMOperationsPrivate.h>
47 #import <WebKit/WebDocument.h>
48 #import <WebKit/WebDocumentInternal.h>
49 #import <WebKit/WebDynamicScrollBarsView.h>
50 #import <WebKit/WebDownload.h>
51 #import <WebKit/WebEditingDelegate.h>
52 #import <WebKit/WebException.h>
53 #import <WebKit/WebFormDelegatePrivate.h>
54 #import <WebKit/WebFrameInternal.h>
55 #import <WebKit/WebFrameViewInternal.h>
56 #import <WebKit/WebHistoryItemPrivate.h>
57 #import <WebKit/WebHTMLRepresentation.h>
58 #import <WebKit/WebHTMLViewInternal.h>
59 #import <WebKit/WebIconDatabase.h>
60 #import <WebKit/WebKitErrors.h>
61 #import <WebKit/WebKitLogging.h>
62 #import <WebKit/WebKitNSStringExtras.h>
63 #import <WebKit/WebKitStatisticsPrivate.h>
64 #import <WebKit/WebNSDataExtras.h>
65 #import <WebKit/WebNSDictionaryExtras.h>
66 #import <WebKit/WebNSObjectExtras.h>
67 #import <WebKit/WebNSPasteboardExtras.h>
68 #import <WebKit/WebNSPrintOperationExtras.h>
69 #import <WebKit/WebNSEventExtras.h>
70 #import <WebKit/WebNSURLExtras.h>
71 #import <WebKit/WebNSURLRequestExtras.h>
72 #import <WebKit/WebNSUserDefaultsExtras.h>
73 #import <WebKit/WebNSViewExtras.h>
74 #import <WebKit/WebPluginDatabase.h>
75 #import <WebKit/WebPolicyDelegate.h>
76 #import <WebKit/WebPreferencesPrivate.h>
77 #import <WebKit/WebResourceLoadDelegate.h>
78 #import <WebKit/WebTextView.h>
79 #import <WebKit/WebTextRepresentation.h>
80 #import <WebKit/WebTextRenderer.h>
81 #import <WebKit/WebUIDelegate.h>
82 #import <WebKit/WebUIDelegatePrivate.h>
84 #import <WebCore/WebCoreEncodings.h>
85 #import <WebCore/WebCoreSettings.h>
86 #import <WebCore/WebCoreView.h>
88 #import <Foundation/NSURLConnection.h>
89 #import <Foundation/NSURLDownloadPrivate.h>
90 #import <Foundation/NSURLFileTypeMappings.h>
92 #if !BUILDING_ON_PANTHER
93 #include <CoreGraphics/CGSConnection.h>
96 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
98 macro(alignJustified) \
101 macro(capitalizeWord) \
102 macro(centerSelectionInVisibleArea) \
103 macro(changeAttributes) \
105 macro(changeDocumentBackgroundColor) \
107 macro(checkSpelling) \
113 macro(deleteBackward) \
114 macro(deleteBackwardByDecomposingPreviousCharacter) \
115 macro(deleteForward) \
116 macro(deleteToBeginningOfLine) \
117 macro(deleteToBeginningOfParagraph) \
118 macro(deleteToEndOfLine) \
119 macro(deleteToEndOfParagraph) \
120 macro(deleteWordBackward) \
121 macro(deleteWordForward) \
122 macro(ignoreSpelling) \
124 macro(insertBacktab) \
125 macro(insertNewline) \
126 macro(insertNewlineIgnoringFieldEditor) \
127 macro(insertParagraphSeparator) \
129 macro(insertTabIgnoringFieldEditor) \
130 macro(lowercaseWord) \
131 macro(moveBackward) \
132 macro(moveBackwardAndModifySelection) \
134 macro(moveDownAndModifySelection) \
136 macro(moveForwardAndModifySelection) \
138 macro(moveLeftAndModifySelection) \
140 macro(moveRightAndModifySelection) \
141 macro(moveToBeginningOfDocument) \
142 macro(moveToBeginningOfDocumentAndModifySelection) \
143 macro(moveToBeginningOfLine) \
144 macro(moveToBeginningOfLineAndModifySelection) \
145 macro(moveToBeginningOfParagraph) \
146 macro(moveToBeginningOfParagraphAndModifySelection) \
147 macro(moveToEndOfDocument) \
148 macro(moveToEndOfDocumentAndModifySelection) \
149 macro(moveToEndOfLine) \
150 macro(moveToEndOfLineAndModifySelection) \
151 macro(moveToEndOfParagraph) \
152 macro(moveToEndOfParagraphAndModifySelection) \
154 macro(moveUpAndModifySelection) \
155 macro(moveWordBackward) \
156 macro(moveWordBackwardAndModifySelection) \
157 macro(moveWordForward) \
158 macro(moveWordForwardAndModifySelection) \
159 macro(moveWordLeft) \
160 macro(moveWordLeftAndModifySelection) \
161 macro(moveWordRight) \
162 macro(moveWordRightAndModifySelection) \
166 macro(pasteAsPlainText) \
167 macro(pasteAsRichText) \
169 macro(performFindPanelAction) \
170 macro(scrollLineDown) \
171 macro(scrollLineUp) \
172 macro(scrollPageDown) \
173 macro(scrollPageUp) \
176 macro(selectParagraph) \
178 macro(showGuessPanel) \
179 macro(startSpeaking) \
180 macro(stopSpeaking) \
185 macro(uppercaseWord) \
187 macro(yankAndSelect) \
189 @interface NSSpellChecker (AppKitSecretsIKnow)
190 - (void)_preflightChosenSpellServer;
193 @interface NSView (AppKitSecretsIKnow)
194 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
195 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
196 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
199 #if !BUILDING_ON_PANTHER
200 @interface NSApplication (AppKitSecrectsIKnow)
201 - (CGSConnectionID)contextID;
205 @interface NSObject (WebDocumentSearchingHack)
206 // FIXME: this should be part of a protocol (new version of <WebDocumentSearching>)
207 - (BOOL)_searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag findInSelection:(BOOL)inSelectionFlag;
210 @interface WebView (WebFileInternal)
211 - (void)_preflightSpellChecker;
212 - (BOOL)_continuousCheckingAllowed;
213 - (NSResponder *)_responderForResponderOperations;
216 NSString *WebElementDOMNodeKey = @"WebElementDOMNode";
217 NSString *WebElementFrameKey = @"WebElementFrame";
218 NSString *WebElementImageKey = @"WebElementImage";
219 NSString *WebElementImageAltStringKey = @"WebElementImageAltString";
220 NSString *WebElementImageRectKey = @"WebElementImageRect";
221 NSString *WebElementImageURLKey = @"WebElementImageURL";
222 NSString *WebElementIsSelectedKey = @"WebElementIsSelected";
223 NSString *WebElementLinkURLKey = @"WebElementLinkURL";
224 NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame";
225 NSString *WebElementLinkLabelKey = @"WebElementLinkLabel";
226 NSString *WebElementLinkTitleKey = @"WebElementLinkTitle";
228 NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification";
229 NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification";
230 NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification";
232 NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification";
233 NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification";
234 NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification";
235 NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification";
236 NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification";
238 enum { WebViewVersion = 2 };
240 #define timedLayoutSize 4096
242 static NSMutableSet *schemesWithRepresentationsSet;
244 NSString *_WebCanGoBackKey = @"canGoBack";
245 NSString *_WebCanGoForwardKey = @"canGoForward";
246 NSString *_WebEstimatedProgressKey = @"estimatedProgress";
247 NSString *_WebIsLoadingKey = @"isLoading";
248 NSString *_WebMainFrameIconKey = @"mainFrameIcon";
249 NSString *_WebMainFrameTitleKey = @"mainFrameTitle";
250 NSString *_WebMainFrameURLKey = @"mainFrameURL";
252 @interface WebProgressItem : NSObject
255 long long bytesReceived;
256 long long estimatedLength;
260 @implementation WebProgressItem
263 static BOOL shouldUseFontSmoothing = YES;
265 @implementation WebViewPrivate
269 backForwardList = [[WebBackForwardList alloc] init];
270 textSizeMultiplier = 1;
271 progressNotificationInterval = 0.02;
272 progressNotificationTimeInterval = 0.1;
273 settings = [[WebCoreSettings alloc] init];
274 dashboardBehaviorAllowWheelScrolling = YES;
281 ASSERT(mainFrame == nil);
282 ASSERT(draggingDocumentView == nil);
283 ASSERT(dragCaretBridge == nil);
285 [backForwardList release];
286 [applicationNameForUserAgent release];
289 [preferences release];
291 [hostWindow release];
293 [policyDelegateForwarder release];
294 [resourceProgressDelegateForwarder release];
295 [UIDelegateForwarder release];
296 [frameLoadDelegateForwarder release];
297 [editingDelegateForwarder release];
299 [progressItems release];
301 [mediaStyle release];
308 @implementation WebView (WebPrivate)
310 #ifdef DEBUG_WIDGET_DRAWING
311 static bool debugWidget = true;
312 - (void)drawRect:(NSRect)rect
314 [[NSColor blueColor] set];
317 NSRect htmlViewRect = [[[[self mainFrame] frameView] documentView] frame];
320 while (debugWidget) {
325 NSLog (@"%s: rect: (%0.f,%0.f) %0.f %0.f, htmlViewRect: (%0.f,%0.f) %0.f %0.f\n",
326 __PRETTY_FUNCTION__, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
327 htmlViewRect.origin.x, htmlViewRect.origin.y, htmlViewRect.size.width, htmlViewRect.size.height
330 [super drawRect:rect];
334 + (NSArray *)_supportedMIMETypes
336 // Load the plug-in DB allowing plug-ins to install types.
337 [WebPluginDatabase installedPlugins];
338 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
341 + (NSArray *)_supportedFileExtensions
343 NSMutableSet *extensions = [[NSMutableSet alloc] init];
344 NSArray *MIMETypes = [self _supportedMIMETypes];
345 NSEnumerator *enumerator = [MIMETypes objectEnumerator];
347 NSURLFileTypeMappings *mappings = [NSURLFileTypeMappings sharedMappings];
348 while ((MIMEType = [enumerator nextObject]) != nil) {
349 NSArray *extensionsForType = [mappings extensionsForMIMEType:MIMEType];
350 if (extensionsForType) {
351 [extensions addObjectsFromArray:extensionsForType];
354 NSArray *uniqueExtensions = [extensions allObjects];
355 [extensions release];
356 return uniqueExtensions;
359 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
361 MIMEType = [MIMEType lowercaseString];
365 // Simple optimization that avoids loading the plug-in DB and image types for the HTML case.
366 if ([self canShowMIMETypeAsHTML:MIMEType]) {
367 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
368 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
369 if (viewClass && repClass) {
380 // Load the plug-in DB allowing plug-ins to install types.
381 [WebPluginDatabase installedPlugins];
383 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
384 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
385 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
386 if (viewClass && repClass) {
387 // Special-case WebTextView for text types that shouldn't be shown.
388 if (viewClass == [WebTextView class] &&
389 repClass == [WebTextRepresentation class] &&
390 [[WebTextView unsupportedTextMIMETypes] containsObject:MIMEType]) {
405 + (void)_setAlwaysUseATSU:(BOOL)f
407 [WebTextRenderer _setAlwaysUseATSU:f];
410 + (BOOL)canShowFile:(NSString *)path
412 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
415 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
417 return [[NSURLFileTypeMappings sharedMappings] preferredExtensionForMIMEType:type];
422 if (_private->setName != nil) {
423 [WebViewSets removeWebView:self fromSetNamed:_private->setName];
424 [_private->setName release];
425 _private->setName = nil;
428 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
429 [self removeDragCaret];
431 [_private->mainFrame _detachFromParent];
432 [_private->mainFrame release];
433 _private->mainFrame = nil;
435 // Clear the page cache so we call destroy on all the plug-ins in the page cache to break any retain cycles.
436 // See comment in [WebHistoryItem _releaseAllPendingPageCaches] for more information.
437 [_private->backForwardList _clearPageCache];
439 if (_private->hasSpellCheckerDocumentTag) {
440 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
441 _private->hasSpellCheckerDocumentTag = NO;
445 - (WebFrame *)_createFrameNamed:(NSString *)fname inParent:(WebFrame *)parent allowsScrolling:(BOOL)allowsScrolling
447 WebFrameView *childView = [[WebFrameView alloc] initWithFrame:NSMakeRect(0,0,0,0)];
449 [childView _setWebView:self];
450 [childView setAllowsScrolling:allowsScrolling];
452 WebFrame *newFrame = [[WebFrame alloc] initWithName:fname webFrameView:childView webView:self];
456 [parent _addChild:newFrame];
463 - (void)_finishedLoadingResourceFromDataSource: (WebDataSource *)dataSource
465 WebFrame *frame = [dataSource webFrame];
467 ASSERT(dataSource != nil);
469 // This resource has completed, so check if the load is complete for all frames.
471 [frame _transitionToLayoutAcceptable];
472 [frame _checkLoadComplete];
476 - (void)_mainReceivedBytesSoFar: (unsigned)bytesSoFar fromDataSource: (WebDataSource *)dataSource complete: (BOOL)isComplete
478 WebFrame *frame = [dataSource webFrame];
480 ASSERT(dataSource != nil);
482 // The frame may be nil if a previously cancelled load is still making progress callbacks.
486 // This resource has completed, so check if the load is complete for all frames.
488 // If the load is complete, mark the primary load as done. The primary load is the load
489 // of the main document. Other resources may still be arriving.
490 [dataSource _setPrimaryLoadComplete: YES];
491 [frame _checkLoadComplete];
494 // If the frame isn't complete it might be ready for a layout. Perform that check here.
495 // Note that transitioning a frame to this state doesn't guarantee a layout, rather it
496 // just indicates that an early layout can be performed.
497 if ((int)bytesSoFar > timedLayoutSize)
498 [frame _transitionToLayoutAcceptable];
502 - (void)_receivedError: (NSError *)error fromDataSource: (WebDataSource *)dataSource
504 WebFrame *frame = [dataSource webFrame];
506 [frame _checkLoadComplete];
510 - (void)_mainReceivedError:(NSError *)error fromDataSource:(WebDataSource *)dataSource complete:(BOOL)isComplete
514 ASSERT([dataSource webFrame]);
517 [dataSource _setMainDocumentError: error];
520 [dataSource _setPrimaryLoadComplete:YES];
521 [[dataSource webFrame] _checkLoadComplete];
525 + (NSString *)_MIMETypeForFile:(NSString *)path
527 NSString *extension = [path pathExtension];
528 NSString *MIMEType = nil;
530 // FIXME: This is a workaround to make web archive files work with Foundations that
531 // are too old to know about web archive files. We should remove this before we ship.
532 if ([extension _webkit_isCaseInsensitiveEqualToString:@"webarchive"]) {
533 return @"application/x-webarchive";
536 // Get the MIME type from the extension.
537 if ([extension length] != 0) {
538 MIMEType = [[NSURLFileTypeMappings sharedMappings] MIMETypeForExtension:extension];
541 // If we can't get a known MIME type from the extension, sniff.
542 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
543 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
544 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
546 if ([data length] != 0) {
547 MIMEType = [data _webkit_guessedMIMEType];
549 if ([MIMEType length] == 0) {
550 MIMEType = @"application/octet-stream";
557 - (void)_downloadURL:(NSURL *)URL
559 [self _downloadURL:URL toDirectory:nil];
562 - (void)_downloadURL:(NSURL *)URL toDirectory:(NSString *)directory
566 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
567 [WebDownload _downloadWithRequest:request
568 delegate:_private->downloadDelegate
569 directory:[directory isAbsolutePath] ? directory : nil];
573 - (BOOL)defersCallbacks
575 return _private->defersCallbacks;
578 - (void)setDefersCallbacks:(BOOL)defers
580 if (defers == _private->defersCallbacks) {
584 _private->defersCallbacks = defers;
585 [_private->mainFrame _defersCallbacksChanged];
588 - (void)_setTopLevelFrameName:(NSString *)name
590 [[self mainFrame] _setName:name];
593 - (WebFrame *)_findFrameInThisWindowNamed:(NSString *)name sourceFrame:(WebFrame *)source
595 return [[self mainFrame] _descendantFrameNamed:name sourceFrame:(WebFrame *)source];
598 - (WebFrame *)_findFrameNamed:(NSString *)name sourceFrame:(WebFrame *)source
600 // Try this WebView first.
601 WebFrame *frame = [self _findFrameInThisWindowNamed:name sourceFrame:source];
607 // Try other WebViews in the same set
608 if (_private->setName != nil) {
609 NSEnumerator *enumerator = [WebViewSets webViewsInSetNamed:_private->setName];
611 while ((webView = [enumerator nextObject]) != nil && frame == nil) {
612 frame = [webView _findFrameInThisWindowNamed:name sourceFrame:source];
619 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
621 id wd = [self UIDelegate];
622 WebView *newWindowWebView = nil;
623 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
624 newWindowWebView = [wd webView:self createWebViewWithRequest:request];
626 newWindowWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:self createWebViewWithRequest: request];
629 [[newWindowWebView _UIDelegateForwarder] webViewShow: newWindowWebView];
631 return newWindowWebView;
634 - (NSMenu *)_menuForElement:(NSDictionary *)element
636 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate]
637 webView:self contextMenuItemsForElement:element defaultMenuItems:nil];
638 NSArray *menuItems = defaultMenuItems;
642 if (_private->UIDelegate) {
643 id cd = _private->UIDelegate;
645 if ([cd respondsToSelector:@selector(webView:contextMenuItemsForElement:defaultMenuItems:)])
646 menuItems = [cd webView:self contextMenuItemsForElement:element defaultMenuItems:defaultMenuItems];
649 if (menuItems && [menuItems count] > 0) {
650 menu = [[[NSMenu alloc] init] autorelease];
652 for (i=0; i<[menuItems count]; i++) {
653 [menu addItem:[menuItems objectAtIndex:i]];
660 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(unsigned)modifierFlags
662 // When the mouse isn't over this view at all, we'll get called with a dictionary of nil over
663 // and over again. So it's a good idea to catch that here and not send multiple calls to the delegate
666 if (dictionary && _private->lastElementWasNonNil) {
667 [[self _UIDelegateForwarder] webView:self mouseDidMoveOverElement:dictionary modifierFlags:modifierFlags];
669 _private->lastElementWasNonNil = dictionary != nil;
672 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
674 // We never go back/forward on a per-frame basis, so the target must be the main frame
675 //ASSERT([item target] == nil || [self _findFrameNamed:[item target]] == [self mainFrame]);
677 // abort any current load if we're going back/forward
678 [[self mainFrame] stopLoading];
679 [[self mainFrame] _goToItem:item withLoadType:type];
682 // Not used now, but could be if we ever store frames in bookmarks or history
683 - (void)_loadItem:(WebHistoryItem *)item
685 WebHistoryItem *newItem = [item copy]; // Makes a deep copy, happily
686 [[self backForwardList] addItem:newItem];
687 [self _goToItem:newItem withLoadType:WebFrameLoadTypeIndexedBackForward];
690 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
692 // It turns out the right combination of behavior is done with the back/forward load
693 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items
694 // in the back forward list, and go to the current one.
696 WebBackForwardList *bfList = [self backForwardList];
697 ASSERT(![bfList currentItem]); // destination list should be empty
699 WebBackForwardList *otherBFList = [otherView backForwardList];
700 if (![otherBFList currentItem]) {
701 return; // empty back forward list, bail
704 WebHistoryItem *newItemToGoTo = nil;
705 int lastItemIndex = [otherBFList forwardListCount];
707 for (i = -[otherBFList backListCount]; i <= lastItemIndex; i++) {
709 // If this item is showing , save away its current scroll and form state,
710 // since that might have changed since loading and it is normally not saved
711 // until we leave that page.
712 [[otherView mainFrame] _saveDocumentAndScrollState];
714 WebHistoryItem *newItem = [[otherBFList itemAtIndex:i] copy];
715 [bfList addItem:newItem];
717 newItemToGoTo = newItem;
721 [self _goToItem:newItemToGoTo withLoadType:WebFrameLoadTypeIndexedBackForward];
724 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
726 _private->formDelegate = delegate;
729 - (id<WebFormDelegate>)_formDelegate
731 if (!_private->formDelegate) {
732 // create lazily, to give the client a chance to set one before we bother to alloc the shared one
733 _private->formDelegate = [WebFormDelegate _sharedWebFormDelegate];
735 return _private->formDelegate;
738 - (WebCoreSettings *)_settings
740 return _private->settings;
743 - (void)_updateWebCoreSettingsFromPreferences: (WebPreferences *)preferences
745 [_private->settings setCursiveFontFamily:[preferences cursiveFontFamily]];
746 [_private->settings setDefaultFixedFontSize:[preferences defaultFixedFontSize]];
747 [_private->settings setDefaultFontSize:[preferences defaultFontSize]];
748 [_private->settings setDefaultTextEncoding:[preferences defaultTextEncodingName]];
749 [_private->settings setFantasyFontFamily:[preferences fantasyFontFamily]];
750 [_private->settings setFixedFontFamily:[preferences fixedFontFamily]];
751 [_private->settings setJavaEnabled:[preferences isJavaEnabled]];
752 [_private->settings setJavaScriptEnabled:[preferences isJavaScriptEnabled]];
753 [_private->settings setJavaScriptCanOpenWindowsAutomatically:[preferences javaScriptCanOpenWindowsAutomatically]];
754 [_private->settings setMinimumFontSize:[preferences minimumFontSize]];
755 [_private->settings setMinimumLogicalFontSize:[preferences minimumLogicalFontSize]];
756 [_private->settings setPluginsEnabled:[preferences arePlugInsEnabled]];
757 [_private->settings setSansSerifFontFamily:[preferences sansSerifFontFamily]];
758 [_private->settings setSerifFontFamily:[preferences serifFontFamily]];
759 [_private->settings setStandardFontFamily:[preferences standardFontFamily]];
760 [_private->settings setWillLoadImagesAutomatically:[preferences loadsImagesAutomatically]];
762 if ([preferences userStyleSheetEnabled]) {
763 [_private->settings setUserStyleSheetLocation:[[preferences userStyleSheetLocation] _web_originalDataAsString]];
765 [_private->settings setUserStyleSheetLocation:@""];
767 [_private->settings setShouldPrintBackgrounds:[preferences shouldPrintBackgrounds]];
768 [_private->settings setTextAreasAreResizable:[preferences textAreasAreResizable]];
771 - (void)_preferencesChangedNotification: (NSNotification *)notification
773 WebPreferences *preferences = (WebPreferences *)[notification object];
775 ASSERT(preferences == [self preferences]);
776 if (!_private->userAgentOverridden) {
777 [_private->userAgent release];
778 _private->userAgent = nil;
780 [self _updateWebCoreSettingsFromPreferences: preferences];
783 - _frameLoadDelegateForwarder
785 if (!_private->frameLoadDelegateForwarder)
786 _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self frameLoadDelegate] defaultTarget: [WebDefaultFrameLoadDelegate sharedFrameLoadDelegate] templateClass: [WebDefaultFrameLoadDelegate class]];
787 return _private->frameLoadDelegateForwarder;
790 - _resourceLoadDelegateForwarder
792 if (!_private->resourceProgressDelegateForwarder)
793 _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
794 return _private->resourceProgressDelegateForwarder;
797 - (void)_cacheResourceLoadDelegateImplementations
799 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
800 id delegate = [self resourceLoadDelegate];
802 cache->delegateImplementsDidCancelAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:)];
803 cache->delegateImplementsDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)];
804 cache->delegateImplementsDidFinishLoadingFromDataSource = [delegate respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)];
805 cache->delegateImplementsDidReceiveContentLength = [delegate respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)];
806 cache->delegateImplementsDidReceiveResponse = [delegate respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)];
807 cache->delegateImplementsWillSendRequest = [delegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)];
808 cache->delegateImplementsIdentifierForRequest = [delegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)];
811 - (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
813 return _private->resourceLoadDelegateImplementations;
816 - _policyDelegateForwarder
818 if (!_private->policyDelegateForwarder)
819 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
820 return _private->policyDelegateForwarder;
823 - _UIDelegateForwarder
825 if (!_private->UIDelegateForwarder)
826 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self UIDelegate] defaultTarget: [WebDefaultUIDelegate sharedUIDelegate] templateClass: [WebDefaultUIDelegate class]];
827 return _private->UIDelegateForwarder;
830 - _editingDelegateForwarder
832 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
833 // Not sure if that is a bug or not.
836 if (!_private->editingDelegateForwarder)
837 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self editingDelegate] defaultTarget: [WebDefaultEditingDelegate sharedEditingDelegate] templateClass: [WebDefaultEditingDelegate class]];
838 return _private->editingDelegateForwarder;
841 - (WebFrame *)_frameForDataSource: (WebDataSource *)dataSource fromFrame: (WebFrame *)frame
845 WebFrame *result, *aFrame;
847 if ([frame dataSource] == dataSource)
850 if ([frame provisionalDataSource] == dataSource)
853 // It's safe to use the internal version because we know this
854 // function will not change the set of frames
855 frames = [frame _internalChildFrames];
856 count = [frames count];
857 for (i = 0; i < count; i++){
858 aFrame = [frames objectAtIndex: i];
859 result = [self _frameForDataSource: dataSource fromFrame: aFrame];
868 - (WebFrame *)_frameForDataSource: (WebDataSource *)dataSource
870 WebFrame *frame = [self mainFrame];
872 return [self _frameForDataSource: dataSource fromFrame: frame];
876 - (WebFrame *)_frameForView: (WebFrameView *)aView fromFrame: (WebFrame *)frame
880 WebFrame *result, *aFrame;
882 if ([frame frameView] == aView)
885 // It's safe to use the internal version because we know this
886 // function will not change the set of frames
887 frames = [frame _internalChildFrames];
888 count = [frames count];
889 for (i = 0; i < count; i++){
890 aFrame = [frames objectAtIndex: i];
891 result = [self _frameForView: aView fromFrame: aFrame];
899 - (WebFrame *)_frameForView: (WebFrameView *)aView
901 WebFrame *frame = [self mainFrame];
903 return [self _frameForView: aView fromFrame: frame];
908 [[self _UIDelegateForwarder] webViewClose:self];
911 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
913 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
914 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
917 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
919 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
920 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
922 // This is used to make _representationExistsForURLScheme faster.
923 // Without this set, we'd have to create the MIME type each time.
924 if (schemesWithRepresentationsSet == nil) {
925 schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
927 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
930 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
932 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
935 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
937 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
940 + (BOOL)_canHandleRequest:(NSURLRequest *)request
942 if ([NSURLConnection canHandleRequest:request]) {
946 // We're always willing to load alternate content for unreachable URLs
947 if ([request _webDataRequestUnreachableURL]) {
951 return [self _representationExistsForURLScheme:[[request URL] scheme]];
954 + (NSString *)_decodeData:(NSData *)data
956 return [WebCoreEncodings decodeData:data];
959 - (void)_pushPerformingProgrammaticFocus
961 _private->programmaticFocusCount++;
964 - (void)_popPerformingProgrammaticFocus
966 _private->programmaticFocusCount--;
969 - (BOOL)_isPerformingProgrammaticFocus
971 return _private->programmaticFocusCount != 0;
974 #define UnknownTotalBytes -1
975 #define WebProgressItemDefaultEstimatedLength 1024*16
977 - (void)_didChangeValueForKey: (NSString *)key
979 LOG (Bindings, "calling didChangeValueForKey: %@", key);
980 [self didChangeValueForKey: key];
983 - (void)_willChangeValueForKey: (NSString *)key
985 LOG (Bindings, "calling willChangeValueForKey: %@", key);
986 [self willChangeValueForKey: key];
989 // Always start progress at INITIAL_PROGRESS_VALUE so it appears progress indicators
990 // will immediately show some progress. This helps provide feedback as soon as a load
992 #define INITIAL_PROGRESS_VALUE 0.1
994 - (void)_resetProgress
996 [_private->progressItems release];
997 _private->progressItems = nil;
998 _private->totalPageAndResourceBytesToLoad = 0;
999 _private->totalBytesReceived = 0;
1000 _private->progressValue = 0;
1001 _private->lastNotifiedProgressValue = 0;
1002 _private->lastNotifiedProgressTime = 0;
1003 _private->finalProgressChangedSent = NO;
1004 _private->numProgressTrackedFrames = 0;
1005 [_private->orginatingProgressFrame release];
1006 _private->orginatingProgressFrame = nil;
1008 - (void)_progressStarted:(WebFrame *)frame
1010 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1011 [self _willChangeValueForKey: @"estimatedProgress"];
1012 if (_private->numProgressTrackedFrames == 0 || _private->orginatingProgressFrame == frame){
1013 [self _resetProgress];
1014 _private->progressValue = INITIAL_PROGRESS_VALUE;
1015 _private->orginatingProgressFrame = [frame retain];
1016 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:self];
1018 _private->numProgressTrackedFrames++;
1019 [self _didChangeValueForKey: @"estimatedProgress"];
1022 - (void)_finalProgressComplete
1026 // Before resetting progress value be sure to send client a least one notification
1027 // with final progress value.
1028 if (!_private->finalProgressChangedSent) {
1029 _private->progressValue = 1;
1030 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1033 [self _resetProgress];
1035 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:self];
1038 - (void)_progressCompleted:(WebFrame *)frame
1040 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1042 if (_private->numProgressTrackedFrames <= 0)
1045 [self _willChangeValueForKey: @"estimatedProgress"];
1047 _private->numProgressTrackedFrames--;
1048 if (_private->numProgressTrackedFrames == 0 ||
1049 (frame == _private->orginatingProgressFrame && _private->numProgressTrackedFrames != 0)){
1050 [self _finalProgressComplete];
1052 [self _didChangeValueForKey: @"estimatedProgress"];
1055 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate response:(NSURLResponse *)response;
1057 if (!connectionDelegate)
1060 LOG (Progress, "_private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1062 if (_private->numProgressTrackedFrames <= 0)
1065 WebProgressItem *item = [[WebProgressItem alloc] init];
1070 long long length = [response expectedContentLength];
1072 length = WebProgressItemDefaultEstimatedLength;
1074 item->estimatedLength = length;
1075 _private->totalPageAndResourceBytesToLoad += length;
1077 if (!_private->progressItems)
1078 _private->progressItems = [[NSMutableDictionary alloc] init];
1080 [_private->progressItems _webkit_setObject:item forUncopiedKey:connectionDelegate];
1084 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate data:(NSData *)data
1086 if (!connectionDelegate)
1089 WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
1094 [self _willChangeValueForKey: @"estimatedProgress"];
1096 unsigned bytesReceived = [data length];
1097 double increment = 0, percentOfRemainingBytes;
1098 long long remainingBytes, estimatedBytesForPendingRequests;
1100 item->bytesReceived += bytesReceived;
1101 if (item->bytesReceived > item->estimatedLength){
1102 _private->totalPageAndResourceBytesToLoad += ((item->bytesReceived*2) - item->estimatedLength);
1103 item->estimatedLength = item->bytesReceived*2;
1106 int numPendingOrLoadingRequests = [[self mainFrame] _numPendingOrLoadingRequests:YES];
1107 estimatedBytesForPendingRequests = WebProgressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
1108 remainingBytes = ((_private->totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - _private->totalBytesReceived);
1109 percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
1110 increment = (1.0 - _private->progressValue) * percentOfRemainingBytes;
1112 _private->totalBytesReceived += bytesReceived;
1114 _private->progressValue += increment;
1116 if (_private->progressValue < 0.0)
1117 _private->progressValue = 0.0;
1119 if (_private->progressValue > 1.0)
1120 _private->progressValue = 1.0;
1122 double now = CFAbsoluteTimeGetCurrent();
1123 double notifiedProgressTimeDelta = CFAbsoluteTimeGetCurrent() - _private->lastNotifiedProgressTime;
1124 _private->lastNotifiedProgressTime = now;
1126 LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
1127 double notificationProgressDelta = _private->progressValue - _private->lastNotifiedProgressValue;
1128 if ((notificationProgressDelta >= _private->progressNotificationInterval ||
1129 notifiedProgressTimeDelta >= _private->progressNotificationTimeInterval) &&
1130 _private->numProgressTrackedFrames > 0) {
1131 if (!_private->finalProgressChangedSent) {
1132 if (_private->progressValue == 1)
1133 _private->finalProgressChangedSent = YES;
1134 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1135 _private->lastNotifiedProgressValue = _private->progressValue;
1139 [self _didChangeValueForKey: @"estimatedProgress"];
1142 - (void)_completeProgressForConnectionDelegate:(id)connectionDelegate
1144 WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
1149 // Adjust the total expected bytes to account for any overage/underage.
1150 long long delta = item->bytesReceived - item->estimatedLength;
1151 _private->totalPageAndResourceBytesToLoad += delta;
1152 item->estimatedLength = item->bytesReceived;
1155 // Required to prevent automatic observer notifications.
1156 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1160 - (NSArray *)_declaredKeys {
1161 static NSArray *declaredKeys = nil;
1163 if (!declaredKeys) {
1164 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, nil];
1167 return declaredKeys;
1170 - (void)setObservationInfo:(void *)info
1172 _private->observationInfo = info;
1175 - (void *)observationInfo
1177 return _private->observationInfo;
1180 - (void)_willChangeBackForwardKeys
1182 [self _willChangeValueForKey: _WebCanGoBackKey];
1183 [self _willChangeValueForKey: _WebCanGoForwardKey];
1186 - (void)_didChangeBackForwardKeys
1188 [self _didChangeValueForKey: _WebCanGoBackKey];
1189 [self _didChangeValueForKey: _WebCanGoForwardKey];
1192 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1194 [self _willChangeBackForwardKeys];
1195 if (frame == [self mainFrame]){
1196 // Force an observer update by sending a will/did.
1197 [self _willChangeValueForKey: _WebIsLoadingKey];
1198 [self _didChangeValueForKey: _WebIsLoadingKey];
1200 [self _willChangeValueForKey: _WebMainFrameURLKey];
1202 [NSApp setWindowsNeedUpdate:YES];
1205 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1207 if (frame == [self mainFrame]){
1208 [self _didChangeValueForKey: _WebMainFrameURLKey];
1210 [NSApp setWindowsNeedUpdate:YES];
1213 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1215 [self _didChangeBackForwardKeys];
1216 if (frame == [self mainFrame]){
1217 // Force an observer update by sending a will/did.
1218 [self _willChangeValueForKey: _WebIsLoadingKey];
1219 [self _didChangeValueForKey: _WebIsLoadingKey];
1221 [NSApp setWindowsNeedUpdate:YES];
1224 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1226 [self _didChangeBackForwardKeys];
1227 if (frame == [self mainFrame]){
1228 // Force an observer update by sending a will/did.
1229 [self _willChangeValueForKey: _WebIsLoadingKey];
1230 [self _didChangeValueForKey: _WebIsLoadingKey];
1232 [NSApp setWindowsNeedUpdate:YES];
1235 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1237 [self _didChangeBackForwardKeys];
1238 if (frame == [self mainFrame]){
1239 // Force an observer update by sending a will/did.
1240 [self _willChangeValueForKey: _WebIsLoadingKey];
1241 [self _didChangeValueForKey: _WebIsLoadingKey];
1243 [self _didChangeValueForKey: _WebMainFrameURLKey];
1245 [NSApp setWindowsNeedUpdate:YES];
1248 - (void)_reloadForPluginChanges
1250 [[self mainFrame] _reloadForPluginChanges];
1253 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1255 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1256 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1257 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1259 return cachedResponse;
1262 - (void)_writeImageElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1264 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1265 [pasteboard _web_writeImage:[element objectForKey:WebElementImageKey]
1266 URL:linkURL ? linkURL : [element objectForKey:WebElementImageURLKey]
1267 title:[element objectForKey:WebElementImageAltStringKey]
1268 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1272 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1274 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1275 andTitle:[element objectForKey:WebElementLinkLabelKey]
1279 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1281 _private->initiatedDrag = initiatedDrag;
1284 #define DASHBOARD_CONTROL_LABEL @"control"
1286 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1288 // Add scroller regions for NSScroller and KWQScrollBar
1289 int i, count = [views count];
1291 for (i = 0; i < count; i++) {
1292 NSView *aView = [views objectAtIndex:i];
1294 if ([aView isKindOfClass:[NSScroller class]] ||
1295 [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1296 NSRect bounds = [aView bounds];
1297 NSRect adjustedBounds;
1298 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1299 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1301 // AppKit has horrible hack of placing absent scrollers at -100,-100
1302 if (adjustedBounds.origin.y == -100)
1304 adjustedBounds.size = bounds.size;
1305 NSRect clip = [aView visibleRect];
1306 NSRect adjustedClip;
1307 adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1308 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1309 adjustedClip.size = clip.size;
1310 WebDashboardRegion *aRegion =
1311 [[[WebDashboardRegion alloc] initWithRect:adjustedBounds
1312 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1313 NSMutableArray *scrollerRegions;
1314 scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1315 if (!scrollerRegions) {
1316 scrollerRegions = [NSMutableArray array];
1317 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1319 [scrollerRegions addObject:aRegion];
1321 [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1325 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1327 [self _addScrollerDashboardRegions:regions from:[self subviews]];
1330 - (NSDictionary *)_dashboardRegions
1332 // Only return regions from main frame.
1333 NSMutableDictionary *regions = [[[self mainFrame] _bridge] dashboardRegions];
1334 [self _addScrollerDashboardRegions:regions];
1338 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag;
1341 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1342 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1345 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1346 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1349 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1350 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1353 case WebDashboardBehaviorAllowWheelScrolling: {
1354 _private->dashboardBehaviorAllowWheelScrolling = flag;
1360 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1363 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1364 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1366 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1367 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1369 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1370 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1372 case WebDashboardBehaviorAllowWheelScrolling: {
1373 return _private->dashboardBehaviorAllowWheelScrolling;
1379 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
1381 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:self resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:dataSource];
1384 + (void)_setShouldUseFontSmoothing:(BOOL)f
1386 shouldUseFontSmoothing = f;
1389 + (BOOL)_shouldUseFontSmoothing
1391 return shouldUseFontSmoothing;
1397 @implementation _WebSafeForwarder
1399 - initWithTarget: t defaultTarget: dt templateClass: (Class)aClass
1402 target = t; // Non retained.
1404 templateClass = aClass;
1409 // Used to send messages to delegates that implement informal protocols.
1410 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
1412 return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
1416 NSMutableDictionary *countInvocations;
1419 - (void)forwardInvocation:(NSInvocation *)anInvocation
1422 if (!countInvocations){
1423 countInvocations = [[NSMutableDictionary alloc] init];
1425 NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
1427 count = [NSNumber numberWithInt: 1];
1429 count = [NSNumber numberWithInt: [count intValue] + 1];
1430 [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
1432 if ([target respondsToSelector: [anInvocation selector]])
1433 [anInvocation invokeWithTarget: target];
1434 else if ([defaultTarget respondsToSelector: [anInvocation selector]])
1435 [anInvocation invokeWithTarget: defaultTarget];
1436 // Do nothing quietly if method not implemented.
1439 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1441 return [templateClass instanceMethodSignatureForSelector: aSelector];
1446 @implementation WebView
1448 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1450 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1453 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1455 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1458 + (NSArray *)MIMETypesShownAsHTML
1460 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1461 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1463 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1465 while ((key = [enumerator nextObject])) {
1466 if ([viewTypes objectForKey:key] == [WebHTMLView class]) {
1467 [array addObject:key];
1474 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1476 NSEnumerator *enumerator;
1479 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1480 enumerator = [viewTypes keyEnumerator];
1481 while ((key = [enumerator nextObject])) {
1482 if ([viewTypes objectForKey:key] == [WebHTMLView class]) {
1483 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1487 int i, count = [MIMETypes count];
1488 for (i = 0; i < count; i++) {
1489 [WebView registerViewClass:[WebHTMLView class]
1490 representationClass:[WebHTMLRepresentation class]
1491 forMIMEType:[MIMETypes objectAtIndex:i]];
1495 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1497 return [pasteboard _web_bestURL];
1500 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1502 return [pasteboard stringForType:WebURLNamePboardType];
1505 - (void)_registerDraggedTypes
1507 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1508 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1509 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1510 [types addObjectsFromArray:URLTypes];
1511 [self registerForDraggedTypes:[types allObjects]];
1515 #if !BUILDING_ON_PANTHER
1516 static bool CGContextInitialized = false;
1519 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1521 #if !BUILDING_ON_PANTHER
1522 if (!CGContextInitialized) {
1523 CFStringRef key = CFSTR(kCGSDisableDeferredUpdates);
1524 CGSSetConnectionProperty([NSApp contextID], [NSApp contextID], (CGSValueObj)key, (CGSValueObj)kCFBooleanTrue);
1525 CGContextInitialized = true;
1529 _private->drawsBackground = YES;
1530 _private->smartInsertDeleteEnabled = YES;
1532 NSRect f = [self frame];
1533 WebFrameView *wv = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1534 [wv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
1535 [self addSubview: wv];
1538 _private->mainFrame = [[WebFrame alloc] initWithName: frameName webFrameView: wv webView: self];
1539 [self setGroupName:groupName];
1541 // If there's already a next key view (e.g., from a nib), wire it up to our
1542 // contained frame view. In any case, wire our next key view up to the our
1543 // contained frame view. This works together with our becomeFirstResponder
1544 // and setNextKeyView overrides.
1545 NSView *nextKeyView = [self nextKeyView];
1546 if (nextKeyView != nil && nextKeyView != wv) {
1547 [wv setNextKeyView:nextKeyView];
1549 [super setNextKeyView:wv];
1553 [self _registerDraggedTypes];
1555 // Update WebCore with preferences. These values will either come from an archived WebPreferences,
1556 // or from the standard preferences, depending on whether this method was called from initWithCoder:
1557 // or initWithFrame, respectively.
1558 [self _updateWebCoreSettingsFromPreferences: [self preferences]];
1560 // Register to receive notifications whenever preference values change.
1561 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1562 name:WebPreferencesChangedNotification object:[self preferences]];
1567 return [self initWithFrame: NSZeroRect frameName: nil groupName: nil];
1570 - initWithFrame: (NSRect)f
1572 [self initWithFrame: f frameName:nil groupName:nil];
1576 - initWithFrame: (NSRect)f frameName: (NSString *)frameName groupName: (NSString *)groupName;
1578 [super initWithFrame: f];
1579 _private = [[WebViewPrivate alloc] init];
1580 [self _commonInitializationWithFrameName:frameName groupName:groupName];
1581 [self setMaintainsBackForwardList: YES];
1585 - (id)initWithCoder:(NSCoder *)decoder
1587 WebView *result = nil;
1591 NSString *frameName;
1592 NSString *groupName;
1594 result = [super initWithCoder:decoder];
1595 result->_private = [[WebViewPrivate alloc] init];
1597 // We don't want any of the archived subviews. The subviews will always
1598 // be created in _commonInitializationFrameName:groupName:.
1599 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1601 if ([decoder allowsKeyedCoding]){
1602 frameName = [decoder decodeObjectForKey:@"FrameName"];
1603 groupName = [decoder decodeObjectForKey:@"GroupName"];
1605 [result setPreferences: [decoder decodeObjectForKey:@"Preferences"]];
1606 result->_private->useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1608 LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)_private->useBackForwardList);
1613 [decoder decodeValueOfObjCType:@encode(int) at:&version];
1614 frameName = [decoder decodeObject];
1615 groupName = [decoder decodeObject];
1616 [result setPreferences: [decoder decodeObject]];
1618 [decoder decodeValuesOfObjCTypes:"c",&result->_private->useBackForwardList];
1620 [result _commonInitializationWithFrameName:frameName groupName:groupName];
1632 - (void)encodeWithCoder:(NSCoder *)encoder
1634 [super encodeWithCoder:encoder];
1636 if ([encoder allowsKeyedCoding]){
1637 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1638 [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1639 [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1640 [encoder encodeBool:_private->useBackForwardList forKey:@"UseBackForwardList"];
1642 LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)_private->useBackForwardList);
1645 int version = WebViewVersion;
1646 [encoder encodeValueOfObjCType:@encode(int) at:&version];
1647 [encoder encodeObject:[[self mainFrame] name]];
1648 [encoder encodeObject:[self groupName]];
1649 [encoder encodeObject:[self preferences]];
1650 [encoder encodeValuesOfObjCTypes:"c",&_private->useBackForwardList];
1660 [[NSNotificationCenter defaultCenter] removeObserver:self];
1662 [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1665 // [super dealloc] can end up dispatching against _private (3466082)
1677 [[NSNotificationCenter defaultCenter] removeObserver:self];
1679 [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1684 - (void)setPreferences: (WebPreferences *)prefs
1686 if (_private->preferences != prefs){
1687 [[NSNotificationCenter defaultCenter] removeObserver: self name: WebPreferencesChangedNotification object: [self preferences]];
1688 [WebPreferences _removeReferenceForIdentifier: [_private->preferences identifier]];
1689 [_private->preferences release];
1690 _private->preferences = [prefs retain];
1691 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1692 name:WebPreferencesChangedNotification object:[self preferences]];
1694 [[NSNotificationCenter defaultCenter]
1695 postNotificationName:WebPreferencesChangedNotification object:prefs userInfo:nil];
1699 - (WebPreferences *)preferences
1701 return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
1704 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
1706 if (![anIdentifier isEqual: [[self preferences] identifier]]){
1707 [self setPreferences: [[WebPreferences alloc] initWithIdentifier:anIdentifier]];
1711 - (NSString *)preferencesIdentifier
1713 return [[self preferences] identifier];
1717 - (void)setUIDelegate:delegate
1719 _private->UIDelegate = delegate;
1720 [_private->UIDelegateForwarder release];
1721 _private->UIDelegateForwarder = nil;
1726 return _private->UIDelegate;
1729 - (void)setResourceLoadDelegate: delegate
1731 _private->resourceProgressDelegate = delegate;
1732 [_private->resourceProgressDelegateForwarder release];
1733 _private->resourceProgressDelegateForwarder = nil;
1734 [self _cacheResourceLoadDelegateImplementations];
1738 - resourceLoadDelegate
1740 return _private->resourceProgressDelegate;
1744 - (void)setDownloadDelegate: delegate
1746 _private->downloadDelegate = delegate;
1752 return _private->downloadDelegate;
1755 - (void)setPolicyDelegate:delegate
1757 _private->policyDelegate = delegate;
1758 [_private->policyDelegateForwarder release];
1759 _private->policyDelegateForwarder = nil;
1764 return _private->policyDelegate;
1767 - (void)setFrameLoadDelegate:delegate
1769 _private->frameLoadDelegate = delegate;
1770 [_private->frameLoadDelegateForwarder release];
1771 _private->frameLoadDelegateForwarder = nil;
1776 return _private->frameLoadDelegate;
1779 - (WebFrame *)mainFrame
1781 // This can be called in initialization, before _private has been set up (3465613)
1782 if (_private != nil) {
1783 return _private->mainFrame;
1788 - (WebBackForwardList *)backForwardList
1790 if (_private->useBackForwardList)
1791 return _private->backForwardList;
1795 - (void)setMaintainsBackForwardList: (BOOL)flag
1797 _private->useBackForwardList = flag;
1802 WebHistoryItem *item = [[self backForwardList] backItem];
1805 [self _goToItem: item withLoadType: WebFrameLoadTypeBack];
1813 WebHistoryItem *item = [[self backForwardList] forwardItem];
1816 [self _goToItem: item withLoadType: WebFrameLoadTypeForward];
1822 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
1824 [self _goToItem: item withLoadType: WebFrameLoadTypeIndexedBackForward];
1828 - (void)setTextSizeMultiplier:(float)m
1830 if (_private->textSizeMultiplier == m) {
1833 _private->textSizeMultiplier = m;
1834 [[self mainFrame] _textSizeMultiplierChanged];
1837 - (float)textSizeMultiplier
1839 return _private->textSizeMultiplier;
1842 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
1844 NSString *name = [applicationName copy];
1845 [_private->applicationNameForUserAgent release];
1846 _private->applicationNameForUserAgent = name;
1847 if (!_private->userAgentOverridden) {
1848 [_private->userAgent release];
1849 _private->userAgent = nil;
1853 - (NSString *)applicationNameForUserAgent
1855 return [[_private->applicationNameForUserAgent retain] autorelease];
1858 - (void)setCustomUserAgent:(NSString *)userAgentString
1860 NSString *override = [userAgentString copy];
1861 [_private->userAgent release];
1862 _private->userAgent = override;
1863 _private->userAgentOverridden = override != nil;
1866 - (NSString *)customUserAgent
1868 return _private->userAgentOverridden ? [[_private->userAgent retain] autorelease] : nil;
1871 - (void)setMediaStyle:(NSString *)mediaStyle
1873 if (_private->mediaStyle != mediaStyle) {
1874 [_private->mediaStyle release];
1875 _private->mediaStyle = [mediaStyle copy];
1879 - (NSString *)mediaStyle
1881 return _private->mediaStyle;
1884 - (BOOL)supportsTextEncoding
1886 id documentView = [[[self mainFrame] frameView] documentView];
1887 return [documentView conformsToProtocol:@protocol(WebDocumentText)]
1888 && [documentView supportsTextEncoding];
1891 - (void)setCustomTextEncodingName:(NSString *)encoding
1893 NSString *oldEncoding = [self customTextEncodingName];
1894 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) {
1897 [[self mainFrame] _reloadAllowingStaleDataWithOverrideEncoding:encoding];
1900 - (NSString *)_mainFrameOverrideEncoding
1902 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
1903 if (dataSource == nil) {
1904 dataSource = [[self mainFrame] dataSource];
1906 if (dataSource == nil) {
1909 return [dataSource _overrideEncoding];
1912 - (NSString *)customTextEncodingName
1914 return [self _mainFrameOverrideEncoding];
1917 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
1919 return [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
1922 - (WebScriptObject *)windowScriptObject
1924 return [[[self mainFrame] _bridge] windowScriptObject];
1928 // Get the appropriate user-agent string for a particular URL.
1929 // Since we no longer automatically spoof, this no longer requires looking at the URL.
1930 - (NSString *)userAgentForURL:(NSURL *)URL
1932 NSString *userAgent = _private->userAgent;
1934 return [[userAgent retain] autorelease];
1937 // FIXME: Some day we will start reporting the actual CPU here instead of hardcoding PPC.
1939 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
1940 id sourceVersion = [[NSBundle bundleForClass:[WebView class]]
1941 objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
1942 NSString *applicationName = _private->applicationNameForUserAgent;
1944 if ([applicationName length]) {
1945 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
1946 language, sourceVersion, applicationName];
1948 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko)",
1949 language, sourceVersion];
1952 _private->userAgent = [userAgent retain];
1956 - (void)setHostWindow:(NSWindow *)hostWindow
1958 if (hostWindow != _private->hostWindow) {
1959 [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
1960 [_private->hostWindow release];
1961 _private->hostWindow = [hostWindow retain];
1962 [[self mainFrame] _viewDidMoveToHostWindow];
1966 - (NSWindow *)hostWindow
1968 return _private->hostWindow;
1971 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
1973 return [[self _frameViewAtWindowPoint:point] documentView];
1976 - (NSView <WebDocumentDragging> *)_draggingDocumentViewAtWindowPoint:(NSPoint)point
1978 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:point];
1979 if ([documentView conformsToProtocol:@protocol(WebDocumentDragging)]) {
1980 return (NSView <WebDocumentDragging> *)documentView;
1985 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
1987 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
1990 NSView <WebDocumentView> *documentView = [frameView documentView];
1991 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
1992 NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
1993 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
1995 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
1998 - (NSDictionary *)elementAtPoint:(NSPoint)point
2000 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2003 - (void)_setDraggingDocumentView:(NSView <WebDocumentDragging> *)newDraggingView
2005 if (_private->draggingDocumentView != newDraggingView) {
2006 [_private->draggingDocumentView release];
2007 _private->draggingDocumentView = [newDraggingView retain];
2011 - (NSDragOperation)_loadingDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2013 if (_private->dragDestinationActionMask & WebDragDestinationActionLoad) {
2014 NSPoint windowPoint = [draggingInfo draggingLocation];
2015 NSView *view = [self hitTest:[[self superview] convertPoint:windowPoint toView:nil]];
2016 // Don't accept the drag over a plug-in since plug-ins may want to handle it.
2017 if (![view isKindOfClass:[WebBaseNetscapePluginView class]] && !_private->editable && !_private->initiatedDrag) {
2018 // If not editing or dragging, use _web_dragOperationForDraggingInfo to find a URL to load on the pasteboard.
2019 return [self _web_dragOperationForDraggingInfo:draggingInfo];
2022 return NSDragOperationNone;
2025 - (NSDragOperation)_delegateDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2027 NSPoint windowPoint = [draggingInfo draggingLocation];
2028 NSView <WebDocumentDragging> *newDraggingView = [self _draggingDocumentViewAtWindowPoint:windowPoint];
2029 if (_private->draggingDocumentView != newDraggingView) {
2030 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2031 [self _setDraggingDocumentView:newDraggingView];
2034 _private->dragDestinationActionMask = [[self _UIDelegateForwarder] webView:self dragDestinationActionMaskForDraggingInfo:draggingInfo];
2035 NSDragOperation operation = NSDragOperationNone;
2037 if (_private->dragDestinationActionMask == WebDragDestinationActionNone) {
2038 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2040 operation = [_private->draggingDocumentView draggingUpdatedWithDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask];
2041 if (operation == NSDragOperationNone) {
2042 return [self _loadingDragOperationForDraggingInfo:draggingInfo];
2049 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2050 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination.
2051 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination.
2052 // Forward these calls to the document subview to make its scroll view scroll.
2053 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2055 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2056 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2059 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2061 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2062 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2065 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2067 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2070 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2072 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2075 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2077 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2078 [self _setDraggingDocumentView:nil];
2081 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2086 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2088 ASSERT(_private->draggingDocumentView == [self _draggingDocumentViewAtWindowPoint:[draggingInfo draggingLocation]]);
2090 if ([_private->draggingDocumentView concludeDragForDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask]) {
2091 [self _setDraggingDocumentView:nil];
2095 [self _setDraggingDocumentView:nil];
2097 if ([self _loadingDragOperationForDraggingInfo:draggingInfo] != NSDragOperationNone) {
2098 NSURL *URL = [[self class] URLFromPasteboard:[draggingInfo draggingPasteboard]];
2100 [[self _UIDelegateForwarder] webView:self willPerformDragDestinationAction:WebDragDestinationActionLoad forDraggingInfo:draggingInfo];
2101 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
2102 [[self mainFrame] loadRequest:request];
2111 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2113 NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2114 if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2121 - (BOOL)acceptsFirstResponder
2123 return [[[self mainFrame] frameView] acceptsFirstResponder];
2126 - (BOOL)becomeFirstResponder
2128 // This works together with setNextKeyView to splice the WebView into
2129 // the key loop similar to the way NSScrollView does this. Note that
2130 // WebFrameView has very similar code.
2131 NSWindow *window = [self window];
2132 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2134 if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2135 NSView *previousValidKeyView = [self previousValidKeyView];
2136 if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2137 [window makeFirstResponder:previousValidKeyView];
2144 if ([mainFrameView acceptsFirstResponder]) {
2145 [window makeFirstResponder:mainFrameView];
2152 - (NSView *)_webcore_effectiveFirstResponder
2154 WebFrameView *frameView = [[self mainFrame] frameView];
2155 return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2158 - (void)setNextKeyView:(NSView *)aView
2160 // This works together with becomeFirstResponder to splice the WebView into
2161 // the key loop similar to the way NSScrollView does this. Note that
2162 // WebFrameView has very similar code.
2163 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2164 if (mainFrameView != nil) {
2165 [mainFrameView setNextKeyView:aView];
2167 [super setNextKeyView:aView];
2171 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2173 return forward ? [curr _nextFrameWithWrap:wrapFlag]
2174 : [curr _previousFrameWithWrap:wrapFlag];
2177 // Search from the end of the currently selected location, or from the beginning of the
2178 // document if nothing is selected. Deals with subframes.
2179 - (BOOL)_searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag findInSelection:(BOOL)findInSelection
2181 // Get the frame holding the selection, or start with the main frame
2182 WebFrame *startFrame = [self _frameForCurrentSelection];
2184 // Search the first frame, then all the other frames, in order
2185 NSView <WebDocumentSearching> *startSearchView = nil;
2186 BOOL startHasSelection = NO;
2187 WebFrame *frame = startFrame;
2189 id <WebDocumentView> view = [[frame frameView] documentView];
2190 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2191 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2193 // first time through
2194 if (frame == startFrame) {
2195 // Remember if start even has a selection, to know if we need to search more later
2196 if ([searchView isKindOfClass:[WebHTMLView class]]) {
2197 // optimization for the common case, to avoid making giant string for selection
2198 startHasSelection = [[startFrame _bridge] selectedDOMRange] != nil;
2199 } else if ([searchView conformsToProtocol:@protocol(WebDocumentText)]) {
2200 startHasSelection = [(id <WebDocumentText>)searchView selectedString] != nil;
2202 startSearchView = searchView;
2205 // Note at this point we are assuming the search will be done top-to-bottom,
2206 // not starting at any selection that exists. See 3228554.
2208 if ([searchView respondsToSelector:@selector(_searchFor:direction:caseSensitive:wrap:findInSelection:)]) {
2209 success = [searchView _searchFor:string direction:forward caseSensitive:caseFlag wrap:NO findInSelection:findInSelection];
2211 success = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:NO];
2214 [[self window] makeFirstResponder:searchView];
2218 frame = incrementFrame(frame, forward, wrapFlag);
2219 } while (frame != nil && frame != startFrame);
2221 // Search contents of startFrame, on the other side of the selection that we did earlier.
2222 // We cheat a bit and just research with wrap on
2223 if (wrapFlag && startHasSelection && startSearchView) {
2225 if ([startSearchView respondsToSelector:@selector(_searchFor:direction:caseSensitive:wrap:findInSelection:)]) {
2226 success = [startSearchView _searchFor:string direction:forward caseSensitive:caseFlag wrap:YES findInSelection:findInSelection];
2228 success = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES];
2231 [[self window] makeFirstResponder:startSearchView];
2238 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2240 return [self _searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag findInSelection:NO];
2244 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2246 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2247 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2250 - (void)setGroupName:(NSString *)groupName
2252 if (groupName != _private->setName){
2253 [_private->setName release];
2254 _private->setName = [groupName copy];
2255 [WebViewSets addWebView:self toSetNamed:_private->setName];
2259 - (NSString *)groupName
2261 return _private->setName;
2264 - (double)estimatedProgress
2266 return _private->progressValue;
2269 - (NSArray *)pasteboardTypesForSelection
2271 NSView <WebDocumentView> *documentView = [[[self _frameForCurrentSelection] frameView] documentView];
2272 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2273 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2275 return [NSArray array];
2278 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2280 WebBridge *bridge = [self _bridgeForCurrentSelection];
2281 if ([bridge selectionState] != WebSelectionStateRange) {
2282 NSView <WebDocumentView> *documentView = [[[bridge webFrame] frameView] documentView];
2283 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2284 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2289 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2291 if ([element objectForKey:WebElementImageURLKey] != nil) {
2292 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2293 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2294 return [NSPasteboard _web_writableTypesForURL];
2295 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2296 return [self pasteboardTypesForSelection];
2298 return [NSArray array];
2301 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2303 if ([element objectForKey:WebElementImageURLKey] != nil) {
2304 [self _writeImageElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2305 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2306 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2307 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2308 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2312 - (void)moveDragCaretToPoint:(NSPoint)point
2314 WebBridge *bridge = [self _bridgeAtPoint:point];
2315 if (bridge != _private->dragCaretBridge) {
2316 [_private->dragCaretBridge removeDragCaret];
2317 _private->dragCaretBridge = [bridge retain];
2319 [_private->dragCaretBridge moveDragCaretToPoint:[self convertPoint:point toView:[[[_private->dragCaretBridge webFrame] frameView] documentView]]];
2322 - (void)removeDragCaret
2324 [_private->dragCaretBridge removeDragCaret];
2325 [_private->dragCaretBridge release];
2326 _private->dragCaretBridge = nil;
2331 @implementation WebView (WebIBActions)
2333 - (IBAction)takeStringURLFrom: sender
2335 NSString *URLString = [sender stringValue];
2337 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2342 return [[self backForwardList] backItem] != nil;
2345 - (BOOL)canGoForward
2347 return [[self backForwardList] forwardItem] != nil;
2350 - (IBAction)goBack:(id)sender
2355 - (IBAction)goForward:(id)sender
2360 - (IBAction)stopLoading:(id)sender
2362 [[self mainFrame] stopLoading];
2365 - (IBAction)reload:(id)sender
2367 [[self mainFrame] reload];
2370 #define MinimumTextSizeMultiplier 0.5
2371 #define MaximumTextSizeMultiplier 3.0
2372 #define TextSizeMultiplierRatio 1.2
2374 - (BOOL)canMakeTextSmaller
2376 if ([[self mainFrame] dataSource] == nil) {
2379 // FIXME: This will prevent text sizing in subframes if the main frame doesn't support it
2380 if (![[[[self mainFrame] frameView] documentView] conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
2383 if ([self textSizeMultiplier]/TextSizeMultiplierRatio < MinimumTextSizeMultiplier) {
2389 - (BOOL)canMakeTextLarger
2391 if ([[self mainFrame] dataSource] == nil) {
2394 // FIXME: This will prevent text sizing in subframes if the main frame doesn't support it
2395 if (![[[[self mainFrame] frameView] documentView] conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
2398 if ([self textSizeMultiplier]*TextSizeMultiplierRatio > MaximumTextSizeMultiplier) {
2404 - (IBAction)makeTextSmaller:(id)sender
2406 if (![self canMakeTextSmaller]) {
2409 [self setTextSizeMultiplier:[self textSizeMultiplier]/TextSizeMultiplierRatio];
2412 - (IBAction)makeTextLarger:(id)sender
2414 if (![self canMakeTextLarger]) {
2417 [self setTextSizeMultiplier:[self textSizeMultiplier]*TextSizeMultiplierRatio];
2420 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2422 id responder = [self _responderForResponderOperations];
2423 if (responder != self && [responder respondsToSelector:[item action]]) {
2424 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) {
2425 return [responder validateUserInterfaceItem:item];
2432 #define VALIDATE(name) \
2433 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2435 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2437 SEL action = [item action];
2439 if (action == @selector(goBack:)) {
2440 return [self canGoBack];
2441 } else if (action == @selector(goForward:)) {
2442 return [self canGoForward];
2443 } else if (action == @selector(makeTextLarger:)) {
2444 return [self canMakeTextLarger];
2445 } else if (action == @selector(makeTextSmaller:)) {
2446 return [self canMakeTextSmaller];
2447 } else if (action == @selector(makeTextStandardSize:)) {
2448 return [self canMakeTextStandardSize];
2449 } else if (action == @selector(reload:)) {
2450 return [[self mainFrame] dataSource] != nil;
2451 } else if (action == @selector(stopLoading:)) {
2452 return [self _isLoading];
2453 } else if (action == @selector(toggleContinuousSpellChecking:)) {
2454 BOOL checkMark = NO;
2456 if ([self isEditable] && [self _continuousCheckingAllowed]) {
2457 checkMark = [self isContinuousSpellCheckingEnabled];
2460 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2461 NSMenuItem *menuItem = (NSMenuItem *)item;
2462 [menuItem setState:checkMark ? NSOnState : NSOffState];
2466 FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2473 @implementation WebView (WebPendingPublic)
2475 - (void)setMainFrameURL:(NSString *)URLString
2477 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2480 - (NSString *)mainFrameURL
2483 ds = [[self mainFrame] provisionalDataSource];
2485 ds = [[self mainFrame] dataSource];
2486 return [[[ds request] URL] _web_originalDataAsString];
2491 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2492 return [self _isLoading];
2495 - (NSString *)mainFrameTitle
2497 NSString *mainFrameTitle = [[[self mainFrame] dataSource] pageTitle];
2498 return (mainFrameTitle != nil) ? mainFrameTitle : @"";
2501 - (NSImage *)mainFrameIcon
2503 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2506 - (void)setDrawsBackground:(BOOL)drawsBackground
2508 if (_private->drawsBackground == drawsBackground)
2510 _private->drawsBackground = drawsBackground;
2511 [[self mainFrame] _updateDrawsBackground];
2514 - (BOOL)drawsBackground
2516 return _private->drawsBackground;
2519 - (void)toggleSmartInsertDelete:(id)sender
2521 if ([self isEditable]) {
2522 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2526 - (IBAction)toggleContinuousSpellChecking:(id)sender
2528 if ([self isEditable]) {
2529 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2533 - (BOOL)isContinuousGrammarCheckingEnabled
2535 return _private->continuousGrammarCheckingEnabled && [self _continuousCheckingAllowed];
2538 - (void)setContinuousGrammarCheckingEnabled:(BOOL)flag
2540 _private->continuousGrammarCheckingEnabled = flag;
2541 if ([self isContinuousGrammarCheckingEnabled]) {
2542 [self _preflightSpellChecker];
2544 // FIXME: Put code here to remove underlines for bad grammar.
2548 - (void)toggleContinuousGrammarChecking:(id)sender
2550 if ([self isEditable]) {
2551 [self setContinuousGrammarCheckingEnabled:![self isContinuousGrammarCheckingEnabled]];
2556 - (BOOL)canMakeTextStandardSize
2558 if ([[self mainFrame] dataSource] == nil) {
2561 // FIXME: This will prevent text sizing in subframes if the main frame doesn't support it
2562 if (![[[[self mainFrame] frameView] documentView] conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
2566 return [self textSizeMultiplier] != 1;
2569 - (IBAction)makeTextStandardSize:(id)sender
2571 if (![self canMakeTextStandardSize]) {
2574 [self setTextSizeMultiplier:1];
2577 - (BOOL)maintainsInactiveSelection
2579 return [self isEditable];
2584 @implementation WebView (WebViewPrintingPrivate)
2586 - (float)_headerHeight
2588 if ([[self UIDelegate] respondsToSelector:@selector(webViewHeaderHeight:)]) {
2589 return [[self UIDelegate] webViewHeaderHeight:self];
2592 #ifdef DEBUG_HEADER_AND_FOOTER
2599 - (float)_footerHeight
2601 if ([[self UIDelegate] respondsToSelector:@selector(webViewFooterHeight:)]) {
2602 return [[self UIDelegate] webViewFooterHeight:self];
2605 #ifdef DEBUG_HEADER_AND_FOOTER
2612 - (void)_drawHeaderInRect:(NSRect)rect
2614 #ifdef DEBUG_HEADER_AND_FOOTER
2615 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2616 [currentContext saveGraphicsState];
2617 [[NSColor yellowColor] set];
2619 [currentContext restoreGraphicsState];
2622 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawHeaderInRect:)]) {
2623 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2624 [currentContext saveGraphicsState];
2626 [[self UIDelegate] webView:self drawHeaderInRect:rect];
2627 [currentContext restoreGraphicsState];
2631 - (void)_drawFooterInRect:(NSRect)rect
2633 #ifdef DEBUG_HEADER_AND_FOOTER
2634 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2635 [currentContext saveGraphicsState];
2636 [[NSColor cyanColor] set];
2638 [currentContext restoreGraphicsState];
2641 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawFooterInRect:)]) {
2642 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2643 [currentContext saveGraphicsState];
2645 [[self UIDelegate] webView:self drawFooterInRect:rect];
2646 [currentContext restoreGraphicsState];
2650 - (void)_adjustPrintingMarginsForHeaderAndFooter
2652 NSPrintOperation *op = [NSPrintOperation currentOperation];
2653 NSPrintInfo *info = [op printInfo];
2654 float scale = [op _web_pageSetupScaleFactor];
2655 [info setTopMargin:[info topMargin] + [self _headerHeight]*scale];
2656 [info setBottomMargin:[info bottomMargin] + [self _footerHeight]*scale];
2659 - (void)_drawHeaderAndFooter
2661 // The header and footer rect height scales with the page, but the width is always
2662 // all the way across the printed page (inset by printing margins).
2663 NSPrintOperation *op = [NSPrintOperation currentOperation];
2664 float scale = [op _web_pageSetupScaleFactor];
2665 NSPrintInfo *printInfo = [op printInfo];
2666 NSSize paperSize = [printInfo paperSize];
2667 float headerFooterLeft = [printInfo leftMargin]/scale;
2668 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
2669 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] ,
2670 headerFooterWidth, [self _footerHeight]);
2671 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale,
2672 headerFooterWidth, [self _headerHeight]);
2674 [self _drawHeaderInRect:headerRect];
2675 [self _drawFooterInRect:footerRect];
2679 @implementation WebView (WebDebugBinding)
2681 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
2683 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
2684 [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
2687 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
2689 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
2690 [super removeObserver:anObserver forKeyPath:keyPath];
2695 //==========================================================================================
2698 @implementation WebView (WebViewCSS)
2700 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
2702 // FIXME: is this the best level for this conversion?
2703 if (pseudoElement == nil) {
2704 pseudoElement = @"";
2706 return [[element ownerDocument] getComputedStyle:element :pseudoElement];
2711 @implementation WebView (WebInternal)
2713 // Return the frame holding first responder
2714 - (WebFrame *)_frameForCurrentSelection
2716 // Find the frame holding the first responder, or holding the first form in the doc
2717 NSResponder *resp = [[self window] firstResponder];
2718 if (!resp || ![resp isKindOfClass:[NSView class]] || ![(NSView *)resp isDescendantOf:self]) {
2719 return [self mainFrame]; // first responder outside our view tree
2721 WebFrameView *frameView = (WebFrameView *)[(NSView *)resp _web_superviewOfClass:[WebFrameView class]];
2722 return [frameView webFrame];
2726 - (WebBridge *)_bridgeForCurrentSelection
2728 return [[self _frameForCurrentSelection] _bridge];
2733 WebFrame *mainFrame = [self mainFrame];
2734 return [[mainFrame dataSource] isLoading]
2735 || [[mainFrame provisionalDataSource] isLoading];
2738 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
2740 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
2741 return (WebFrameView *)[view _web_superviewOfClass:[WebFrameView class] stoppingAtClass:[self class]];
2744 - (WebBridge *)_bridgeAtPoint:(NSPoint)point
2746 return [[[self _frameViewAtWindowPoint:[self convertPoint:point toView:nil]] webFrame] _bridge];
2751 @implementation WebView (WebViewEditing)
2753 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
2755 WebBridge *bridge = [self _bridgeAtPoint:point];
2756 return [bridge editableDOMRangeForPoint:[self convertPoint:point toView:[[[bridge webFrame] frameView] documentView]]];
2759 - (BOOL)_shouldBeginEditingInDOMRange:(DOMRange *)range
2761 return [[self _editingDelegateForwarder] webView:self shouldBeginEditingInDOMRange:range];
2764 - (BOOL)_shouldEndEditingInDOMRange:(DOMRange *)range
2766 return [[self _editingDelegateForwarder] webView:self shouldEndEditingInDOMRange:range];
2771 id documentView = [[[self mainFrame] frameView] documentView];
2772 return [documentView respondsToSelector:@selector(_canPaste)] && [documentView _canPaste];
2775 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
2777 // Derive the bridge to use from the range passed in.
2778 // Using _bridgeForCurrentSelection could give us a different document than
2779 // the one the range uses.
2780 [[[range startContainer] _bridge] setSelectedDOMRange:range affinity:selectionAffinity closeTyping:YES];
2783 - (DOMRange *)selectedDOMRange
2785 return [[self _bridgeForCurrentSelection] selectedDOMRange];
2788 - (NSSelectionAffinity)selectionAffinity
2790 return [[self _bridgeForCurrentSelection] selectionAffinity];
2793 - (void)setEditable:(BOOL)flag
2795 if (_private->editable != flag) {
2796 _private->editable = flag;
2797 WebBridge *bridge = [[self mainFrame] _bridge];
2799 [bridge applyEditingStyleToBodyElement];
2800 // If the WebView is made editable and the selection is empty, set it to something.
2801 if ([self selectedDOMRange] == nil)
2802 [bridge setSelectionFromNone];
2805 [bridge removeEditingStyleFromBodyElement];
2812 return _private->editable;
2815 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
2817 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
2818 // change the API to allow this.
2819 [[self _bridgeForCurrentSelection] setTypingStyle:style withUndoAction:WebUndoActionUnspecified];
2822 - (DOMCSSStyleDeclaration *)typingStyle
2824 return [[self _bridgeForCurrentSelection] typingStyle];
2827 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
2829 _private->smartInsertDeleteEnabled = flag;
2832 - (BOOL)smartInsertDeleteEnabled
2834 return _private->smartInsertDeleteEnabled;
2837 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
2839 _private->continuousSpellCheckingEnabled = flag;
2840 if ([self isContinuousSpellCheckingEnabled]) {
2841 [self _preflightSpellChecker];
2843 [[self mainFrame] _unmarkAllMisspellings];
2847 - (BOOL)isContinuousSpellCheckingEnabled
2849 return _private->continuousSpellCheckingEnabled && [self _continuousCheckingAllowed];
2852 - (int)spellCheckerDocumentTag
2854 if (!_private->hasSpellCheckerDocumentTag) {
2855 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
2856 _private->hasSpellCheckerDocumentTag = YES;
2858 return _private->spellCheckerDocumentTag;
2861 - (NSUndoManager *)undoManager
2863 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
2867 return [super undoManager];
2870 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
2872 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
2873 if ([_private->editingDelegate respondsToSelector:selector])
2874 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
2877 - (void)setEditingDelegate:(id)delegate
2879 if (_private->editingDelegate == delegate)
2882 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
2884 // remove notifications from current delegate
2885 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
2886 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
2887 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
2888 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
2889 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
2891 _private->editingDelegate = delegate;
2892 [_private->editingDelegateForwarder release];
2893 _private->editingDelegateForwarder = nil;
2895 // add notifications for new delegate
2896 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
2897 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
2898 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
2899 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
2900 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
2903 - (id)editingDelegate
2905 return _private->editingDelegate;
2908 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
2910 // FIXME: Should this really be attached to the document with the current selection?
2911 DOMCSSStyleDeclaration *decl = [[[self _bridgeForCurrentSelection] DOMDocument] createCSSStyleDeclaration];
2912 [decl setCssText:text];
2918 @implementation WebView (WebViewUndoableEditing)
2920 - (void)replaceSelectionWithNode:(DOMNode *)node
2922 [[self _bridgeForCurrentSelection] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO];
2925 - (void)replaceSelectionWithText:(NSString *)text
2927 [[self _bridgeForCurrentSelection] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
2930 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
2932 [[self _bridgeForCurrentSelection] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
2935 - (void)replaceSelectionWithArchive:(WebArchive *)archive
2937 [[[[self _bridgeForCurrentSelection] webFrame] dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
2940 - (void)deleteSelection
2942 WebBridge *bridge = [self _bridgeForCurrentSelection];
2943 [bridge deleteSelectionWithSmartDelete:[(WebHTMLView *)[[[bridge webFrame] frameView] documentView] _canSmartCopyOrDelete]];
2946 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
2948 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
2949 // change the API to allow this.
2950 [[self _bridgeForCurrentSelection] applyStyle:style withUndoAction:WebUndoActionUnspecified];
2955 @implementation WebView (WebViewEditingActions)
2957 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
2959 static BOOL reentered = NO;
2961 [[self nextResponder] tryToPerform:selector with:parameter];
2965 // There are two possibilities here.
2967 // One is that WebView has been called in its role as part of the responder chain.
2968 // In that case, it's fine to call the first responder and end up calling down the
2969 // responder chain again. Later we will return here with reentered = YES and continue
2970 // past the WebView.
2972 // The other is that we are being called directly, in which case we want to pass the
2973 // selector down to the view inside us that can handle it, and continue down the
2974 // responder chain as usual.
2976 // Pass this selector down to the first responder.
2977 NSResponder *responder = [self _responderForResponderOperations];
2979 [responder tryToPerform:selector with:parameter];
2983 #define FORWARD(name) \
2984 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
2986 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
2988 - (void)insertText:(NSString *)text
2990 [self _performResponderOperation:_cmd with:text];
2995 @implementation WebView (WebViewEditingInMail)
2997 - (void)_insertNewlineInQuotedContent;
2999 [[self _bridgeForCurrentSelection] insertParagraphSeparatorInQuotedContent];
3002 - (BOOL)_selectWordBeforeMenuEvent
3004 return _private->selectWordBeforeMenuEvent;
3007 - (void)_setSelectWordBeforeMenuEvent:(BOOL)flag
3009 _private->selectWordBeforeMenuEvent = flag;
3014 @implementation WebView (WebFileInternal)
3016 - (void)_preflightSpellCheckerNow:(id)sender
3018 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
3021 - (void)_preflightSpellChecker
3023 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3024 if ([NSSpellChecker sharedSpellCheckerExists]) {
3025 [self _preflightSpellCheckerNow:self];
3027 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
3031 - (BOOL)_continuousCheckingAllowed
3033 static BOOL allowContinuousSpellChecking = YES;
3034 static BOOL readAllowContinuousSpellCheckingDefault = NO;
3035 if (!readAllowContinuousSpellCheckingDefault) {
3036 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
3037 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
3039 readAllowContinuousSpellCheckingDefault = YES;
3041 return allowContinuousSpellChecking;
3044 - (NSResponder *)_responderForResponderOperations
3046 NSResponder *responder = [[self window] firstResponder];
3047 if (![self _web_firstResponderIsSelfOrDescendantView]) {
3048 responder = [[[self mainFrame] frameView] documentView];
3050 responder = [[self mainFrame] frameView];