2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2006 David Smith (catfish.man@gmail.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #import "WebViewInternal.h"
32 #import <JavaScriptCore/Assertions.h>
33 #import "WebBackForwardList.h"
34 #import "WebBaseNetscapePluginView.h"
35 #import "WebDOMOperationsPrivate.h"
36 #import "WebDashboardRegion.h"
37 #import "WebDataProtocol.h"
38 #import "WebDataSourceInternal.h"
39 #import "WebDefaultEditingDelegate.h"
40 #import "WebDefaultFrameLoadDelegate.h"
41 #import "WebDefaultPolicyDelegate.h"
42 #import "WebDefaultResourceLoadDelegate.h"
43 #import "WebDefaultScriptDebugDelegate.h"
44 #import "WebDefaultUIDelegate.h"
45 #import "WebDocument.h"
46 #import "WebDocumentInternal.h"
47 #import "WebDownload.h"
48 #import "WebDownloadInternal.h"
49 #import "WebDynamicScrollBarsView.h"
50 #import "WebEditingDelegate.h"
51 #import "WebFormDelegatePrivate.h"
52 #import "WebFrameBridge.h"
53 #import "WebFrameInternal.h"
54 #import "WebFrameLoader.h"
55 #import "WebFrameViewInternal.h"
56 #import "WebHTMLRepresentation.h"
57 #import "WebHTMLViewInternal.h"
58 #import "WebHistoryItemPrivate.h"
59 #import "WebIconDatabase.h"
60 #import "WebInspector.h"
61 #import "WebKitErrors.h"
62 #import "WebKitLogging.h"
63 #import "WebKitNSStringExtras.h"
64 #import "WebKitStatisticsPrivate.h"
65 #import "WebLocalizableStrings.h"
66 #import "WebNSDataExtras.h"
67 #import "WebNSDataExtrasPrivate.h"
68 #import "WebNSDictionaryExtras.h"
69 #import "WebNSEventExtras.h"
70 #import "WebNSObjectExtras.h"
71 #import "WebNSPasteboardExtras.h"
72 #import "WebNSPrintOperationExtras.h"
73 #import "WebNSURLExtras.h"
74 #import "WebNSURLRequestExtras.h"
75 #import "WebNSUserDefaultsExtras.h"
76 #import "WebNSViewExtras.h"
77 #import "WebPageBridge.h"
78 #import "WebPDFView.h"
79 #import "WebPluginDatabase.h"
80 #import "WebPolicyDelegate.h"
81 #import "WebPreferencesPrivate.h"
82 #import "WebResourceLoadDelegate.h"
83 #import "WebScriptDebugDelegatePrivate.h"
84 #import "WebScriptDebugServerPrivate.h"
85 #import "WebUIDelegate.h"
86 #import "WebUIDelegatePrivate.h"
87 #import <CoreFoundation/CFSet.h>
88 #import <Foundation/NSURLConnection.h>
89 #import <WebCore/WebCoreEncodings.h>
90 #import <WebCore/WebCoreFrameBridge.h>
91 #import <WebCore/WebCoreSettings.h>
92 #import <WebCore/WebCoreView.h>
93 #import <WebKit/DOM.h>
94 #import <WebKit/DOMPrivate.h>
95 #import <WebKit/DOMExtensions.h>
96 #import <WebKitSystemInterface.h>
97 #import <objc/objc-runtime.h>
99 #import <WebCore/WebCoreTextRenderer.h>
101 #if defined(__ppc__) || defined(__ppc64__)
102 #define PROCESSOR "PPC"
103 #elif defined(__i386__) || defined(__x86_64__)
104 #define PROCESSOR "Intel"
106 #error Unknown architecture
109 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
111 macro(alignJustified) \
114 macro(capitalizeWord) \
115 macro(centerSelectionInVisibleArea) \
116 macro(changeAttributes) \
118 macro(changeDocumentBackgroundColor) \
120 macro(checkSpelling) \
126 macro(deleteBackward) \
127 macro(deleteBackwardByDecomposingPreviousCharacter) \
128 macro(deleteForward) \
129 macro(deleteToBeginningOfLine) \
130 macro(deleteToBeginningOfParagraph) \
131 macro(deleteToEndOfLine) \
132 macro(deleteToEndOfParagraph) \
133 macro(deleteWordBackward) \
134 macro(deleteWordForward) \
135 macro(ignoreSpelling) \
137 macro(insertBacktab) \
138 macro(insertNewline) \
139 macro(insertNewlineIgnoringFieldEditor) \
140 macro(insertParagraphSeparator) \
142 macro(insertTabIgnoringFieldEditor) \
143 macro(lowercaseWord) \
144 macro(moveBackward) \
145 macro(moveBackwardAndModifySelection) \
147 macro(moveDownAndModifySelection) \
149 macro(moveForwardAndModifySelection) \
151 macro(moveLeftAndModifySelection) \
153 macro(moveRightAndModifySelection) \
154 macro(moveToBeginningOfDocument) \
155 macro(moveToBeginningOfDocumentAndModifySelection) \
156 macro(moveToBeginningOfSentence) \
157 macro(moveToBeginningOfSentenceAndModifySelection) \
158 macro(moveToBeginningOfLine) \
159 macro(moveToBeginningOfLineAndModifySelection) \
160 macro(moveToBeginningOfParagraph) \
161 macro(moveToBeginningOfParagraphAndModifySelection) \
162 macro(moveToEndOfDocument) \
163 macro(moveToEndOfDocumentAndModifySelection) \
164 macro(moveToEndOfLine) \
165 macro(moveToEndOfLineAndModifySelection) \
166 macro(moveToEndOfParagraph) \
167 macro(moveToEndOfParagraphAndModifySelection) \
168 macro(moveToEndOfSentence) \
169 macro(moveToEndOfSentenceAndModifySelection) \
171 macro(moveUpAndModifySelection) \
172 macro(moveWordBackward) \
173 macro(moveWordBackwardAndModifySelection) \
174 macro(moveWordForward) \
175 macro(moveWordForwardAndModifySelection) \
176 macro(moveWordLeft) \
177 macro(moveWordLeftAndModifySelection) \
178 macro(moveWordRight) \
179 macro(moveWordRightAndModifySelection) \
183 macro(pasteAsPlainText) \
184 macro(pasteAsRichText) \
186 macro(performFindPanelAction) \
187 macro(scrollLineDown) \
188 macro(scrollLineUp) \
189 macro(scrollPageDown) \
190 macro(scrollPageUp) \
191 macro(scrollToBeginningOfDocument) \
192 macro(scrollToEndOfDocument) \
195 macro(selectSentence) \
197 macro(selectParagraph) \
198 macro(showGuessPanel) \
199 macro(startSpeaking) \
200 macro(stopSpeaking) \
205 macro(uppercaseWord) \
207 macro(yankAndSelect) \
209 @interface NSSpellChecker (AppKitSecretsIKnow)
210 - (void)_preflightChosenSpellServer;
213 @interface NSView (AppKitSecretsIKnow)
214 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
215 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
216 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
219 @interface WebViewPrivate : NSObject
222 WebPageBridge *_pageBridge;
225 id UIDelegateForwarder;
226 id resourceProgressDelegate;
227 id resourceProgressDelegateForwarder;
230 id policyDelegateForwarder;
231 id frameLoadDelegate;
232 id frameLoadDelegateForwarder;
233 id <WebFormDelegate> formDelegate;
235 id editingDelegateForwarder;
236 id scriptDebugDelegate;
237 id scriptDebugDelegateForwarder;
239 WebBackForwardList *backForwardList;
240 BOOL useBackForwardList;
242 float textSizeMultiplier;
244 NSString *applicationNameForUserAgent;
246 BOOL userAgentOverridden;
248 BOOL defersCallbacks;
250 WebPreferences *preferences;
251 WebCoreSettings *settings;
253 BOOL lastElementWasNonNil;
255 NSWindow *hostWindow;
257 int programmaticFocusCount;
259 WebResourceDelegateImplementationCache resourceLoadDelegateImplementations;
261 long long totalPageAndResourceBytesToLoad;
262 long long totalBytesReceived;
263 double progressValue;
264 double lastNotifiedProgressValue;
265 double lastNotifiedProgressTime;
266 double progressNotificationInterval;
267 double progressNotificationTimeInterval;
268 BOOL finalProgressChangedSent;
269 WebFrame *originatingProgressFrame;
271 int numProgressTrackedFrames;
272 NSMutableDictionary *progressItems;
274 void *observationInfo;
277 BOOL shouldCloseWithWindow;
278 BOOL mainFrameDocumentReady;
279 BOOL drawsBackground;
282 BOOL tabKeyCyclesThroughElements;
283 BOOL tabKeyCyclesThroughElementsChanged;
285 NSColor *backgroundColor;
287 NSString *mediaStyle;
289 NSView <WebDocumentDragging> *draggingDocumentView;
290 unsigned int dragDestinationActionMask;
292 BOOL hasSpellCheckerDocumentTag;
293 WebNSInteger spellCheckerDocumentTag;
295 BOOL continuousSpellCheckingEnabled;
296 BOOL smartInsertDeleteEnabled;
298 BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
299 BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
300 BOOL dashboardBehaviorAlwaysAcceptsFirstMouse;
301 BOOL dashboardBehaviorAllowWheelScrolling;
303 BOOL selectWordBeforeMenuEvent;
305 WebPluginDatabase *pluginDatabase;
309 @interface WebView (WebFileInternal)
310 - (WebFrame *)_selectedOrMainFrame;
311 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame;
313 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
314 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point;
315 - (WebFrame *)_focusedFrame;
316 + (void)_preflightSpellChecker;
317 - (BOOL)_continuousCheckingAllowed;
318 - (NSResponder *)_responderForResponderOperations;
319 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor;
320 - (void)_notifyTextSizeMultiplierChanged;
323 NSString *WebElementDOMNodeKey = @"WebElementDOMNode";
324 NSString *WebElementFrameKey = @"WebElementFrame";
325 NSString *WebElementImageKey = @"WebElementImage";
326 NSString *WebElementImageAltStringKey = @"WebElementImageAltString";
327 NSString *WebElementImageRectKey = @"WebElementImageRect";
328 NSString *WebElementImageURLKey = @"WebElementImageURL";
329 NSString *WebElementIsSelectedKey = @"WebElementIsSelected";
330 NSString *WebElementTitleKey = @"WebElementTitle";
331 NSString *WebElementLinkURLKey = @"WebElementLinkURL";
332 NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame";
333 NSString *WebElementLinkLabelKey = @"WebElementLinkLabel";
334 NSString *WebElementLinkTitleKey = @"WebElementLinkTitle";
336 NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification";
337 NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification";
338 NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification";
340 NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification";
341 NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification";
342 NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification";
343 NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification";
344 NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification";
346 enum { WebViewVersion = 2 };
348 #define timedLayoutSize 4096
350 static NSMutableSet *schemesWithRepresentationsSet;
352 NSString *_WebCanGoBackKey = @"canGoBack";
353 NSString *_WebCanGoForwardKey = @"canGoForward";
354 NSString *_WebEstimatedProgressKey = @"estimatedProgress";
355 NSString *_WebIsLoadingKey = @"isLoading";
356 NSString *_WebMainFrameIconKey = @"mainFrameIcon";
357 NSString *_WebMainFrameTitleKey = @"mainFrameTitle";
358 NSString *_WebMainFrameURLKey = @"mainFrameURL";
359 NSString *_WebMainFrameDocumentKey = @"mainFrameDocument";
361 @interface WebProgressItem : NSObject
364 long long bytesReceived;
365 long long estimatedLength;
369 @implementation WebProgressItem
372 @implementation WebViewPrivate
380 backForwardList = [[WebBackForwardList alloc] init];
381 textSizeMultiplier = 1;
382 progressNotificationInterval = 0.02;
383 progressNotificationTimeInterval = 0.1;
384 settings = [[WebCoreSettings alloc] init];
385 dashboardBehaviorAllowWheelScrolling = YES;
386 tabKeyCyclesThroughElements = YES;
387 shouldCloseWithWindow = objc_collecting_enabled();
394 ASSERT(!_pageBridge);
395 ASSERT(draggingDocumentView == nil);
397 [backForwardList release];
398 [applicationNameForUserAgent release];
400 [backgroundColor release];
402 [preferences release];
404 [hostWindow release];
406 [policyDelegateForwarder release];
407 [resourceProgressDelegateForwarder release];
408 [UIDelegateForwarder release];
409 [frameLoadDelegateForwarder release];
410 [editingDelegateForwarder release];
411 [scriptDebugDelegateForwarder release];
413 [progressItems release];
415 [mediaStyle release];
422 @implementation WebView (AllWebViews)
424 static CFSetCallBacks NonRetainingSetCallbacks = {
433 static CFMutableSetRef allWebViewsSet;
435 + (void)_makeAllWebViewsPerformSelector:(SEL)selector
440 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
443 - (void)_removeFromAllWebViewsSet
446 CFSetRemoveValue(allWebViewsSet, self);
449 - (void)_addToAllWebViewsSet
452 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
454 CFSetSetValue(allWebViewsSet, self);
459 @implementation WebView (WebPrivate)
461 #ifdef DEBUG_WIDGET_DRAWING
462 static bool debugWidget = true;
463 - (void)drawRect:(NSRect)rect
465 [[NSColor blueColor] set];
468 NSRect htmlViewRect = [[[[self mainFrame] frameView] documentView] frame];
471 while (debugWidget) {
476 NSLog (@"%s: rect: (%0.f,%0.f) %0.f %0.f, htmlViewRect: (%0.f,%0.f) %0.f %0.f\n",
477 __PRETTY_FUNCTION__, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
478 htmlViewRect.origin.x, htmlViewRect.origin.y, htmlViewRect.size.width, htmlViewRect.size.height
481 [super drawRect:rect];
485 + (BOOL)_developerExtrasEnabled
488 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
489 BOOL enableDebugger = [defaults boolForKey:@"WebKitDeveloperExtras"];
491 enableDebugger = [defaults boolForKey:@"IncludeDebugMenu"];
492 return enableDebugger;
494 return YES; // always enable in debug builds
498 + (BOOL)_scriptDebuggerEnabled
501 return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitScriptDebuggerEnabled"];
503 return YES; // always enable in debug builds
507 + (NSArray *)_supportedMIMETypes
509 // Load the plug-in DB allowing plug-ins to install types.
510 [WebPluginDatabase installedPlugins];
511 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
514 + (NSArray *)_supportedFileExtensions
516 NSMutableSet *extensions = [[NSMutableSet alloc] init];
517 NSArray *MIMETypes = [self _supportedMIMETypes];
518 NSEnumerator *enumerator = [MIMETypes objectEnumerator];
520 while ((MIMEType = [enumerator nextObject]) != nil) {
521 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
522 if (extensionsForType) {
523 [extensions addObjectsFromArray:extensionsForType];
526 NSArray *uniqueExtensions = [extensions allObjects];
527 [extensions release];
528 return uniqueExtensions;
531 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
533 MIMEType = [MIMEType lowercaseString];
534 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
535 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
537 if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) {
538 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
539 // Load the plug-in DB allowing plug-ins to install types.
540 [WebPluginDatabase installedPlugins];
542 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
543 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
544 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
547 if (viewClass && repClass) {
548 // Special-case WebHTMLView for text types that shouldn't be shown.
549 if (viewClass == [WebHTMLView class] &&
550 repClass == [WebHTMLRepresentation class] &&
551 [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) {
564 - (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
566 if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType])
569 if (_private->pluginDatabase) {
570 WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
573 *vClass = [WebHTMLView class];
575 *rClass = [WebHTMLRepresentation class];
583 + (void)_setAlwaysUseATSU:(BOOL)f
585 WebCoreSetAlwaysUseATSU(f);
588 + (BOOL)canShowFile:(NSString *)path
590 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
593 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
595 return WKGetPreferredExtensionForMIMEType(type);
600 if (!_private || _private->closed)
602 _private->closed = YES;
604 [self _removeFromAllWebViewsSet];
606 [self setGroupName:nil];
607 [self setHostWindow:nil];
608 [self setDownloadDelegate:nil];
609 [self setEditingDelegate:nil];
610 [self setFrameLoadDelegate:nil];
611 [self setPolicyDelegate:nil];
612 [self setResourceLoadDelegate:nil];
613 [self setScriptDebugDelegate:nil];
614 [self setUIDelegate:nil];
616 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
617 [self removeDragCaret];
619 [[self mainFrame] _detachFromParent];
620 [_private->_pageBridge close];
621 [_private->_pageBridge release];
622 _private->_pageBridge = nil;
624 // Clear the page cache so we call destroy on all the plug-ins in the page cache to break any retain cycles.
625 // See comment in [WebHistoryItem _releaseAllPendingPageCaches] for more information.
626 if (_private->backForwardList) {
627 [_private->backForwardList _close];
628 [_private->backForwardList release];
629 _private->backForwardList = nil;
632 if (_private->hasSpellCheckerDocumentTag) {
633 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
634 _private->hasSpellCheckerDocumentTag = NO;
637 if (_private->pluginDatabase) {
638 [_private->pluginDatabase close];
639 [_private->pluginDatabase release];
640 _private->pluginDatabase = nil;
643 [[NSNotificationCenter defaultCenter] removeObserver:self];
645 [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
648 + (NSString *)_MIMETypeForFile:(NSString *)path
650 NSString *extension = [path pathExtension];
651 NSString *MIMEType = nil;
653 // Get the MIME type from the extension.
654 if ([extension length] != 0) {
655 MIMEType = WKGetMIMETypeForExtension(extension);
658 // If we can't get a known MIME type from the extension, sniff.
659 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
660 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
661 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
663 if ([data length] != 0) {
664 MIMEType = [data _webkit_guessedMIMEType];
666 if ([MIMEType length] == 0) {
667 MIMEType = @"application/octet-stream";
674 - (void)_downloadURL:(NSURL *)URL
678 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
679 [WebDownload _downloadWithRequest:request
680 delegate:_private->downloadDelegate
685 - (BOOL)defersCallbacks
687 return _private->defersCallbacks;
690 - (void)setDefersCallbacks:(BOOL)defers
692 if (defers == _private->defersCallbacks) {
696 _private->defersCallbacks = defers;
697 [[self mainFrame] _defersCallbacksChanged];
700 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
702 id wd = [self UIDelegate];
703 WebView *newWindowWebView = nil;
704 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
705 newWindowWebView = [wd webView:self createWebViewWithRequest:request];
707 newWindowWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:self createWebViewWithRequest: request];
710 [[newWindowWebView _UIDelegateForwarder] webViewShow: newWindowWebView];
712 return newWindowWebView;
715 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
717 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate]
718 webView:self contextMenuItemsForElement:element defaultMenuItems:items];
719 NSArray *menuItems = defaultMenuItems;
723 DOMNode* node = [element objectForKey:WebElementDOMNodeKey];
724 BOOL elementIsTextField = [node isKindOfClass:[DOMHTMLInputElement class]] && [(DOMHTMLInputElement*)node _isTextField];
725 BOOL elementIsTextArea = [node isKindOfClass:[DOMHTMLTextAreaElement class]];
726 if (_private->UIDelegate && !elementIsTextField && !elementIsTextArea) {
727 id cd = _private->UIDelegate;
729 if ([cd respondsToSelector:@selector(webView:contextMenuItemsForElement:defaultMenuItems:)]) {
730 menuItems = [cd webView:self contextMenuItemsForElement:element defaultMenuItems:defaultMenuItems];
732 // Versions of Mail compiled with older WebKits will end up without three context menu items, though
733 // with the separators between them. Here we check for that problem and reinsert the three missing
734 // items. This shouldn't affect any clients other than Mail since the tags for the three items
735 // were not public API. We can remove this code when we no longer support previously-built versions
736 // of Mail on Tiger. See 4498606 for more details.
737 if ([menuItems count] && ([[defaultMenuItems objectAtIndex:0] tag] == WebMenuItemTagSearchInSpotlight) && ([[menuItems objectAtIndex:0] isSeparatorItem])) {
738 ASSERT([[menuItems objectAtIndex:1] isSeparatorItem]);
739 ASSERT([[defaultMenuItems objectAtIndex:1] tag] == WebMenuItemTagSearchWeb);
740 ASSERT([[defaultMenuItems objectAtIndex:2] isSeparatorItem]);
741 ASSERT([[defaultMenuItems objectAtIndex:3] tag] == WebMenuItemTagLookUpInDictionary);
742 ASSERT([[defaultMenuItems objectAtIndex:4] isSeparatorItem]);
743 NSMutableArray *mutableMenuItems = [NSMutableArray arrayWithArray:menuItems];
744 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:0] atIndex:0];
745 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:1] atIndex:1];
746 [mutableMenuItems insertObject:[defaultMenuItems objectAtIndex:3] atIndex:3];
747 menuItems = mutableMenuItems;
752 if (menuItems && [menuItems count] > 0) {
753 menu = [[[NSMenu alloc] init] autorelease];
755 for (i=0; i<[menuItems count]; i++) {
756 [menu addItem:[menuItems objectAtIndex:i]];
760 // optionally add the Inspect Element menu item it if preference is set or in debug builds
761 // and only showing the menu item if we are working with a WebHTMLView
762 WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
763 if ([WebView _developerExtrasEnabled] && [[[webFrame frameView] documentView] isKindOfClass:[WebHTMLView class]]) {
765 menu = [[[NSMenu alloc] init] autorelease];
766 else if ([menu numberOfItems])
767 [menu addItem:[NSMenuItem separatorItem]];
768 NSMenuItem *menuItem = [[[NSMenuItem alloc] init] autorelease];
769 [menuItem setAction:@selector(_inspectElement:)];
770 [menuItem setTitle:UI_STRING("Inspect Element", "Inspect Element context menu item")];
771 [menuItem setRepresentedObject:element];
772 [menu addItem:menuItem];
778 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(WebNSUInteger)modifierFlags
780 // When the mouse isn't over this view at all, we'll get called with a dictionary of nil over
781 // and over again. So it's a good idea to catch that here and not send multiple calls to the delegate
784 if (dictionary && _private->lastElementWasNonNil) {
785 [[self _UIDelegateForwarder] webView:self mouseDidMoveOverElement:dictionary modifierFlags:modifierFlags];
787 _private->lastElementWasNonNil = dictionary != nil;
790 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
792 // We never go back/forward on a per-frame basis, so the target must be the main frame
793 //ASSERT([item target] == nil || [self _findFrameNamed:[item target]] == [self mainFrame]);
795 // abort any current load if we're going back/forward
796 [[self mainFrame] stopLoading];
797 [[self mainFrame] _goToItem:item withLoadType:type];
800 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
802 // It turns out the right combination of behavior is done with the back/forward load
803 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items
804 // in the back forward list, and go to the current one.
806 WebBackForwardList *bfList = [self backForwardList];
807 ASSERT(![bfList currentItem]); // destination list should be empty
809 WebBackForwardList *otherBFList = [otherView backForwardList];
810 if (![otherBFList currentItem]) {
811 return; // empty back forward list, bail
814 WebHistoryItem *newItemToGoTo = nil;
815 int lastItemIndex = [otherBFList forwardListCount];
817 for (i = -[otherBFList backListCount]; i <= lastItemIndex; i++) {
819 // If this item is showing , save away its current scroll and form state,
820 // since that might have changed since loading and it is normally not saved
821 // until we leave that page.
822 [[otherView mainFrame] _saveDocumentAndScrollState];
824 WebHistoryItem *newItem = [[otherBFList itemAtIndex:i] copy];
825 [bfList addItem:newItem];
827 newItemToGoTo = newItem;
831 [self _goToItem:newItemToGoTo withLoadType:WebFrameLoadTypeIndexedBackForward];
834 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
836 _private->formDelegate = delegate;
839 - (id<WebFormDelegate>)_formDelegate
841 if (!_private->formDelegate) {
842 // create lazily, to give the client a chance to set one before we bother to alloc the shared one
843 _private->formDelegate = [WebFormDelegate _sharedWebFormDelegate];
845 return _private->formDelegate;
848 - (WebCoreSettings *)_settings
850 return _private->settings;
853 - (void)_updateWebCoreSettingsFromPreferences:(WebPreferences *)preferences
855 [_private->settings setCursiveFontFamily:[preferences cursiveFontFamily]];
856 [_private->settings setDefaultFixedFontSize:[preferences defaultFixedFontSize]];
857 [_private->settings setDefaultFontSize:[preferences defaultFontSize]];
858 [_private->settings setDefaultTextEncoding:[preferences defaultTextEncodingName]];
859 [_private->settings setFantasyFontFamily:[preferences fantasyFontFamily]];
860 [_private->settings setFixedFontFamily:[preferences fixedFontFamily]];
861 [_private->settings setJavaEnabled:[preferences isJavaEnabled]];
862 [_private->settings setJavaScriptEnabled:[preferences isJavaScriptEnabled]];
863 [_private->settings setJavaScriptCanOpenWindowsAutomatically:[preferences javaScriptCanOpenWindowsAutomatically]];
864 [_private->settings setMinimumFontSize:[preferences minimumFontSize]];
865 [_private->settings setMinimumLogicalFontSize:[preferences minimumLogicalFontSize]];
866 [_private->settings setPluginsEnabled:[preferences arePlugInsEnabled]];
867 [_private->settings setPrivateBrowsingEnabled:[preferences privateBrowsingEnabled]];
868 [_private->settings setSansSerifFontFamily:[preferences sansSerifFontFamily]];
869 [_private->settings setSerifFontFamily:[preferences serifFontFamily]];
870 [_private->settings setStandardFontFamily:[preferences standardFontFamily]];
871 [_private->settings setWillLoadImagesAutomatically:[preferences loadsImagesAutomatically]];
873 if ([preferences userStyleSheetEnabled]) {
874 [_private->settings setUserStyleSheetLocation:[[preferences userStyleSheetLocation] _web_originalDataAsString]];
876 [_private->settings setUserStyleSheetLocation:@""];
878 [_private->settings setShouldPrintBackgrounds:[preferences shouldPrintBackgrounds]];
879 [_private->settings setTextAreasAreResizable:[preferences textAreasAreResizable]];
880 [_private->settings setEditableLinkBehavior:[preferences editableLinkBehavior]];
883 - (void)_preferencesChangedNotification: (NSNotification *)notification
885 WebPreferences *preferences = (WebPreferences *)[notification object];
887 ASSERT(preferences == [self preferences]);
888 if (!_private->userAgentOverridden) {
889 [_private->userAgent release];
890 _private->userAgent = nil;
892 [self _updateWebCoreSettingsFromPreferences: preferences];
895 - _frameLoadDelegateForwarder
897 if (!_private->frameLoadDelegateForwarder)
898 _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self frameLoadDelegate] defaultTarget: [WebDefaultFrameLoadDelegate sharedFrameLoadDelegate] templateClass: [WebDefaultFrameLoadDelegate class]];
899 return _private->frameLoadDelegateForwarder;
902 - _resourceLoadDelegateForwarder
904 if (!_private->resourceProgressDelegateForwarder)
905 _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
906 return _private->resourceProgressDelegateForwarder;
909 - (void)_cacheResourceLoadDelegateImplementations
911 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
912 id delegate = [self resourceLoadDelegate];
914 cache->delegateImplementsDidCancelAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:)];
915 cache->delegateImplementsDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)];
916 cache->delegateImplementsDidFinishLoadingFromDataSource = [delegate respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)];
917 cache->delegateImplementsDidReceiveContentLength = [delegate respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)];
918 cache->delegateImplementsDidReceiveResponse = [delegate respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)];
919 cache->delegateImplementsWillSendRequest = [delegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)];
920 cache->delegateImplementsIdentifierForRequest = [delegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)];
923 - (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
925 return _private->resourceLoadDelegateImplementations;
928 - _policyDelegateForwarder
930 if (!_private->policyDelegateForwarder)
931 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
932 return _private->policyDelegateForwarder;
935 - _UIDelegateForwarder
937 if (!_private->UIDelegateForwarder)
938 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self UIDelegate] defaultTarget: [WebDefaultUIDelegate sharedUIDelegate] templateClass: [WebDefaultUIDelegate class]];
939 return _private->UIDelegateForwarder;
942 - _editingDelegateForwarder
944 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
945 // Not sure if that is a bug or not.
948 if (!_private->editingDelegateForwarder)
949 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self editingDelegate] defaultTarget: [WebDefaultEditingDelegate sharedEditingDelegate] templateClass: [WebDefaultEditingDelegate class]];
950 return _private->editingDelegateForwarder;
953 - _scriptDebugDelegateForwarder
955 if (!_private->scriptDebugDelegateForwarder)
956 _private->scriptDebugDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self scriptDebugDelegate] defaultTarget: [WebDefaultScriptDebugDelegate sharedScriptDebugDelegate] templateClass: [WebDefaultScriptDebugDelegate class]];
957 return _private->scriptDebugDelegateForwarder;
962 [[self _UIDelegateForwarder] webViewClose:self];
965 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
967 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
968 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
971 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
973 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
974 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
976 // This is used to make _representationExistsForURLScheme faster.
977 // Without this set, we'd have to create the MIME type each time.
978 if (schemesWithRepresentationsSet == nil) {
979 schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
981 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
984 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
986 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
989 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
991 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
994 + (BOOL)_canHandleRequest:(NSURLRequest *)request
996 if ([NSURLConnection canHandleRequest:request]) {
1000 // We're always willing to load alternate content for unreachable URLs
1001 if ([request _webDataRequestUnreachableURL]) {
1005 return [self _representationExistsForURLScheme:[[request URL] scheme]];
1008 + (NSString *)_decodeData:(NSData *)data
1010 return [WebCoreEncodings decodeData:data];
1013 - (void)_pushPerformingProgrammaticFocus
1015 _private->programmaticFocusCount++;
1018 - (void)_popPerformingProgrammaticFocus
1020 _private->programmaticFocusCount--;
1023 - (BOOL)_isPerformingProgrammaticFocus
1025 return _private->programmaticFocusCount != 0;
1028 #define UnknownTotalBytes -1
1029 #define WebProgressItemDefaultEstimatedLength 1024*16
1031 - (void)_didChangeValueForKey: (NSString *)key
1033 LOG (Bindings, "calling didChangeValueForKey: %@", key);
1034 [self didChangeValueForKey: key];
1037 - (void)_willChangeValueForKey: (NSString *)key
1039 LOG (Bindings, "calling willChangeValueForKey: %@", key);
1040 [self willChangeValueForKey: key];
1043 // Always start progress at INITIAL_PROGRESS_VALUE. This helps provide feedback as
1044 // soon as a load starts.
1045 #define INITIAL_PROGRESS_VALUE 0.1
1046 // Similarly, always leave space at the end. This helps show the user that we're not done
1047 // until we're done.
1048 #define FINAL_PROGRESS_VALUE 1.0 - INITIAL_PROGRESS_VALUE
1050 - (void)_resetProgress
1052 [_private->progressItems release];
1053 _private->progressItems = nil;
1054 _private->totalPageAndResourceBytesToLoad = 0;
1055 _private->totalBytesReceived = 0;
1056 _private->progressValue = 0;
1057 _private->lastNotifiedProgressValue = 0;
1058 _private->lastNotifiedProgressTime = 0;
1059 _private->finalProgressChangedSent = NO;
1060 _private->numProgressTrackedFrames = 0;
1061 [_private->originatingProgressFrame release];
1062 _private->originatingProgressFrame = nil;
1064 - (void)_progressStarted:(WebFrame *)frame
1066 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1067 [self _willChangeValueForKey: @"estimatedProgress"];
1068 if (_private->numProgressTrackedFrames == 0 || _private->originatingProgressFrame == frame){
1069 [self _resetProgress];
1070 _private->progressValue = INITIAL_PROGRESS_VALUE;
1071 _private->originatingProgressFrame = [frame retain];
1072 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:self];
1074 _private->numProgressTrackedFrames++;
1075 [self _didChangeValueForKey: @"estimatedProgress"];
1078 - (void)_finalProgressComplete
1082 // Before resetting progress value be sure to send client a least one notification
1083 // with final progress value.
1084 if (!_private->finalProgressChangedSent) {
1085 _private->progressValue = 1;
1086 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1089 [self _resetProgress];
1091 [self setMainFrameDocumentReady:YES]; // make sure this is turned on at this point
1092 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:self];
1095 - (void)_progressCompleted:(WebFrame *)frame
1097 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1099 if (_private->numProgressTrackedFrames <= 0)
1102 [self _willChangeValueForKey: @"estimatedProgress"];
1104 _private->numProgressTrackedFrames--;
1105 if (_private->numProgressTrackedFrames == 0 ||
1106 (frame == _private->originatingProgressFrame && _private->numProgressTrackedFrames != 0)){
1107 [self _finalProgressComplete];
1109 [self _didChangeValueForKey: @"estimatedProgress"];
1112 - (void)_incrementProgressForIdentifier:(id)identifier response:(NSURLResponse *)response;
1117 LOG (Progress, "_private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", _private->numProgressTrackedFrames, _private->originatingProgressFrame);
1119 if (_private->numProgressTrackedFrames <= 0)
1122 WebProgressItem *item = [[WebProgressItem alloc] init];
1127 long long length = [response expectedContentLength];
1129 length = WebProgressItemDefaultEstimatedLength;
1131 item->estimatedLength = length;
1132 _private->totalPageAndResourceBytesToLoad += length;
1134 if (!_private->progressItems)
1135 _private->progressItems = [[NSMutableDictionary alloc] init];
1137 [_private->progressItems _webkit_setObject:item forUncopiedKey:identifier];
1141 - (void)_incrementProgressForIdentifier:(id)identifier data:(NSData *)data
1146 WebProgressItem *item = [_private->progressItems objectForKey:identifier];
1151 [self _willChangeValueForKey: @"estimatedProgress"];
1153 unsigned bytesReceived = [data length];
1154 double increment, percentOfRemainingBytes;
1155 long long remainingBytes, estimatedBytesForPendingRequests;
1157 item->bytesReceived += bytesReceived;
1158 if (item->bytesReceived > item->estimatedLength){
1159 _private->totalPageAndResourceBytesToLoad += ((item->bytesReceived*2) - item->estimatedLength);
1160 item->estimatedLength = item->bytesReceived*2;
1163 int numPendingOrLoadingRequests = [_private->originatingProgressFrame _numPendingOrLoadingRequests:YES];
1164 estimatedBytesForPendingRequests = WebProgressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
1165 remainingBytes = ((_private->totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - _private->totalBytesReceived);
1166 percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
1168 // Treat the first layout as the half-way point.
1169 double maxProgressValue = [_private->originatingProgressFrame _firstLayoutDone]
1170 ? FINAL_PROGRESS_VALUE
1172 increment = (maxProgressValue - _private->progressValue) * percentOfRemainingBytes;
1173 _private->progressValue += increment;
1174 if (_private->progressValue > maxProgressValue)
1175 _private->progressValue = maxProgressValue;
1176 ASSERT(_private->progressValue >= INITIAL_PROGRESS_VALUE);
1178 _private->totalBytesReceived += bytesReceived;
1180 double now = CFAbsoluteTimeGetCurrent();
1181 double notifiedProgressTimeDelta = now - _private->lastNotifiedProgressTime;
1183 LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
1184 double notificationProgressDelta = _private->progressValue - _private->lastNotifiedProgressValue;
1185 if ((notificationProgressDelta >= _private->progressNotificationInterval ||
1186 notifiedProgressTimeDelta >= _private->progressNotificationTimeInterval) &&
1187 _private->numProgressTrackedFrames > 0) {
1188 if (!_private->finalProgressChangedSent) {
1189 if (_private->progressValue == 1)
1190 _private->finalProgressChangedSent = YES;
1191 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1192 _private->lastNotifiedProgressValue = _private->progressValue;
1193 _private->lastNotifiedProgressTime = now;
1197 [self _didChangeValueForKey: @"estimatedProgress"];
1200 - (void)_completeProgressForIdentifier:(id)identifier
1202 WebProgressItem *item = [_private->progressItems objectForKey:identifier];
1207 // Adjust the total expected bytes to account for any overage/underage.
1208 long long delta = item->bytesReceived - item->estimatedLength;
1209 _private->totalPageAndResourceBytesToLoad += delta;
1210 item->estimatedLength = item->bytesReceived;
1213 // Required to prevent automatic observer notifications.
1214 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1218 - (NSArray *)_declaredKeys {
1219 static NSArray *declaredKeys = nil;
1221 if (!declaredKeys) {
1222 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1225 return declaredKeys;
1228 - (void)setObservationInfo:(void *)info
1230 _private->observationInfo = info;
1233 - (void *)observationInfo
1235 return _private->observationInfo;
1238 - (void)_willChangeBackForwardKeys
1240 [self _willChangeValueForKey: _WebCanGoBackKey];
1241 [self _willChangeValueForKey: _WebCanGoForwardKey];
1244 - (void)_didChangeBackForwardKeys
1246 [self _didChangeValueForKey: _WebCanGoBackKey];
1247 [self _didChangeValueForKey: _WebCanGoForwardKey];
1250 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1252 [self _willChangeBackForwardKeys];
1253 if (frame == [self mainFrame]){
1254 // Force an observer update by sending a will/did.
1255 [self _willChangeValueForKey: _WebIsLoadingKey];
1256 [self _didChangeValueForKey: _WebIsLoadingKey];
1258 [self _willChangeValueForKey: _WebMainFrameURLKey];
1260 [NSApp setWindowsNeedUpdate:YES];
1263 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1265 if (frame == [self mainFrame]){
1266 [self _didChangeValueForKey: _WebMainFrameURLKey];
1268 [NSApp setWindowsNeedUpdate:YES];
1271 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1273 [self _didChangeBackForwardKeys];
1274 if (frame == [self mainFrame]){
1275 // Force an observer update by sending a will/did.
1276 [self _willChangeValueForKey: _WebIsLoadingKey];
1277 [self _didChangeValueForKey: _WebIsLoadingKey];
1279 [NSApp setWindowsNeedUpdate:YES];
1282 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1284 [self _didChangeBackForwardKeys];
1285 if (frame == [self mainFrame]){
1286 // Force an observer update by sending a will/did.
1287 [self _willChangeValueForKey: _WebIsLoadingKey];
1288 [self _didChangeValueForKey: _WebIsLoadingKey];
1290 [NSApp setWindowsNeedUpdate:YES];
1293 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1295 [self _didChangeBackForwardKeys];
1296 if (frame == [self mainFrame]){
1297 // Force an observer update by sending a will/did.
1298 [self _willChangeValueForKey: _WebIsLoadingKey];
1299 [self _didChangeValueForKey: _WebIsLoadingKey];
1301 [self _didChangeValueForKey: _WebMainFrameURLKey];
1303 [NSApp setWindowsNeedUpdate:YES];
1306 - (void)_reloadForPluginChanges
1308 [[self mainFrame] _reloadForPluginChanges];
1311 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1313 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1314 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1315 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1317 return cachedResponse;
1320 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1322 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1323 DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1324 [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
1326 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1327 title:[element objectForKey:WebElementImageAltStringKey]
1328 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1332 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1334 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1335 andTitle:[element objectForKey:WebElementLinkLabelKey]
1339 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1341 _private->initiatedDrag = initiatedDrag;
1344 #define DASHBOARD_CONTROL_LABEL @"control"
1346 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1348 // Add scroller regions for NSScroller and KWQScrollBar
1349 int i, count = [views count];
1351 for (i = 0; i < count; i++) {
1352 NSView *aView = [views objectAtIndex:i];
1354 if ([aView isKindOfClass:[NSScroller class]] ||
1355 [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1356 NSRect bounds = [aView bounds];
1357 NSRect adjustedBounds;
1358 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1359 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1361 // AppKit has horrible hack of placing absent scrollers at -100,-100
1362 if (adjustedBounds.origin.y == -100)
1364 adjustedBounds.size = bounds.size;
1365 NSRect clip = [aView visibleRect];
1366 NSRect adjustedClip;
1367 adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1368 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1369 adjustedClip.size = clip.size;
1370 WebDashboardRegion *aRegion =
1371 [[[WebDashboardRegion alloc] initWithRect:adjustedBounds
1372 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1373 NSMutableArray *scrollerRegions;
1374 scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1375 if (!scrollerRegions) {
1376 scrollerRegions = [NSMutableArray array];
1377 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1379 [scrollerRegions addObject:aRegion];
1381 [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1385 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1387 [self _addScrollerDashboardRegions:regions from:[self subviews]];
1390 - (NSDictionary *)_dashboardRegions
1392 // Only return regions from main frame.
1393 NSMutableDictionary *regions = [[[self mainFrame] _bridge] dashboardRegions];
1394 [self _addScrollerDashboardRegions:regions];
1398 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag;
1401 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1402 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1405 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1406 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1409 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1410 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1413 case WebDashboardBehaviorAllowWheelScrolling: {
1414 _private->dashboardBehaviorAllowWheelScrolling = flag;
1420 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1423 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1424 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1426 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1427 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1429 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1430 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1432 case WebDashboardBehaviorAllowWheelScrolling: {
1433 return _private->dashboardBehaviorAllowWheelScrolling;
1439 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
1441 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:self resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:dataSource];
1444 + (void)_setShouldUseFontSmoothing:(BOOL)f
1446 WebCoreSetShouldUseFontSmoothing(f);
1449 + (BOOL)_shouldUseFontSmoothing
1451 return WebCoreShouldUseFontSmoothing();
1454 + (NSString *)_minimumRequiredSafariBuildNumber
1459 - (void)setAlwaysShowVerticalScroller:(BOOL)flag
1461 WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1463 [scrollview setVerticalScrollingMode:WebCoreScrollBarAlwaysOn];
1464 [scrollview setVerticalScrollingModeLocked:YES];
1466 [scrollview setVerticalScrollingModeLocked:NO];
1467 [scrollview setVerticalScrollingMode:WebCoreScrollBarAuto];
1471 - (BOOL)alwaysShowVerticalScroller
1473 WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1474 return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == WebCoreScrollBarAlwaysOn;
1477 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag
1479 WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1481 [scrollview setHorizontalScrollingMode:WebCoreScrollBarAlwaysOn];
1482 [scrollview setHorizontalScrollingModeLocked:YES];
1484 [scrollview setHorizontalScrollingModeLocked:NO];
1485 [scrollview setHorizontalScrollingMode:WebCoreScrollBarAuto];
1489 - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits
1491 [[[self mainFrame] _bridge] setProhibitsScrolling:YES];
1494 - (BOOL)alwaysShowHorizontalScroller
1496 WebDynamicScrollBarsView *scrollview = (WebDynamicScrollBarsView *)[[[self mainFrame] frameView] _scrollView];
1497 return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == WebCoreScrollBarAlwaysOn;
1500 - (void)_setInViewSourceMode:(BOOL)flag
1502 [[[self mainFrame] _bridge] setInViewSourceMode:flag];
1505 - (BOOL)_inViewSourceMode
1507 return [[[self mainFrame] _bridge] inViewSourceMode];
1510 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
1512 if (!_private->pluginDatabase)
1513 _private->pluginDatabase = [[WebPluginDatabase alloc] init];
1515 [_private->pluginDatabase setPlugInPaths:newPaths];
1516 [_private->pluginDatabase refresh];
1519 - (void)_attachScriptDebuggerToAllFrames
1521 WebFrame *frame = [self mainFrame];
1523 [frame _attachScriptDebugger];
1524 frame = [frame _nextFrameWithWrap:NO];
1528 - (void)_detachScriptDebuggerFromAllFrames
1530 WebFrame *frame = [self mainFrame];
1532 [frame _detachScriptDebugger];
1533 frame = [frame _nextFrameWithWrap:NO];
1537 - (void)setBackgroundColor:(NSColor *)backgroundColor
1539 if ([_private->backgroundColor isEqual:backgroundColor])
1542 id old = _private->backgroundColor;
1543 _private->backgroundColor = [backgroundColor retain];
1546 [[self mainFrame] _updateBackground];
1549 - (NSColor *)backgroundColor
1551 return _private->backgroundColor;
1557 @implementation _WebSafeForwarder
1559 - initWithTarget: t defaultTarget: dt templateClass: (Class)aClass
1561 self = [super init];
1565 target = t; // Non retained.
1567 templateClass = aClass;
1572 // Used to send messages to delegates that implement informal protocols.
1573 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
1575 return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
1579 NSMutableDictionary *countInvocations;
1582 - (void)forwardInvocation:(NSInvocation *)anInvocation
1585 if (!countInvocations){
1586 countInvocations = [[NSMutableDictionary alloc] init];
1588 NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
1590 count = [NSNumber numberWithInt: 1];
1592 count = [NSNumber numberWithInt: [count intValue] + 1];
1593 [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
1595 if ([target respondsToSelector: [anInvocation selector]])
1596 [anInvocation invokeWithTarget: target];
1597 else if ([defaultTarget respondsToSelector: [anInvocation selector]])
1598 [anInvocation invokeWithTarget: defaultTarget];
1599 // Do nothing quietly if method not implemented.
1602 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1604 return [templateClass instanceMethodSignatureForSelector: aSelector];
1609 @implementation WebView
1611 #if REMOVE_SAFARI_DOM_TREE_DEBUG_ITEM
1612 // this prevents open source users from crashing when using the Show DOM Tree menu item in Safari
1613 // FIXME: remove this when it is no longer needed to prevent Safari from crashing
1616 static BOOL tooLate = NO;
1618 if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeDebugMenu"])
1619 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_finishedLaunching) name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1624 +(void)_finishedLaunching
1626 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_removeDOMTreeMenuItem:) name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1627 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1630 +(void)_removeDOMTreeMenuItem:(NSNotification *)notification
1632 NSMenu *debugMenu = [[[[NSApp mainMenu] itemArray] lastObject] submenu];
1633 NSMenuItem *domTree = [debugMenu itemWithTitle:@"Show DOM Tree"];
1635 [debugMenu removeItem:domTree];
1636 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1640 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1642 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1645 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
1647 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForMIMEType:MIMEType];
1649 return pluginPackage;
1651 if (_private->pluginDatabase)
1652 return [_private->pluginDatabase pluginForMIMEType:MIMEType];
1657 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
1659 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase installedPlugins] pluginForExtension:extension];
1661 return pluginPackage;
1663 if (_private->pluginDatabase)
1664 return [_private->pluginDatabase pluginForExtension:extension];
1669 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
1671 if ([[WebPluginDatabase installedPlugins] isMIMETypeRegistered:MIMEType])
1674 if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
1680 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1682 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1685 + (NSArray *)MIMETypesShownAsHTML
1687 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1688 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1690 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1692 while ((key = [enumerator nextObject])) {
1693 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1694 [array addObject:key];
1700 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1702 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1703 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1705 while ((key = [enumerator nextObject])) {
1706 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1707 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1710 int i, count = [MIMETypes count];
1711 for (i = 0; i < count; i++) {
1712 [WebView registerViewClass:[WebHTMLView class]
1713 representationClass:[WebHTMLRepresentation class]
1714 forMIMEType:[MIMETypes objectAtIndex:i]];
1718 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1720 return [pasteboard _web_bestURL];
1723 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1725 return [pasteboard stringForType:WebURLNamePboardType];
1728 - (void)_registerDraggedTypes
1730 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1731 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1732 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1733 [types addObjectsFromArray:URLTypes];
1734 [self registerForDraggedTypes:[types allObjects]];
1738 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1740 _private->mainFrameDocumentReady = NO;
1741 _private->drawsBackground = YES;
1742 _private->smartInsertDeleteEnabled = YES;
1743 _private->backgroundColor = [[NSColor whiteColor] retain];
1745 NSRect f = [self frame];
1746 WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1747 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1748 [self addSubview:frameView];
1749 [frameView release];
1751 WebKitInitializeLoggingChannelsIfNecessary();
1752 _private->_pageBridge = [[WebPageBridge alloc] initWithMainFrameName:frameName webView:self frameView:frameView];
1754 [self _addToAllWebViewsSet];
1755 [self setGroupName:groupName];
1757 // If there's already a next key view (e.g., from a nib), wire it up to our
1758 // contained frame view. In any case, wire our next key view up to the our
1759 // contained frame view. This works together with our becomeFirstResponder
1760 // and setNextKeyView overrides.
1761 NSView *nextKeyView = [self nextKeyView];
1762 if (nextKeyView != nil && nextKeyView != frameView) {
1763 [frameView setNextKeyView:nextKeyView];
1765 [super setNextKeyView:frameView];
1769 [self _registerDraggedTypes];
1771 // initialize WebScriptDebugServer here so listeners can register before any pages are loaded.
1772 if ([WebView _scriptDebuggerEnabled])
1773 [WebScriptDebugServer sharedScriptDebugServer];
1775 // Update WebCore with preferences. These values will either come from an archived WebPreferences,
1776 // or from the standard preferences, depending on whether this method was called from initWithCoder:
1777 // or initWithFrame, respectively.
1778 [self _updateWebCoreSettingsFromPreferences: [self preferences]];
1780 // Register to receive notifications whenever preference values change.
1781 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1782 name:WebPreferencesChangedNotification object:[self preferences]];
1785 - (id)initWithFrame:(NSRect)f
1787 return [self initWithFrame:f frameName:nil groupName:nil];
1790 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName;
1792 self = [super initWithFrame:f];
1796 #if ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1797 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1798 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the
1799 // need for Safari to unset it to prevent it from being passed to applications it launches.
1800 // Unsetting it when a WebView is first created is as good a place as any.
1801 // See <http://bugzilla.opendarwin.org/show_bug.cgi?id=4286> for more details.
1802 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1803 unsetenv("DYLD_FRAMEWORK_PATH");
1804 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1808 _private = [[WebViewPrivate alloc] init];
1809 [self _commonInitializationWithFrameName:frameName groupName:groupName];
1810 [self setMaintainsBackForwardList: YES];
1814 - (id)initWithCoder:(NSCoder *)decoder
1816 WebView *result = nil;
1820 NSString *frameName;
1821 NSString *groupName;
1822 WebPreferences *preferences;
1823 BOOL useBackForwardList;
1825 result = [super initWithCoder:decoder];
1826 result->_private = [[WebViewPrivate alloc] init];
1828 // We don't want any of the archived subviews. The subviews will always
1829 // be created in _commonInitializationFrameName:groupName:.
1830 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1832 if ([decoder allowsKeyedCoding]) {
1833 frameName = [decoder decodeObjectForKey:@"FrameName"];
1834 groupName = [decoder decodeObjectForKey:@"GroupName"];
1835 preferences = [decoder decodeObjectForKey:@"Preferences"];
1836 useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1839 [decoder decodeValueOfObjCType:@encode(int) at:&version];
1840 frameName = [decoder decodeObject];
1841 groupName = [decoder decodeObject];
1842 preferences = [decoder decodeObject];
1844 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
1847 if (![frameName isKindOfClass:[NSString class]])
1849 if (![groupName isKindOfClass:[NSString class]])
1851 if (![preferences isKindOfClass:[WebPreferences class]])
1854 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
1857 [result setPreferences:preferences];
1858 result->_private->useBackForwardList = useBackForwardList;
1859 [result _commonInitializationWithFrameName:frameName groupName:groupName];
1871 - (void)encodeWithCoder:(NSCoder *)encoder
1873 [super encodeWithCoder:encoder];
1875 if ([encoder allowsKeyedCoding]) {
1876 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1877 [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1878 [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1879 [encoder encodeBool:_private->useBackForwardList forKey:@"UseBackForwardList"];
1881 int version = WebViewVersion;
1882 [encoder encodeValueOfObjCType:@encode(int) at:&version];
1883 [encoder encodeObject:[[self mainFrame] name]];
1884 [encoder encodeObject:[self groupName]];
1885 [encoder encodeObject:[self preferences]];
1886 [encoder encodeValuesOfObjCTypes:"c", &_private->useBackForwardList];
1889 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)_private->useBackForwardList);
1894 // call close to ensure we tear-down completly
1895 // this maintains our old behavior for existing applications
1901 // [super dealloc] can end up dispatching against _private (3466082)
1909 ASSERT(_private->closed);
1921 - (void)setShouldCloseWithWindow:(BOOL)close
1923 _private->shouldCloseWithWindow = close;
1926 - (BOOL)shouldCloseWithWindow
1928 return _private->shouldCloseWithWindow;
1931 - (void)viewWillMoveToWindow:(NSWindow *)window
1933 // Don't do anything if we aren't initialized. This happens
1934 // when decoding a WebView.
1937 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
1939 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window];
1943 - (void)_windowWillClose:(NSNotification *)notification
1945 if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow])))
1949 - (void)setPreferences:(WebPreferences *)prefs
1951 if (_private->preferences != prefs) {
1952 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
1953 [WebPreferences _removeReferenceForIdentifier:[_private->preferences identifier]];
1954 [_private->preferences release];
1955 _private->preferences = [prefs retain];
1956 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1957 name:WebPreferencesChangedNotification object:[self preferences]];
1958 [[NSNotificationCenter defaultCenter]
1959 postNotificationName:WebPreferencesChangedNotification object:prefs userInfo:nil];
1963 - (WebPreferences *)preferences
1965 return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
1968 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
1970 if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) {
1971 WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
1972 [self setPreferences:prefs];
1977 - (NSString *)preferencesIdentifier
1979 return [[self preferences] identifier];
1983 - (void)setUIDelegate:delegate
1985 _private->UIDelegate = delegate;
1986 [_private->UIDelegateForwarder release];
1987 _private->UIDelegateForwarder = nil;
1992 return _private->UIDelegate;
1995 - (void)setResourceLoadDelegate: delegate
1997 _private->resourceProgressDelegate = delegate;
1998 [_private->resourceProgressDelegateForwarder release];
1999 _private->resourceProgressDelegateForwarder = nil;
2000 [self _cacheResourceLoadDelegateImplementations];
2004 - resourceLoadDelegate
2006 return _private->resourceProgressDelegate;
2010 - (void)setDownloadDelegate: delegate
2012 _private->downloadDelegate = delegate;
2018 return _private->downloadDelegate;
2021 - (void)setPolicyDelegate:delegate
2023 _private->policyDelegate = delegate;
2024 [_private->policyDelegateForwarder release];
2025 _private->policyDelegateForwarder = nil;
2030 return _private->policyDelegate;
2033 - (void)setFrameLoadDelegate:delegate
2035 _private->frameLoadDelegate = delegate;
2036 [_private->frameLoadDelegateForwarder release];
2037 _private->frameLoadDelegateForwarder = nil;
2042 return _private->frameLoadDelegate;
2045 - (WebFrame *)mainFrame
2047 // This can be called in initialization, before _private has been set up (3465613)
2050 return [(WebFrameBridge *)[_private->_pageBridge mainFrame] webFrame];
2053 - (WebFrame *)selectedFrame
2055 // If the first responder is a view in our tree, we get the frame containing the first responder.
2056 // This is faster than searching the frame hierarchy, and will give us a result even in the case
2057 // where the focused frame doesn't actually contain a selection.
2058 WebFrame *focusedFrame = [self _focusedFrame];
2060 return focusedFrame;
2062 // If the first responder is outside of our view tree, we search for a frame containing a selection.
2063 // There should be at most only one of these.
2064 return [[self mainFrame] _findFrameWithSelection];
2069 - (WebBackForwardList *)backForwardList
2071 if (_private->useBackForwardList)
2072 return _private->backForwardList;
2076 - (void)setMaintainsBackForwardList: (BOOL)flag
2078 _private->useBackForwardList = flag;
2083 WebHistoryItem *item = [[self backForwardList] backItem];
2086 [self _goToItem: item withLoadType: WebFrameLoadTypeBack];
2094 WebHistoryItem *item = [[self backForwardList] forwardItem];
2097 [self _goToItem: item withLoadType: WebFrameLoadTypeForward];
2103 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
2105 [self _goToItem: item withLoadType: WebFrameLoadTypeIndexedBackForward];
2109 - (void)setTextSizeMultiplier:(float)m
2111 // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>)
2112 if (_private->textSizeMultiplier == m)
2115 _private->textSizeMultiplier = m;
2116 [self _notifyTextSizeMultiplierChanged];
2119 - (float)textSizeMultiplier
2121 return _private->textSizeMultiplier;
2124 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
2126 NSString *name = [applicationName copy];
2127 [_private->applicationNameForUserAgent release];
2128 _private->applicationNameForUserAgent = name;
2129 if (!_private->userAgentOverridden) {
2130 [_private->userAgent release];
2131 _private->userAgent = nil;
2135 - (NSString *)applicationNameForUserAgent
2137 return [[_private->applicationNameForUserAgent retain] autorelease];
2140 - (void)setCustomUserAgent:(NSString *)userAgentString
2142 NSString *override = [userAgentString copy];
2143 [_private->userAgent release];
2144 _private->userAgent = override;
2145 _private->userAgentOverridden = override != nil;
2148 - (NSString *)customUserAgent
2150 return _private->userAgentOverridden ? [[_private->userAgent retain] autorelease] : nil;
2153 - (void)setMediaStyle:(NSString *)mediaStyle
2155 if (_private->mediaStyle != mediaStyle) {
2156 [_private->mediaStyle release];
2157 _private->mediaStyle = [mediaStyle copy];
2161 - (NSString *)mediaStyle
2163 return _private->mediaStyle;
2166 - (BOOL)supportsTextEncoding
2168 id documentView = [[[self mainFrame] frameView] documentView];
2169 return [documentView conformsToProtocol:@protocol(WebDocumentText)]
2170 && [documentView supportsTextEncoding];
2173 - (void)setCustomTextEncodingName:(NSString *)encoding
2175 NSString *oldEncoding = [self customTextEncodingName];
2176 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) {
2179 [[[self mainFrame] _frameLoader] _reloadAllowingStaleDataWithOverrideEncoding:encoding];
2182 - (NSString *)_mainFrameOverrideEncoding
2184 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
2185 if (dataSource == nil) {
2186 dataSource = [[self mainFrame] dataSource];
2188 if (dataSource == nil) {
2191 return [dataSource _overrideEncoding];
2194 - (NSString *)customTextEncodingName
2196 return [self _mainFrameOverrideEncoding];
2199 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
2201 return [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
2204 - (WebScriptObject *)windowScriptObject
2206 return [[[self mainFrame] _bridge] windowScriptObject];
2209 // Get the appropriate user-agent string for a particular URL.
2210 // Since we no longer automatically spoof, this no longer requires looking at the URL.
2211 - (NSString *)userAgentForURL:(NSURL *)URL
2213 NSString *userAgent = _private->userAgent;
2215 return [[userAgent retain] autorelease];
2218 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
2219 id sourceVersion = [[NSBundle bundleForClass:[WebView class]]
2220 objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
2221 NSString *applicationName = _private->applicationNameForUserAgent;
2223 if ([applicationName length]) {
2224 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
2225 language, sourceVersion, applicationName];
2227 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko)",
2228 language, sourceVersion];
2231 _private->userAgent = [userAgent retain];
2235 - (void)setHostWindow:(NSWindow *)hostWindow
2237 if (!_private->closed && hostWindow != _private->hostWindow) {
2238 [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
2239 if (_private->hostWindow)
2240 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow];
2242 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow];
2243 [_private->hostWindow release];
2244 _private->hostWindow = [hostWindow retain];
2245 [[self mainFrame] _viewDidMoveToHostWindow];
2249 - (NSWindow *)hostWindow
2251 return _private->hostWindow;
2254 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
2256 return [[self _frameViewAtWindowPoint:point] documentView];
2259 - (NSView <WebDocumentDragging> *)_draggingDocumentViewAtWindowPoint:(NSPoint)point
2261 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:point];
2262 if ([documentView conformsToProtocol:@protocol(WebDocumentDragging)]) {
2263 return (NSView <WebDocumentDragging> *)documentView;
2268 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
2270 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
2273 NSView <WebDocumentView> *documentView = [frameView documentView];
2274 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
2275 NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
2276 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
2278 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
2281 - (NSDictionary *)elementAtPoint:(NSPoint)point
2283 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2286 - (void)_setDraggingDocumentView:(NSView <WebDocumentDragging> *)newDraggingView
2288 if (_private->draggingDocumentView != newDraggingView) {
2289 [_private->draggingDocumentView release];
2290 _private->draggingDocumentView = [newDraggingView retain];
2294 - (NSDragOperation)_loadingDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2296 if (_private->dragDestinationActionMask & WebDragDestinationActionLoad) {
2297 NSPoint windowPoint = [draggingInfo draggingLocation];
2298 NSView *view = [self hitTest:[[self superview] convertPoint:windowPoint toView:nil]];
2299 // Don't accept the drag over a plug-in since plug-ins may want to handle it.
2300 if (![view isKindOfClass:[WebBaseNetscapePluginView class]] && !_private->editable && !_private->initiatedDrag) {
2301 // If not editing or dragging, use _web_dragOperationForDraggingInfo to find a URL to load on the pasteboard.
2302 return [self _web_dragOperationForDraggingInfo:draggingInfo];
2305 return NSDragOperationNone;
2308 - (NSDragOperation)_delegateDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2310 NSPoint windowPoint = [draggingInfo draggingLocation];
2311 NSView <WebDocumentDragging> *newDraggingView = [self _draggingDocumentViewAtWindowPoint:windowPoint];
2312 if (_private->draggingDocumentView != newDraggingView) {
2313 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2314 [self _setDraggingDocumentView:newDraggingView];
2317 _private->dragDestinationActionMask = [[self _UIDelegateForwarder] webView:self dragDestinationActionMaskForDraggingInfo:draggingInfo];
2318 NSDragOperation operation = NSDragOperationNone;
2320 if (_private->dragDestinationActionMask == WebDragDestinationActionNone) {
2321 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2323 operation = [_private->draggingDocumentView draggingUpdatedWithDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask];
2324 if (operation == NSDragOperationNone) {
2325 return [self _loadingDragOperationForDraggingInfo:draggingInfo];
2332 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2333 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination.
2334 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination.
2335 // Forward these calls to the document subview to make its scroll view scroll.
2336 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2338 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2339 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2342 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2344 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2345 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2348 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2350 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2353 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2355 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2358 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2360 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2361 [self _setDraggingDocumentView:nil];
2364 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2369 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2371 ASSERT(_private->draggingDocumentView == [self _draggingDocumentViewAtWindowPoint:[draggingInfo draggingLocation]]);
2373 if ([_private->draggingDocumentView concludeDragForDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask]) {
2374 [self _setDraggingDocumentView:nil];
2378 [self _setDraggingDocumentView:nil];
2380 if ([self _loadingDragOperationForDraggingInfo:draggingInfo] != NSDragOperationNone) {
2381 NSURL *URL = [[self class] URLFromPasteboard:[draggingInfo draggingPasteboard]];
2383 [[self _UIDelegateForwarder] webView:self willPerformDragDestinationAction:WebDragDestinationActionLoad forDraggingInfo:draggingInfo];
2384 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
2385 [[self mainFrame] loadRequest:request];
2394 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2396 NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2397 if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2404 - (BOOL)acceptsFirstResponder
2406 return [[[self mainFrame] frameView] acceptsFirstResponder];
2409 - (BOOL)becomeFirstResponder
2411 // This works together with setNextKeyView to splice the WebView into
2412 // the key loop similar to the way NSScrollView does this. Note that
2413 // WebFrameView has very similar code.
2414 NSWindow *window = [self window];
2415 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2417 if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2418 NSView *previousValidKeyView = [self previousValidKeyView];
2419 if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2420 [window makeFirstResponder:previousValidKeyView];
2427 if ([mainFrameView acceptsFirstResponder]) {
2428 [window makeFirstResponder:mainFrameView];
2435 - (NSView *)_webcore_effectiveFirstResponder
2437 WebFrameView *frameView = [[self mainFrame] frameView];
2438 return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2441 - (void)setNextKeyView:(NSView *)aView
2443 // This works together with becomeFirstResponder to splice the WebView into
2444 // the key loop similar to the way NSScrollView does this. Note that
2445 // WebFrameView has very similar code.
2446 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2447 if (mainFrameView != nil) {
2448 [mainFrameView setNextKeyView:aView];
2450 [super setNextKeyView:aView];
2454 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2456 return forward ? [curr _nextFrameWithWrap:wrapFlag]
2457 : [curr _previousFrameWithWrap:wrapFlag];
2460 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2462 if (_private->closed)
2465 // Get the frame holding the selection, or start with the main frame
2466 WebFrame *startFrame = [self _selectedOrMainFrame];
2468 // Search the first frame, then all the other frames, in order
2469 NSView <WebDocumentSearching> *startSearchView = nil;
2470 BOOL startHasSelection = NO;
2471 WebFrame *frame = startFrame;
2473 id <WebDocumentView> view = [[frame frameView] documentView];
2474 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2475 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2477 // first time through
2478 if (frame == startFrame) {
2479 // Remember if start even has a selection, to know if we need to search more later
2480 if ([searchView isKindOfClass:[WebHTMLView class]]) {
2481 // optimization for the common case, to avoid making giant string for selection
2482 startHasSelection = [[startFrame _bridge] selectedDOMRange] != nil;
2483 } else if ([searchView conformsToProtocol:@protocol(WebDocumentText)]) {
2484 startHasSelection = [(id <WebDocumentText>)searchView selectedString] != nil;
2486 startSearchView = searchView;
2489 if ([searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:NO]) {
2490 if (frame != startFrame)
2491 [startFrame _clearSelection];
2492 [[self window] makeFirstResponder:searchView];
2496 frame = incrementFrame(frame, forward, wrapFlag);
2497 } while (frame != nil && frame != startFrame);
2499 // Search contents of startFrame, on the other side of the selection that we did earlier.
2500 // We cheat a bit and just research with wrap on
2501 if (wrapFlag && startHasSelection && startSearchView) {
2502 if ([startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]) {
2503 [[self window] makeFirstResponder:startSearchView];
2510 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2512 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2513 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2516 - (void)setGroupName:(NSString *)groupName
2518 [[self _pageBridge] setGroupName:groupName];
2521 - (NSString *)groupName
2523 return [[self _pageBridge] groupName];
2526 - (double)estimatedProgress
2528 return _private->progressValue;
2531 - (NSArray *)pasteboardTypesForSelection
2533 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
2534 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2535 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2537 return [NSArray array];
2540 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2542 WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
2543 if (bridge && [bridge selectionState] != WebSelectionStateRange) {
2544 NSView <WebDocumentView> *documentView = [[[bridge webFrame] frameView] documentView];
2545 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2546 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2551 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2553 if ([element objectForKey:WebElementImageURLKey] != nil) {
2554 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2555 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2556 return [NSPasteboard _web_writableTypesForURL];
2557 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2558 return [self pasteboardTypesForSelection];
2560 return [NSArray array];
2563 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2565 if ([element objectForKey:WebElementImageURLKey] != nil) {
2566 [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2567 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2568 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2569 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2570 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2574 - (void)moveDragCaretToPoint:(NSPoint)point
2576 [[[self mainFrame] _bridge] moveDragCaretToPoint:[self convertPoint:point toView:[[[self mainFrame] frameView] documentView]]];
2579 - (void)removeDragCaret
2581 [[[self mainFrame] _bridge] removeDragCaret];
2584 - (void)setMainFrameURL:(NSString *)URLString
2586 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2589 - (NSString *)mainFrameURL
2592 ds = [[self mainFrame] provisionalDataSource];
2594 ds = [[self mainFrame] dataSource];
2595 return [[[ds request] URL] _web_originalDataAsString];
2600 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2601 return [self _isLoading];
2604 - (NSString *)mainFrameTitle
2606 NSString *mainFrameTitle = [[[self mainFrame] dataSource] pageTitle];
2607 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
2610 - (NSImage *)mainFrameIcon
2612 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2615 - (DOMDocument *)mainFrameDocument
2617 // only return the actual value if the state we're in gives NSTreeController
2618 // enough time to release its observers on the old model
2619 if (_private->mainFrameDocumentReady)
2620 return [[self mainFrame] DOMDocument];
2624 - (void)setDrawsBackground:(BOOL)drawsBackground
2626 if (_private->drawsBackground == drawsBackground)
2628 _private->drawsBackground = drawsBackground;
2629 [[self mainFrame] _updateBackground];
2632 - (BOOL)drawsBackground
2634 return _private->drawsBackground;
2637 - (void)_inspectElement:(id)sender
2639 NSDictionary *element = [sender representedObject];
2640 WebFrame *frame = [element objectForKey:WebElementFrameKey];
2641 DOMNode *node = [element objectForKey:WebElementDOMNodeKey];
2642 if (!node || !frame)
2645 if ([node nodeType] != DOM_ELEMENT_NODE || [node nodeType] != DOM_DOCUMENT_NODE)
2646 node = [node parentNode];
2648 WebInspector *inspector = [WebInspector sharedWebInspector];
2649 [inspector setWebFrame:frame];
2650 [inspector setFocusedDOMNode:node];
2652 node = [node parentNode];
2653 node = [node parentNode];
2654 if (node) // set the root node to something relatively close to the focused node
2655 [inspector setRootDOMNode:node];
2657 [inspector showWindow:nil];
2661 @implementation WebView (WebIBActions)
2663 - (IBAction)takeStringURLFrom: sender
2665 NSString *URLString = [sender stringValue];
2667 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2672 return [[self backForwardList] backItem] != nil;
2675 - (BOOL)canGoForward
2677 return [[self backForwardList] forwardItem] != nil;
2680 - (IBAction)goBack:(id)sender
2685 - (IBAction)goForward:(id)sender
2690 - (IBAction)stopLoading:(id)sender
2692 [[self mainFrame] stopLoading];
2695 - (IBAction)reload:(id)sender
2697 [[self mainFrame] reload];
2700 #define MinimumTextSizeMultiplier 0.5f
2701 #define MaximumTextSizeMultiplier 3.0f
2702 #define TextSizeMultiplierRatio 1.2f
2704 - (BOOL)canMakeTextSmaller
2706 BOOL canShrinkMore = _private->textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2707 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:0];
2710 - (BOOL)canMakeTextLarger
2712 BOOL canGrowMore = _private->textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2713 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:0];
2716 - (IBAction)makeTextSmaller:(id)sender
2718 float newScale = _private->textSizeMultiplier / TextSizeMultiplierRatio;
2719 BOOL canShrinkMore = newScale > MinimumTextSizeMultiplier;
2720 [self _performTextSizingSelector:@selector(_makeTextSmaller:) withObject:sender onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:newScale];
2723 - (IBAction)makeTextLarger:(id)sender
2725 float newScale = _private->textSizeMultiplier*TextSizeMultiplierRatio;
2726 BOOL canGrowMore = newScale < MaximumTextSizeMultiplier;
2727 [self _performTextSizingSelector:@selector(_makeTextLarger:) withObject:sender onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:newScale];
2730 - (IBAction)toggleSmartInsertDelete:(id)sender
2732 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2735 - (IBAction)toggleContinuousSpellChecking:(id)sender
2737 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2740 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2742 id responder = [self _responderForResponderOperations];
2743 if (responder != self && [responder respondsToSelector:[item action]]) {
2744 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) {
2745 return [responder validateUserInterfaceItem:item];
2752 - (BOOL)canMakeTextStandardSize
2754 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2755 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:0.0f];
2758 - (IBAction)makeTextStandardSize:(id)sender
2760 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2761 [self _performTextSizingSelector:@selector(_makeTextStandardSize:) withObject:sender onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:1.0f];
2764 #define VALIDATE(name) \
2765 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2767 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2769 SEL action = [item action];
2771 if (action == @selector(goBack:)) {
2772 return [self canGoBack];
2773 } else if (action == @selector(goForward:)) {
2774 return [self canGoForward];
2775 } else if (action == @selector(makeTextLarger:)) {
2776 return [self canMakeTextLarger];
2777 } else if (action == @selector(makeTextSmaller:)) {
2778 return [self canMakeTextSmaller];
2779 } else if (action == @selector(makeTextStandardSize:)) {
2780 return [self canMakeTextStandardSize];
2781 } else if (action == @selector(reload:)) {
2782 return [[self mainFrame] dataSource] != nil;
2783 } else if (action == @selector(stopLoading:)) {
2784 return [self _isLoading];
2785 } else if (action == @selector(toggleContinuousSpellChecking:)) {
2786 BOOL checkMark = NO;
2788 if ([self _continuousCheckingAllowed]) {
2789 checkMark = [self isContinuousSpellCheckingEnabled];
2792 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2793 NSMenuItem *menuItem = (NSMenuItem *)item;
2794 [menuItem setState:checkMark ? NSOnState : NSOffState];
2798 FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2805 @implementation WebView (WebPendingPublic)
2807 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
2809 // by setting this to NO, calls to mainFrameDocument are forced to return nil
2810 // setting this to YES lets it return the actual DOMDocument value
2811 // we use this to tell NSTreeController to reset its observers and clear its state
2812 if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
2814 [self _willChangeValueForKey:_WebMainFrameDocumentKey];
2815 _private->mainFrameDocumentReady = mainFrameDocumentReady;
2816 [self _didChangeValueForKey:_WebMainFrameDocumentKey];
2817 // this will cause observers to call mainFrameDocument where this flag will be checked
2820 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it
2821 // until the day comes when we're no longer supporting Mail on Tiger.
2822 - (WebFrame *)_frameForCurrentSelection
2824 return [self _selectedOrMainFrame];
2827 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements
2829 _private->tabKeyCyclesThroughElementsChanged = YES;
2830 _private->tabKeyCyclesThroughElements = cyclesElements;
2833 - (BOOL)tabKeyCyclesThroughElements
2835 return _private->tabKeyCyclesThroughElements;
2838 - (void)setScriptDebugDelegate:delegate
2840 _private->scriptDebugDelegate = delegate;
2841 [_private->scriptDebugDelegateForwarder release];
2842 _private->scriptDebugDelegateForwarder = nil;
2844 [self _attachScriptDebuggerToAllFrames];
2846 [self _detachScriptDebuggerFromAllFrames];
2849 - scriptDebugDelegate
2851 return _private->scriptDebugDelegate;
2856 WebFrameBridge *bridge = [[self mainFrame] _bridge];
2859 return [bridge shouldClose];
2862 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
2864 return [[[self mainFrame] _bridge] aeDescByEvaluatingJavaScriptFromString:script];
2867 - (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(unsigned)limit
2869 WebFrame *frame = [self mainFrame];
2870 unsigned matchCount = 0;
2872 id <WebDocumentView> view = [[frame frameView] documentView];
2873 // FIXME: introduce a protocol, or otherwise make this work with other types
2874 if ([view isKindOfClass:[WebHTMLView class]])
2875 [(WebHTMLView *)view setMarkedTextMatchesAreHighlighted:highlight];
2877 ASSERT(limit == 0 || matchCount < limit);
2878 matchCount += [(WebHTMLView *)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
2880 // Stop looking if we've reached the limit. A limit of 0 means no limit.
2881 if (limit > 0 && matchCount >= limit)
2884 frame = incrementFrame(frame, YES, NO);
2890 - (void)unmarkAllTextMatches
2892 WebFrame *frame = [self mainFrame];
2894 id <WebDocumentView> view = [[frame frameView] documentView];
2895 // FIXME: introduce a protocol, or otherwise make this work with other types
2896 if ([view isKindOfClass:[WebHTMLView class]])
2897 [(WebHTMLView *)view unmarkAllTextMatches];
2899 frame = incrementFrame(frame, YES, NO);
2903 - (NSArray *)rectsForTextMatches
2905 NSMutableArray *result = [NSMutableArray array];
2906 WebFrame *frame = [self mainFrame];
2908 id <WebDocumentView> view = [[frame frameView] documentView];
2909 // FIXME: introduce a protocol, or otherwise make this work with other types
2910 if ([view isKindOfClass:[WebHTMLView class]]) {
2911 WebHTMLView *htmlView = (WebHTMLView *)view;
2912 NSArray *originalRects = [htmlView rectsForTextMatches];
2913 unsigned rectCount = [originalRects count];
2915 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
2916 for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
2917 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
2918 if (NSIsEmptyRect(r))
2921 // Convert rect to our coordinate system
2922 r = [htmlView convertRect:r toView:self];
2923 [result addObject:[NSValue valueWithRect:r]];
2924 if (rectIndex % 10 == 0)
2930 frame = incrementFrame(frame, YES, NO);
2938 @implementation WebView (WebViewPrintingPrivate)
2940 - (float)_headerHeight
2942 if ([[self UIDelegate] respondsToSelector:@selector(webViewHeaderHeight:)]) {
2943 return [[self UIDelegate] webViewHeaderHeight:self];
2946 #ifdef DEBUG_HEADER_AND_FOOTER
2953 - (float)_footerHeight
2955 if ([[self UIDelegate] respondsToSelector:@selector(webViewFooterHeight:)]) {
2956 return [[self UIDelegate] webViewFooterHeight:self];
2959 #ifdef DEBUG_HEADER_AND_FOOTER
2966 - (void)_drawHeaderInRect:(NSRect)rect
2968 #ifdef DEBUG_HEADER_AND_FOOTER
2969 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2970 [currentContext saveGraphicsState];
2971 [[NSColor yellowColor] set];
2973 [currentContext restoreGraphicsState];
2976 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawHeaderInRect:)]) {
2977 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2978 [currentContext saveGraphicsState];
2980 [[self UIDelegate] webView:self drawHeaderInRect:rect];
2981 [currentContext restoreGraphicsState];
2985 - (void)_drawFooterInRect:(NSRect)rect
2987 #ifdef DEBUG_HEADER_AND_FOOTER
2988 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2989 [currentContext saveGraphicsState];
2990 [[NSColor cyanColor] set];
2992 [currentContext restoreGraphicsState];
2995 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawFooterInRect:)]) {
2996 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2997 [currentContext saveGraphicsState];
2999 [[self UIDelegate] webView:self drawFooterInRect:rect];
3000 [currentContext restoreGraphicsState];
3004 - (void)_adjustPrintingMarginsForHeaderAndFooter
3006 NSPrintOperation *op = [NSPrintOperation currentOperation];
3007 NSPrintInfo *info = [op printInfo];
3008 float scale = [op _web_pageSetupScaleFactor];
3009 [info setTopMargin:[info topMargin] + [self _headerHeight]*scale];
3010 [info setBottomMargin:[info bottomMargin] + [self _footerHeight]*scale];
3013 - (void)_drawHeaderAndFooter
3015 // The header and footer rect height scales with the page, but the width is always
3016 // all the way across the printed page (inset by printing margins).
3017 NSPrintOperation *op = [NSPrintOperation currentOperation];
3018 float scale = [op _web_pageSetupScaleFactor];
3019 NSPrintInfo *printInfo = [op printInfo];
3020 NSSize paperSize = [printInfo paperSize];
3021 float headerFooterLeft = [printInfo leftMargin]/scale;
3022 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
3023 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] ,
3024 headerFooterWidth, [self _footerHeight]);
3025 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale,
3026 headerFooterWidth, [self _headerHeight]);
3028 [self _drawHeaderInRect:headerRect];
3029 [self _drawFooterInRect:footerRect];
3033 @implementation WebView (WebDebugBinding)
3035 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
3037 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
3038 [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
3041 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
3043 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
3044 [super removeObserver:anObserver forKeyPath:keyPath];
3049 //==========================================================================================
3052 @implementation WebView (WebViewCSS)
3054 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
3056 // FIXME: is this the best level for this conversion?
3057 if (pseudoElement == nil) {
3058 pseudoElement = @"";
3060 return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement];
3065 @implementation WebView (WebViewEditing)
3067 - (void)scrollDOMRangeToVisible:(DOMRange *)range
3069 [[[range startContainer] _bridge] scrollDOMRangeToVisible:range];
3072 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
3074 WebFrameBridge *bridge = [self _bridgeAtPoint:point];
3075 return [bridge editableDOMRangeForPoint:[self convertPoint:point toView:[[[bridge webFrame] frameView] documentView]]];
3078 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag;
3080 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
3083 - (BOOL)_shouldBeginEditingInDOMRange:(DOMRange *)range
3085 return [[self _editingDelegateForwarder] webView:self shouldBeginEditingInDOMRange:range];
3088 - (BOOL)_shouldEndEditingInDOMRange:(DOMRange *)range
3090 return [[self _editingDelegateForwarder] webView:self shouldEndEditingInDOMRange:range];
3093 - (BOOL)maintainsInactiveSelection
3098 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
3101 [[self _bridgeForSelectedOrMainFrame] deselectText];
3103 // Derive the bridge to use from the range passed in.
3104 // Using _bridgeForSelectedOrMainFrame could give us a different document than
3105 // the one the range uses.
3106 [[[range startContainer] _bridge] setSelectedDOMRange:range affinity:selectionAffinity closeTyping:YES];
3110 - (DOMRange *)selectedDOMRange
3112 return [[self _bridgeForSelectedOrMainFrame] selectedDOMRange];
3115 - (NSSelectionAffinity)selectionAffinity
3117 return [[self _bridgeForSelectedOrMainFrame] selectionAffinity];
3120 - (void)setEditable:(BOOL)flag
3122 if (_private->editable != flag) {
3123 _private->editable = flag;
3124 if (!_private->tabKeyCyclesThroughElementsChanged)
3125 _private->tabKeyCyclesThroughElements = !flag;
3126 WebFrameBridge *bridge = [[self mainFrame] _bridge];
3128 [bridge applyEditingStyleToBodyElement];
3129 // If the WebView is made editable and the selection is empty, set it to something.
3130 if (![self selectedDOMRange])
3131 [bridge setSelectionFromNone];
3133 [bridge removeEditingStyleFromBodyElement];
3139 return _private->editable;
3142 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
3144 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3145 // change the API to allow this.
3146 [[self _bridgeForSelectedOrMainFrame] setTypingStyle:style withUndoAction:WebUndoActionUnspecified];
3149 - (DOMCSSStyleDeclaration *)typingStyle
3151 return [[self _bridgeForSelectedOrMainFrame] typingStyle];
3154 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
3156 _private->smartInsertDeleteEnabled = flag;
3159 - (BOOL)smartInsertDeleteEnabled
3161 return _private->smartInsertDeleteEnabled;
3164 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
3166 _private->continuousSpellCheckingEnabled = flag;
3167 if ([self isContinuousSpellCheckingEnabled]) {
3168 [[self class] _preflightSpellChecker];
3170 [[self mainFrame] _unmarkAllMisspellings];
3174 - (BOOL)isContinuousSpellCheckingEnabled
3176 return _private->continuousSpellCheckingEnabled && [self _continuousCheckingAllowed];
3179 - (WebNSInteger)spellCheckerDocumentTag
3181 if (!_private->hasSpellCheckerDocumentTag) {
3182 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
3183 _private->hasSpellCheckerDocumentTag = YES;
3185 return _private->spellCheckerDocumentTag;
3188 - (NSUndoManager *)undoManager
3190 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
3194 return [super undoManager];
3197 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
3199 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3200 if ([_private->editingDelegate respondsToSelector:selector])
3201 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
3204 - (void)setEditingDelegate:(id)delegate
3206 if (_private->editingDelegate == delegate)
3209 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3211 // remove notifications from current delegate
3212 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
3213 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
3214 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
3215 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
3216 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
3218 _private->editingDelegate = delegate;
3219 [_private->editingDelegateForwarder release];
3220 _private->editingDelegateForwarder = nil;
3222 // add notifications for new delegate
3223 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
3224 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
3225 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
3226 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
3227 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
3230 - (id)editingDelegate
3232 return _private->editingDelegate;
3235 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
3237 // FIXME: Should this really be attached to the document with the current selection?
3238 DOMCSSStyleDeclaration *decl = [[[self _bridgeForSelectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
3239 [decl setCssText:text];
3245 @implementation WebView (WebViewUndoableEditing)
3247 - (void)replaceSelectionWithNode:(DOMNode *)node
3249 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO];
3252 - (void)replaceSelectionWithText:(NSString *)text
3254 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
3257 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
3259 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
3262 - (void)replaceSelectionWithArchive:(WebArchive *)archive
3264 [[[[self _bridgeForSelectedOrMainFrame] webFrame] dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
3267 - (void)deleteSelection
3269 WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
3270 [bridge deleteSelectionWithSmartDelete:[(WebHTMLView *)[[[bridge webFrame] frameView] documentView] _canSmartCopyOrDelete]];
3273 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
3275 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3276 // change the API to allow this.
3277 [[self _bridgeForSelectedOrMainFrame] applyStyle:style withUndoAction:WebUndoActionUnspecified];
3282 @implementation WebView (WebViewEditingActions)
3284 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
3286 static BOOL reentered = NO;
3288 [[self nextResponder] tryToPerform:selector with:parameter];
3292 // There are two possibilities here.
3294 // One is that WebView has been called in its role as part of the responder chain.
3295 // In that case, it's fine to call the first responder and end up calling down the
3296 // responder chain again. Later we will return here with reentered = YES and continue
3297 // past the WebView.
3299 // The other is that we are being called directly, in which case we want to pass the
3300 // selector down to the view inside us that can handle it, and continue down the
3301 // responder chain as usual.
3303 // Pass this selector down to the first responder.
3304 NSResponder *responder = [self _responderForResponderOperations];
3306 [responder tryToPerform:selector with:parameter];
3310 #define FORWARD(name) \
3311 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
3313 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
3315 - (void)insertText:(NSString *)text
3317 [self _performResponderOperation:_cmd with:text];
3322 @implementation WebView (WebViewEditingInMail)
3324 - (void)_insertNewlineInQuotedContent;
3326 [[self _bridgeForSelectedOrMainFrame] insertParagraphSeparatorInQuotedContent];
3329 - (BOOL)_selectWordBeforeMenuEvent
3331 return _private->selectWordBeforeMenuEvent;
3334 - (void)_setSelectWordBeforeMenuEvent:(BOOL)flag
3336 _private->selectWordBeforeMenuEvent = flag;
3339 - (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle
3341 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle];
3346 static WebFrameView *containingFrameView(NSView *view)
3348 while (view && ![view isKindOfClass:[WebFrameView class]])
3349 view = [view superview];
3350 return (WebFrameView *)view;
3353 @implementation WebView (WebFileInternal)
3355 - (WebFrame *)_focusedFrame
3357 NSResponder *resp = [[self window] firstResponder];
3358 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) {
3359 WebFrameView *frameView = containingFrameView((NSView *)resp);
3360 ASSERT(frameView != nil);
3361 return [frameView webFrame];
3367 - (WebFrame *)_selectedOrMainFrame
3369 WebFrame *result = [self selectedFrame];
3371 result = [self mainFrame];
3375 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame
3377 return [[self _selectedOrMainFrame] _bridge];
3382 WebFrame *mainFrame = [self mainFrame];
3383 return [[mainFrame dataSource] isLoading]
3384 || [[mainFrame provisionalDataSource] isLoading];
3387 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
3389 if (_private->closed)
3391 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
3392 if (![view isDescendantOf:[[self mainFrame] frameView]])
3394 WebFrameView *frameView = containingFrameView(view);
3399 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point
3401 return [[[self _frameViewAtWindowPoint:[self convertPoint:point toView:nil]] webFrame] _bridge];
3404 + (void)_preflightSpellCheckerNow:(id)sender
3406 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
3409 + (void)_preflightSpellChecker
3411 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3412 if ([NSSpellChecker sharedSpellCheckerExists]) {
3413 [self _preflightSpellCheckerNow:self];
3415 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
3419 - (BOOL)_continuousCheckingAllowed
3421 static BOOL allowContinuousSpellChecking = YES;
3422 static BOOL readAllowContinuousSpellCheckingDefault = NO;
3423 if (!readAllowContinuousSpellCheckingDefault) {
3424 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
3425 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
3427 readAllowContinuousSpellCheckingDefault = YES;
3429 return allowContinuousSpellChecking;
3432 - (NSResponder *)_responderForResponderOperations
3434 NSResponder *responder = [[self window] firstResponder];
3435 WebFrameView *mainFrameView = [[self mainFrame] frameView];
3437 // If the current responder is outside of the webview, use our main frameView or its
3438 // document view. We also do this for subviews of self that are siblings of the main
3439 // frameView since clients might insert non-webview-related views there (see 4552713).
3440 if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) {
3441 responder = [mainFrameView documentView];
3443 responder = mainFrameView;
3448 - (void)_searchWithGoogleFromMenu:(id)sender
3450 id documentView = [[[self selectedFrame] frameView] documentView];
3451 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3455 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3456 if ([selectedString length] == 0) {
3460 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
3461 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
3462 NSMutableString *s = [selectedString mutableCopy];
3463 const unichar nonBreakingSpaceCharacter = 0xA0;
3464 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1];
3465 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
3466 [pasteboard setString:s forType:NSStringPboardType];
3469 // FIXME: seems fragile to use the service by name, but this is what AppKit does
3470 NSPerformService(@"Search With Google", pasteboard);
3473 - (void)_searchWithSpotlightFromMenu:(id)sender
3475 id documentView = [[[self selectedFrame] frameView] documentView];
3476 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3480 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3481 if ([selectedString length] == 0) {
3485 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions);
3488 // Slightly funky method that lets us have one copy of the logic for finding docViews that can do
3489 // text sizing. It returns whether it found any "suitable" doc views. It sends sel to any suitable
3490 // doc views, or if sel==0 we do nothing to them. For doc views that track our size factor, they are
3491 // suitable if doTrackingViews==YES (which in practice means that our size factor isn't at its max or
3492 // min). For doc views that don't track it, we send them testSel to determine suitablility. If we
3493 // do find any suitable tracking doc views and newScaleFactor!=0, we will set the common scale factor
3494 // to that new factor before we send sel to any of them.
3495 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor
3497 if ([[self mainFrame] dataSource] == nil)
3500 BOOL foundSome = NO;
3501 NSArray *docViews = [[self mainFrame] _documentViews];
3502 for (int i = [docViews count]-1; i >= 0; i--) {
3503 id docView = [docViews objectAtIndex:i];
3504 if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)]) {
3505 id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
3507 if ([sizingDocView _tracksCommonSizeFactor]) {
3508 isSuitable = doTrackingViews;
3509 if (isSuitable && newScaleFactor != 0)
3510 _private->textSizeMultiplier = newScaleFactor;
3512 // Incantation to perform a selector returning a BOOL.
3513 isSuitable = ((BOOL(*)(id, SEL))objc_msgSend)(sizingDocView, testSel);
3519 [sizingDocView performSelector:sel withObject:arg];
3521 // if we're just called for the benefit of the return value, we can return at first match
3531 - (void)_notifyTextSizeMultiplierChanged
3533 if ([[self mainFrame] dataSource] == nil)
3536 NSArray *docViews = [[self mainFrame] _documentViews];
3537 for (int i = [docViews count]-1; i >= 0; i--) {
3538 id docView = [docViews objectAtIndex:i];
3539 if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)] == NO)
3542 id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
3543 if ([sizingDocView _tracksCommonSizeFactor])
3544 [sizingDocView _textSizeMultiplierChanged];
3551 @implementation WebView (WebViewBridge)
3553 - (WebPageBridge *)_pageBridge
3555 return _private->_pageBridge;