2 * Copyright (C) 2005, 2006, 2007, 2008 Apple 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 "DOMRangeInternal.h"
33 #import "WebBackForwardList.h"
34 #import "WebBackForwardListInternal.h"
35 #import "WebBaseNetscapePluginView.h"
36 #import "WebChromeClient.h"
37 #import "WebContextMenuClient.h"
38 #import "WebDOMOperationsPrivate.h"
39 #import "WebDatabaseManagerInternal.h"
40 #import "WebDatabaseManagerPrivate.h"
41 #import "WebDataSourceInternal.h"
42 #import "WebDefaultEditingDelegate.h"
43 #import "WebDefaultPolicyDelegate.h"
44 #import "WebDefaultScriptDebugDelegate.h"
45 #import "WebDefaultUIDelegate.h"
46 #import "WebDocument.h"
47 #import "WebDocumentInternal.h"
48 #import "WebDownload.h"
49 #import "WebDownloadInternal.h"
50 #import "WebDragClient.h"
51 #import "WebDynamicScrollBarsView.h"
52 #import "WebEditingDelegate.h"
53 #import "WebEditorClient.h"
54 #import "WebFormDelegatePrivate.h"
55 #import "WebFrameBridge.h"
56 #import "WebFrameInternal.h"
57 #import "WebFrameViewInternal.h"
58 #import "WebHTMLRepresentation.h"
59 #import "WebHTMLViewInternal.h"
60 #import "WebHistoryItemInternal.h"
61 #import "WebIconDatabase.h"
62 #import "WebIconDatabaseInternal.h"
63 #import "WebInspector.h"
64 #import "WebInspectorClient.h"
65 #import "WebKitErrors.h"
66 #import "WebKitLogging.h"
67 #import "WebKitNSStringExtras.h"
68 #import "WebKitStatisticsPrivate.h"
69 #import "WebKitSystemBits.h"
70 #import "WebKitVersionChecks.h"
71 #import "WebLocalizableStrings.h"
72 #import "WebNSDataExtras.h"
73 #import "WebNSDataExtrasPrivate.h"
74 #import "WebNSDictionaryExtras.h"
75 #import "WebNSEventExtras.h"
76 #import "WebNSObjectExtras.h"
77 #import "WebNSPasteboardExtras.h"
78 #import "WebNSPrintOperationExtras.h"
79 #import "WebNSURLExtras.h"
80 #import "WebNSURLRequestExtras.h"
81 #import "WebNSUserDefaultsExtras.h"
82 #import "WebNSViewExtras.h"
83 #import "WebPanelAuthenticationHandler.h"
84 #import "WebPasteboardHelper.h"
85 #import "WebPDFView.h"
86 #import "WebPluginDatabase.h"
87 #import "WebPolicyDelegate.h"
88 #import "WebPreferenceKeysPrivate.h"
89 #import "WebPreferencesPrivate.h"
90 #import "WebScriptDebugDelegatePrivate.h"
91 #import "WebScriptDebugServerPrivate.h"
92 #import "WebUIDelegate.h"
93 #import "WebUIDelegatePrivate.h"
94 #import <CoreFoundation/CFSet.h>
95 #import <Foundation/NSURLConnection.h>
96 #import <JavaScriptCore/Assertions.h>
97 #import <WebCore/Cache.h>
98 #import <WebCore/ColorMac.h>
99 #import <WebCore/Document.h>
100 #import <WebCore/DocumentLoader.h>
101 #import <WebCore/DragController.h>
102 #import <WebCore/DragData.h>
103 #import <WebCore/Editor.h>
104 #import <WebCore/ExceptionHandlers.h>
105 #import <WebCore/Frame.h>
106 #import <WebCore/FrameLoader.h>
107 #import <WebCore/FrameTree.h>
108 #import <WebCore/HTMLNames.h>
109 #import <WebCore/HistoryItem.h>
110 #import <WebCore/Logging.h>
111 #import <WebCore/MIMETypeRegistry.h>
112 #import <WebCore/Page.h>
113 #import <WebCore/PageCache.h>
114 #import <WebCore/PlatformMouseEvent.h>
115 #import <WebCore/ProgressTracker.h>
116 #import <WebCore/SelectionController.h>
117 #import <WebCore/Settings.h>
118 #import <WebCore/TextResourceDecoder.h>
119 #import <WebCore/WebCoreFrameBridge.h>
120 #import <WebCore/WebCoreObjCExtras.h>
121 #import <WebCore/WebCoreTextRenderer.h>
122 #import <WebCore/WebCoreView.h>
123 #import <WebKit/DOM.h>
124 #import <WebKit/DOMExtensions.h>
125 #import <WebKit/DOMPrivate.h>
126 #import <WebKit/WebDashboardRegion.h>
127 #import <WebKitSystemInterface.h>
128 #import <mach-o/dyld.h>
129 #import <objc/objc-auto.h>
130 #import <objc/objc-runtime.h>
131 #import <wtf/RefPtr.h>
132 #import <wtf/HashTraits.h>
134 using namespace WebCore;
136 #if defined(__ppc__) || defined(__ppc64__)
137 #define PROCESSOR "PPC"
138 #elif defined(__i386__) || defined(__x86_64__)
139 #define PROCESSOR "Intel"
141 #error Unknown architecture
144 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
146 macro(alignJustified) \
149 macro(capitalizeWord) \
150 macro(centerSelectionInVisibleArea) \
151 macro(changeAttributes) \
152 macro(changeBaseWritingDirection) \
153 macro(changeBaseWritingDirectionToLTR) \
154 macro(changeBaseWritingDirectionToRTL) \
156 macro(changeDocumentBackgroundColor) \
158 macro(changeSpelling) \
159 macro(checkSpelling) \
165 macro(deleteBackward) \
166 macro(deleteBackwardByDecomposingPreviousCharacter) \
167 macro(deleteForward) \
168 macro(deleteToBeginningOfLine) \
169 macro(deleteToBeginningOfParagraph) \
170 macro(deleteToEndOfLine) \
171 macro(deleteToEndOfParagraph) \
172 macro(deleteToMark) \
173 macro(deleteWordBackward) \
174 macro(deleteWordForward) \
175 macro(ignoreSpelling) \
177 macro(insertBacktab) \
178 macro(insertLineBreak) \
179 macro(insertNewline) \
180 macro(insertNewlineIgnoringFieldEditor) \
181 macro(insertParagraphSeparator) \
183 macro(insertTabIgnoringFieldEditor) \
184 macro(lowercaseWord) \
185 macro(moveBackward) \
186 macro(moveBackwardAndModifySelection) \
188 macro(moveDownAndModifySelection) \
190 macro(moveForwardAndModifySelection) \
192 macro(moveLeftAndModifySelection) \
193 macro(moveParagraphBackwardAndModifySelection) \
194 macro(moveParagraphForwardAndModifySelection) \
196 macro(moveRightAndModifySelection) \
197 macro(moveToBeginningOfDocument) \
198 macro(moveToBeginningOfDocumentAndModifySelection) \
199 macro(moveToBeginningOfLine) \
200 macro(moveToBeginningOfLineAndModifySelection) \
201 macro(moveToBeginningOfParagraph) \
202 macro(moveToBeginningOfParagraphAndModifySelection) \
203 macro(moveToBeginningOfSentence) \
204 macro(moveToBeginningOfSentenceAndModifySelection) \
205 macro(moveToEndOfDocument) \
206 macro(moveToEndOfDocumentAndModifySelection) \
207 macro(moveToEndOfLine) \
208 macro(moveToEndOfLineAndModifySelection) \
209 macro(moveToEndOfParagraph) \
210 macro(moveToEndOfParagraphAndModifySelection) \
211 macro(moveToEndOfSentence) \
212 macro(moveToEndOfSentenceAndModifySelection) \
214 macro(moveUpAndModifySelection) \
215 macro(moveWordBackward) \
216 macro(moveWordBackwardAndModifySelection) \
217 macro(moveWordForward) \
218 macro(moveWordForwardAndModifySelection) \
219 macro(moveWordLeft) \
220 macro(moveWordLeftAndModifySelection) \
221 macro(moveWordRight) \
222 macro(moveWordRightAndModifySelection) \
225 macro(pageDownAndModifySelection) \
227 macro(pageUpAndModifySelection) \
229 macro(pasteAsPlainText) \
230 macro(pasteAsRichText) \
232 macro(performFindPanelAction) \
233 macro(scrollLineDown) \
234 macro(scrollLineUp) \
235 macro(scrollPageDown) \
236 macro(scrollPageUp) \
237 macro(scrollToBeginningOfDocument) \
238 macro(scrollToEndOfDocument) \
241 macro(selectParagraph) \
242 macro(selectSentence) \
243 macro(selectToMark) \
246 macro(showGuessPanel) \
247 macro(startSpeaking) \
248 macro(stopSpeaking) \
251 macro(swapWithMark) \
252 macro(takeFindStringFromSelection) \
253 macro(toggleBaseWritingDirection) \
257 macro(uppercaseWord) \
259 macro(yankAndSelect) \
261 #define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin"
262 #define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin"
264 static BOOL s_didSetCacheModel;
265 static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
267 static BOOL applicationIsTerminating;
268 static int pluginDatabaseClientCount = 0;
270 @interface NSSpellChecker (AppKitSecretsIKnow)
271 - (void)_preflightChosenSpellServer;
274 @interface NSView (AppKitSecretsIKnow)
275 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
276 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
277 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
280 @interface NSWindow (AppKitSecretsIKnow)
281 - (id)_oldFirstResponderBeforeBecoming;
284 @interface NSObject (ValidateWithoutDelegate)
285 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item;
288 @interface _WebSafeForwarder : NSObject
290 id target; // Non-retained. Don't retain delegates.
292 BOOL catchExceptions;
294 - (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions;
297 @interface WebViewPrivate : NSObject
303 id UIDelegateForwarder;
304 id resourceProgressDelegate;
307 id policyDelegateForwarder;
308 id frameLoadDelegate;
309 id frameLoadDelegateForwarder;
310 id <WebFormDelegate> formDelegate;
312 id editingDelegateForwarder;
313 id scriptDebugDelegate;
314 id scriptDebugDelegateForwarder;
316 WebInspector *inspector;
320 float textSizeMultiplier;
322 NSString *applicationNameForUserAgent;
324 BOOL userAgentOverridden;
326 WebPreferences *preferences;
327 BOOL useSiteSpecificSpoofing;
329 NSWindow *hostWindow;
331 int programmaticFocusCount;
333 WebResourceDelegateImplementationCache resourceLoadDelegateImplementations;
334 WebFrameLoadDelegateImplementationCache frameLoadDelegateImplementations;
336 void *observationInfo;
339 BOOL shouldCloseWithWindow;
340 BOOL mainFrameDocumentReady;
341 BOOL drawsBackground;
343 BOOL tabKeyCyclesThroughElementsChanged;
344 BOOL becomingFirstResponder;
345 BOOL becomingFirstResponderFromOutside;
346 BOOL hoverFeedbackSuspended;
348 BOOL catchesDelegateExceptions;
350 NSColor *backgroundColor;
352 NSString *mediaStyle;
354 BOOL hasSpellCheckerDocumentTag;
355 NSInteger spellCheckerDocumentTag;
357 BOOL smartInsertDeleteEnabled;
359 BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
360 BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
361 BOOL dashboardBehaviorAlwaysAcceptsFirstMouse;
362 BOOL dashboardBehaviorAllowWheelScrolling;
364 // WebKit has both a global plug-in database and a separate, per WebView plug-in database. Dashboard uses the per WebView database.
365 WebPluginDatabase *pluginDatabase;
367 HashMap<unsigned long, RetainPtr<id> >* identifierMap;
371 @interface WebView (WebFileInternal)
372 - (WebFrame *)_selectedOrMainFrame;
373 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame;
375 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
376 - (WebFrame *)_focusedFrame;
377 + (void)_preflightSpellChecker;
378 - (BOOL)_continuousCheckingAllowed;
379 - (NSResponder *)_responderForResponderOperations;
380 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor;
381 - (void)_notifyTextSizeMultiplierChanged;
384 @interface WebView (WebCallDelegateFunctions)
387 NSString *WebElementDOMNodeKey = @"WebElementDOMNode";
388 NSString *WebElementFrameKey = @"WebElementFrame";
389 NSString *WebElementImageKey = @"WebElementImage";
390 NSString *WebElementImageAltStringKey = @"WebElementImageAltString";
391 NSString *WebElementImageRectKey = @"WebElementImageRect";
392 NSString *WebElementImageURLKey = @"WebElementImageURL";
393 NSString *WebElementIsSelectedKey = @"WebElementIsSelected";
394 NSString *WebElementLinkLabelKey = @"WebElementLinkLabel";
395 NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame";
396 NSString *WebElementLinkTitleKey = @"WebElementLinkTitle";
397 NSString *WebElementLinkURLKey = @"WebElementLinkURL";
398 NSString *WebElementSpellingToolTipKey = @"WebElementSpellingToolTip";
399 NSString *WebElementTitleKey = @"WebElementTitle";
400 NSString *WebElementLinkIsLiveKey = @"WebElementLinkIsLive";
401 NSString *WebElementIsContentEditableKey = @"WebElementIsContentEditableKey";
403 NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification";
404 NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification";
405 NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification";
407 NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification";
408 NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification";
409 NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification";
410 NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification";
411 NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification";
413 enum { WebViewVersion = 4 };
415 #define timedLayoutSize 4096
417 static NSMutableSet *schemesWithRepresentationsSet;
419 NSString *_WebCanGoBackKey = @"canGoBack";
420 NSString *_WebCanGoForwardKey = @"canGoForward";
421 NSString *_WebEstimatedProgressKey = @"estimatedProgress";
422 NSString *_WebIsLoadingKey = @"isLoading";
423 NSString *_WebMainFrameIconKey = @"mainFrameIcon";
424 NSString *_WebMainFrameTitleKey = @"mainFrameTitle";
425 NSString *_WebMainFrameURLKey = @"mainFrameURL";
426 NSString *_WebMainFrameDocumentKey = @"mainFrameDocument";
428 @interface WebProgressItem : NSObject
431 long long bytesReceived;
432 long long estimatedLength;
436 @implementation WebProgressItem
439 static BOOL continuousSpellCheckingEnabled;
440 #ifndef BUILDING_ON_TIGER
441 static BOOL grammarCheckingEnabled;
444 @implementation WebViewPrivate
446 #ifndef BUILDING_ON_TIGER
449 WebCoreObjCFinalizeOnMainThread(self);
459 textSizeMultiplier = 1;
460 dashboardBehaviorAllowWheelScrolling = YES;
461 shouldCloseWithWindow = objc_collecting_enabled();
462 continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled];
464 #ifndef BUILDING_ON_TIGER
465 grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled];
467 userAgent = new String;
471 identifierMap = new HashMap<unsigned long, RetainPtr<id> >();
472 pluginDatabaseClientCount++;
480 ASSERT(!preferences);
483 delete identifierMap;
485 [applicationNameForUserAgent release];
486 [backgroundColor release];
489 [hostWindow release];
491 [policyDelegateForwarder release];
492 [UIDelegateForwarder release];
493 [frameLoadDelegateForwarder release];
494 [editingDelegateForwarder release];
495 [scriptDebugDelegateForwarder release];
497 [mediaStyle release];
504 ASSERT_MAIN_THREAD();
507 delete identifierMap;
514 @implementation WebView (AllWebViews)
516 static CFSetCallBacks NonRetainingSetCallbacks = {
525 static CFMutableSetRef allWebViewsSet;
527 + (void)_makeAllWebViewsPerformSelector:(SEL)selector
532 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
535 - (void)_removeFromAllWebViewsSet
538 CFSetRemoveValue(allWebViewsSet, self);
541 - (void)_addToAllWebViewsSet
544 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
546 CFSetSetValue(allWebViewsSet, self);
551 @implementation WebView (WebPrivate)
553 #ifdef DEBUG_WIDGET_DRAWING
554 static bool debugWidget = true;
555 - (void)drawRect:(NSRect)rect
557 [[NSColor blueColor] set];
560 NSRect htmlViewRect = [[[[self mainFrame] frameView] documentView] frame];
563 while (debugWidget) {
568 NSLog (@"%s: rect: (%0.f,%0.f) %0.f %0.f, htmlViewRect: (%0.f,%0.f) %0.f %0.f\n",
569 __PRETTY_FUNCTION__, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
570 htmlViewRect.origin.x, htmlViewRect.origin.y, htmlViewRect.size.width, htmlViewRect.size.height
573 [super drawRect:rect];
577 + (BOOL)_scriptDebuggerEnabled
580 return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitScriptDebuggerEnabled"];
582 return YES; // always enable in debug builds
586 + (NSArray *)_supportedMIMETypes
588 // Load the plug-in DB allowing plug-ins to install types.
589 [WebPluginDatabase sharedDatabase];
590 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
593 + (NSArray *)_supportedFileExtensions
595 NSMutableSet *extensions = [[NSMutableSet alloc] init];
596 NSArray *MIMETypes = [self _supportedMIMETypes];
597 NSEnumerator *enumerator = [MIMETypes objectEnumerator];
599 while ((MIMEType = [enumerator nextObject]) != nil) {
600 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
601 if (extensionsForType) {
602 [extensions addObjectsFromArray:extensionsForType];
605 NSArray *uniqueExtensions = [extensions allObjects];
606 [extensions release];
607 return uniqueExtensions;
610 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
612 MIMEType = [MIMEType lowercaseString];
613 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
614 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
616 if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) {
617 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
618 // Load the plug-in DB allowing plug-ins to install types.
619 [WebPluginDatabase sharedDatabase];
621 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
622 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
623 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
626 if (viewClass && repClass) {
627 // Special-case WebHTMLView for text types that shouldn't be shown.
628 if (viewClass == [WebHTMLView class] &&
629 repClass == [WebHTMLRepresentation class] &&
630 [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) {
643 - (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
645 if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType])
648 if (_private->pluginDatabase) {
649 WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType];
652 *vClass = [WebHTMLView class];
654 *rClass = [WebHTMLRepresentation class];
662 + (void)_setAlwaysUseATSU:(BOOL)f
664 WebCoreSetAlwaysUseATSU(f);
667 + (BOOL)canShowFile:(NSString *)path
669 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
672 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
674 return WKGetPreferredExtensionForMIMEType(type);
679 if (!_private || _private->closed)
686 if (!_private || _private->closed)
689 FrameLoader* mainFrameLoader = [[self mainFrame] _frameLoader];
691 mainFrameLoader->detachFromParent();
693 [self _removeFromAllWebViewsSet];
694 [self setGroupName:nil];
695 [self setHostWindow:nil];
697 [self setDownloadDelegate:nil];
698 [self setEditingDelegate:nil];
699 [self setFrameLoadDelegate:nil];
700 [self setPolicyDelegate:nil];
701 [self setResourceLoadDelegate:nil];
702 [self setScriptDebugDelegate:nil];
703 [self setUIDelegate:nil];
705 [_private->inspector webViewClosed];
707 // setHostWindow:nil must be called before this value is set (see 5408186)
708 _private->closed = YES;
710 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
711 [self removeDragCaret];
713 // Deleteing the WebCore::Page will clear the page cache so we call destroy on
714 // all the plug-ins in the page cache to break any retain cycles.
715 // See comment in HistoryItem::releaseAllPendingPageCaches() for more information.
716 delete _private->page;
719 if (_private->hasSpellCheckerDocumentTag) {
720 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
721 _private->hasSpellCheckerDocumentTag = NO;
724 [[NSNotificationCenter defaultCenter] removeObserver:self];
726 [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]];
728 WebPreferences *preferences = _private->preferences;
729 _private->preferences = nil;
730 [preferences didRemoveFromWebView];
731 [preferences release];
733 pluginDatabaseClientCount--;
735 // Make sure to close both sets of plug-ins databases because plug-ins need an opportunity to clean up files, etc.
737 // Unload the WebView local plug-in database.
738 if (_private->pluginDatabase) {
739 [_private->pluginDatabase close];
740 [_private->pluginDatabase release];
741 _private->pluginDatabase = nil;
744 // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles.
745 if (!pluginDatabaseClientCount && applicationIsTerminating)
746 [WebPluginDatabase closeSharedDatabase];
749 + (NSString *)_MIMETypeForFile:(NSString *)path
751 NSString *extension = [path pathExtension];
752 NSString *MIMEType = nil;
754 // Get the MIME type from the extension.
755 if ([extension length] != 0) {
756 MIMEType = WKGetMIMETypeForExtension(extension);
759 // If we can't get a known MIME type from the extension, sniff.
760 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
761 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
762 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
764 if ([data length] != 0) {
765 MIMEType = [data _webkit_guessedMIMEType];
767 if ([MIMEType length] == 0) {
768 MIMEType = @"application/octet-stream";
775 - (WebDownload *)_downloadURL:(NSURL *)URL
779 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
780 WebDownload *download = [WebDownload _downloadWithRequest:request
781 delegate:_private->downloadDelegate
788 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
790 NSDictionary *features = [[NSDictionary alloc] init];
791 WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self
792 createWebViewWithRequest:nil
793 windowFeatures:features];
795 if (!newWindowWebView)
798 CallUIDelegate(newWindowWebView, @selector(webViewShow:));
799 return newWindowWebView;
802 - (WebInspector *)inspector
804 if (!_private->inspector)
805 _private->inspector = [[WebInspector alloc] initWithWebView:self];
806 return _private->inspector;
809 - (WebCore::Page*)page
811 return _private->page;
814 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
816 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items];
818 NSArray *menuItems = CallUIDelegate(self, @selector(webView:contextMenuItemsForElement:defaultMenuItems:), element, defaultMenuItems);
822 unsigned count = [menuItems count];
826 NSMenu *menu = [[NSMenu alloc] init];
827 for (unsigned i = 0; i < count; i++)
828 [menu addItem:[menuItems objectAtIndex:i]];
830 return [menu autorelease];
833 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags
835 // We originally intended to call this delegate method sometimes with a nil dictionary, but due to
836 // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't
837 // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients.
840 CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags);
843 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
848 if (!otherView->_private->page)
851 // It turns out the right combination of behavior is done with the back/forward load
852 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items
853 // in the back forward list, and go to the current one.
855 BackForwardList* backForwardList = _private->page->backForwardList();
856 ASSERT(!backForwardList->currentItem()); // destination list should be empty
858 BackForwardList* otherBackForwardList = otherView->_private->page->backForwardList();
859 if (!otherBackForwardList->currentItem())
860 return; // empty back forward list, bail
862 HistoryItem* newItemToGoTo = 0;
864 int lastItemIndex = otherBackForwardList->forwardListCount();
865 for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) {
867 // If this item is showing , save away its current scroll and form state,
868 // since that might have changed since loading and it is normally not saved
869 // until we leave that page.
870 otherView->_private->page->mainFrame()->loader()->saveDocumentAndScrollState();
872 RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy();
874 newItemToGoTo = newItem.get();
875 backForwardList->addItem(newItem.release());
878 ASSERT(newItemToGoTo);
879 _private->page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward);
882 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
884 _private->formDelegate = delegate;
887 - (id<WebFormDelegate>)_formDelegate
889 return _private->formDelegate;
892 - (BOOL)_needsAdobeFrameReloadingQuirk
894 static BOOL checked = NO;
895 static BOOL needsQuirk = NO;
900 needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0)
901 || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0)
902 || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0)
903 || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0)
904 || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2)
905 || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1)
906 || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1)
907 || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1)
908 || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1)
909 || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2);
915 - (BOOL)_needsKeyboardEventDisambiguationQuirks
917 static BOOL checked = NO;
918 static BOOL needsQuirks = NO;
923 needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH)
924 && ![[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"];
930 - (void)_preferencesChangedNotification:(NSNotification *)notification
932 WebPreferences *preferences = (WebPreferences *)[notification object];
933 ASSERT(preferences == [self preferences]);
935 if (!_private->userAgentOverridden)
936 *_private->userAgent = String();
938 // Cache this value so we don't have to read NSUserDefaults on each page load
939 _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
941 // Update corresponding WebCore Settings object.
945 Settings* settings = _private->page->settings();
947 settings->setCursiveFontFamily([preferences cursiveFontFamily]);
948 settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]);
949 settings->setDefaultFontSize([preferences defaultFontSize]);
950 settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]);
951 settings->setFantasyFontFamily([preferences fantasyFontFamily]);
952 settings->setFixedFontFamily([preferences fixedFontFamily]);
953 settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]);
954 settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]);
955 settings->setJavaEnabled([preferences isJavaEnabled]);
956 settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]);
957 settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]);
958 settings->setMinimumFontSize([preferences minimumFontSize]);
959 settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]);
960 settings->setPluginsEnabled([preferences arePlugInsEnabled]);
961 settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]);
962 settings->setSansSerifFontFamily([preferences sansSerifFontFamily]);
963 settings->setSerifFontFamily([preferences serifFontFamily]);
964 settings->setStandardFontFamily([preferences standardFontFamily]);
965 settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]);
966 settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]);
967 settings->setTextAreasAreResizable([preferences textAreasAreResizable]);
968 settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]);
969 settings->setEditableLinkBehavior(core([preferences editableLinkBehavior]));
970 settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]);
971 settings->setUsesPageCache([self usesPageCache]);
972 settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]);
973 settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]);
974 settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]);
975 if ([preferences userStyleSheetEnabled]) {
976 NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString];
977 settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]);
979 settings->setUserStyleSheetLocation([NSURL URLWithString:@""]);
980 settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]);
981 settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]);
982 settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing);
985 static inline IMP getMethod(id o, SEL s)
987 return [o respondsToSelector:s] ? [o methodForSelector:s] : 0;
990 - (void)_cacheResourceLoadDelegateImplementations
992 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
993 id delegate = _private->resourceProgressDelegate;
996 bzero(cache, sizeof(WebResourceDelegateImplementationCache));
1000 cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1001 cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:));
1002 cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:));
1003 cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:));
1004 cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:));
1005 cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:));
1006 cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:));
1007 cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:));
1008 cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:));
1009 cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:));
1010 cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:));
1013 WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *webView)
1015 static WebResourceDelegateImplementationCache empty;
1018 return &webView->_private->resourceLoadDelegateImplementations;
1021 - (void)_cacheFrameLoadDelegateImplementations
1023 WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations;
1024 id delegate = _private->frameLoadDelegate;
1027 bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache));
1031 cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:));
1032 cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:));
1033 cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:));
1034 cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:));
1035 cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:));
1036 cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:));
1037 cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:));
1038 cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:));
1039 cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:));
1040 cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:));
1041 cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:));
1042 cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:));
1043 cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:));
1044 cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:));
1045 cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:));
1046 cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:));
1047 cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:));
1050 WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *webView)
1052 static WebFrameLoadDelegateImplementationCache empty;
1055 return &webView->_private->frameLoadDelegateImplementations;
1058 - (id)_policyDelegateForwarder
1060 if (!_private->policyDelegateForwarder)
1061 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions];
1062 return _private->policyDelegateForwarder;
1065 - (id)_UIDelegateForwarder
1067 if (!_private->UIDelegateForwarder)
1068 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions];
1069 return _private->UIDelegateForwarder;
1072 - (id)_editingDelegateForwarder
1074 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
1075 // Not sure if that is a bug or not.
1079 if (!_private->editingDelegateForwarder)
1080 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions];
1081 return _private->editingDelegateForwarder;
1084 - (id)_scriptDebugDelegateForwarder
1086 if (!_private->scriptDebugDelegateForwarder)
1087 _private->scriptDebugDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->scriptDebugDelegate defaultTarget:[WebDefaultScriptDebugDelegate sharedScriptDebugDelegate] catchExceptions:_private->catchesDelegateExceptions];
1088 return _private->scriptDebugDelegateForwarder;
1091 - (void)_closeWindow
1093 [[self _UIDelegateForwarder] webViewClose:self];
1096 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
1098 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1099 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
1101 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1102 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner
1103 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1104 MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType);
1107 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
1109 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
1110 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
1112 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
1113 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner
1114 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
1115 if ([viewClass class] == [WebHTMLView class])
1116 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
1118 // This is used to make _representationExistsForURLScheme faster.
1119 // Without this set, we'd have to create the MIME type each time.
1120 if (schemesWithRepresentationsSet == nil) {
1121 schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
1123 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
1126 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1128 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
1131 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1133 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
1136 + (BOOL)_canHandleRequest:(NSURLRequest *)request
1138 // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed
1142 if ([NSURLConnection canHandleRequest:request])
1145 NSString *scheme = [[request URL] scheme];
1147 if ([self _representationExistsForURLScheme:scheme])
1150 return ([scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"]);
1153 + (NSString *)_decodeData:(NSData *)data
1155 HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet
1156 RefPtr<TextResourceDecoder> decoder = new TextResourceDecoder("text/html"); // bookmark files are HTML
1157 String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]);
1158 result += decoder->flush();
1162 - (void)_pushPerformingProgrammaticFocus
1164 _private->programmaticFocusCount++;
1167 - (void)_popPerformingProgrammaticFocus
1169 _private->programmaticFocusCount--;
1172 - (BOOL)_isPerformingProgrammaticFocus
1174 return _private->programmaticFocusCount != 0;
1177 - (void)_didChangeValueForKey: (NSString *)key
1179 LOG (Bindings, "calling didChangeValueForKey: %@", key);
1180 [self didChangeValueForKey: key];
1183 - (void)_willChangeValueForKey: (NSString *)key
1185 LOG (Bindings, "calling willChangeValueForKey: %@", key);
1186 [self willChangeValueForKey: key];
1189 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1190 static NSSet *manualNotifyKeys = nil;
1191 if (!manualNotifyKeys)
1192 manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1193 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1194 if ([manualNotifyKeys containsObject:key])
1199 - (NSArray *)_declaredKeys {
1200 static NSArray *declaredKeys = nil;
1202 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey,
1203 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil];
1204 return declaredKeys;
1207 - (void)setObservationInfo:(void *)info
1209 _private->observationInfo = info;
1212 - (void *)observationInfo
1214 return _private->observationInfo;
1217 - (void)_willChangeBackForwardKeys
1219 [self _willChangeValueForKey: _WebCanGoBackKey];
1220 [self _willChangeValueForKey: _WebCanGoForwardKey];
1223 - (void)_didChangeBackForwardKeys
1225 [self _didChangeValueForKey: _WebCanGoBackKey];
1226 [self _didChangeValueForKey: _WebCanGoForwardKey];
1229 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1231 [self _willChangeBackForwardKeys];
1232 if (frame == [self mainFrame]){
1233 // Force an observer update by sending a will/did.
1234 [self _willChangeValueForKey: _WebIsLoadingKey];
1235 [self _didChangeValueForKey: _WebIsLoadingKey];
1237 [self _willChangeValueForKey: _WebMainFrameURLKey];
1240 [NSApp setWindowsNeedUpdate:YES];
1243 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1245 if (frame == [self mainFrame])
1246 [self _didChangeValueForKey: _WebMainFrameURLKey];
1247 [NSApp setWindowsNeedUpdate:YES];
1250 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1252 [self _didChangeBackForwardKeys];
1253 if (frame == [self mainFrame]){
1254 // Force an observer update by sending a will/did.
1255 [self _willChangeValueForKey: _WebIsLoadingKey];
1256 [self _didChangeValueForKey: _WebIsLoadingKey];
1258 [NSApp setWindowsNeedUpdate:YES];
1261 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1263 [self _didChangeBackForwardKeys];
1264 if (frame == [self mainFrame]){
1265 // Force an observer update by sending a will/did.
1266 [self _willChangeValueForKey: _WebIsLoadingKey];
1267 [self _didChangeValueForKey: _WebIsLoadingKey];
1269 [NSApp setWindowsNeedUpdate:YES];
1272 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1274 [self _didChangeBackForwardKeys];
1275 if (frame == [self mainFrame]){
1276 // Force an observer update by sending a will/did.
1277 [self _willChangeValueForKey: _WebIsLoadingKey];
1278 [self _didChangeValueForKey: _WebIsLoadingKey];
1280 [self _didChangeValueForKey: _WebMainFrameURLKey];
1282 [NSApp setWindowsNeedUpdate:YES];
1285 - (void)_reloadForPluginChanges
1287 [[self mainFrame] _reloadForPluginChanges];
1290 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1292 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1293 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1294 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1296 return cachedResponse;
1299 - (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1301 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1302 DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey];
1303 [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey])
1305 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1306 title:[element objectForKey:WebElementImageAltStringKey]
1307 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1312 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1314 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1315 andTitle:[element objectForKey:WebElementLinkLabelKey]
1319 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1321 if (!_private->page)
1323 _private->page->dragController()->setDidInitiateDrag(initiatedDrag);
1326 #define DASHBOARD_CONTROL_LABEL @"control"
1328 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1330 // Add scroller regions for NSScroller and KWQScrollBar
1331 int i, count = [views count];
1333 for (i = 0; i < count; i++) {
1334 NSView *aView = [views objectAtIndex:i];
1336 if ([aView isKindOfClass:[NSScroller class]] ||
1337 [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1338 NSRect bounds = [aView bounds];
1339 NSRect adjustedBounds;
1340 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1341 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1343 // AppKit has horrible hack of placing absent scrollers at -100,-100
1344 if (adjustedBounds.origin.y == -100)
1346 adjustedBounds.size = bounds.size;
1347 NSRect clip = [aView visibleRect];
1348 NSRect adjustedClip;
1349 adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1350 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1351 adjustedClip.size = clip.size;
1352 WebDashboardRegion *aRegion =
1353 [[[WebDashboardRegion alloc] initWithRect:adjustedBounds
1354 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1355 NSMutableArray *scrollerRegions;
1356 scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1357 if (!scrollerRegions) {
1358 scrollerRegions = [NSMutableArray array];
1359 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1361 [scrollerRegions addObject:aRegion];
1363 [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1367 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1369 [self _addScrollerDashboardRegions:regions from:[self subviews]];
1372 - (NSDictionary *)_dashboardRegions
1374 // Only return regions from main frame.
1375 Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1378 NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary();
1379 [self _addScrollerDashboardRegions:regions];
1383 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag
1385 // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement
1386 // specific support for the backward compatibility mode flag.
1387 if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page)
1388 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true);
1391 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1392 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1395 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1396 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1399 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1400 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1403 case WebDashboardBehaviorAllowWheelScrolling: {
1404 _private->dashboardBehaviorAllowWheelScrolling = flag;
1407 case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1409 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag);
1415 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1418 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1419 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1421 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1422 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1424 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1425 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1427 case WebDashboardBehaviorAllowWheelScrolling: {
1428 return _private->dashboardBehaviorAllowWheelScrolling;
1430 case WebDashboardBehaviorUseBackwardCompatibilityMode: {
1431 return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode();
1437 + (void)_setShouldUseFontSmoothing:(BOOL)f
1439 WebCoreSetShouldUseFontSmoothing(f);
1442 + (BOOL)_shouldUseFontSmoothing
1444 return WebCoreShouldUseFontSmoothing();
1447 + (void)_setUsesTestModeFocusRingColor:(BOOL)f
1449 setUsesTestModeFocusRingColor(f);
1452 + (BOOL)_usesTestModeFocusRingColor
1454 return usesTestModeFocusRingColor();
1457 // This is only used by versions of Safari up to and including 3.0 and should be removed in a future release.
1458 + (NSString *)_minimumRequiredSafariBuildNumber
1463 - (void)setAlwaysShowVerticalScroller:(BOOL)flag
1465 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1467 [scrollview setVerticalScrollingMode:WebCoreScrollbarAlwaysOn andLock:YES];
1469 [scrollview setVerticalScrollingModeLocked:NO];
1470 [scrollview setVerticalScrollingMode:WebCoreScrollbarAuto];
1474 - (BOOL)alwaysShowVerticalScroller
1476 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1477 return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == WebCoreScrollbarAlwaysOn;
1480 - (void)setAlwaysShowHorizontalScroller:(BOOL)flag
1482 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1484 [scrollview setHorizontalScrollingMode:WebCoreScrollbarAlwaysOn andLock:YES];
1486 [scrollview setHorizontalScrollingModeLocked:NO];
1487 [scrollview setHorizontalScrollingMode:WebCoreScrollbarAuto];
1491 - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits
1493 Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1495 mainFrame->setProhibitsScrolling(prohibits);
1498 - (BOOL)alwaysShowHorizontalScroller
1500 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView];
1501 return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == WebCoreScrollbarAlwaysOn;
1504 - (void)_setInViewSourceMode:(BOOL)flag
1506 Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1508 mainFrame->setInViewSourceMode(flag);
1511 - (BOOL)_inViewSourceMode
1513 Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
1514 return mainFrame && mainFrame->inViewSourceMode();
1517 - (void)_setUseFastImageScalingMode:(BOOL)flag
1519 if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) {
1520 _private->page->setInLowQualityImageInterpolationMode(flag);
1521 [self setNeedsDisplay:YES];
1525 - (BOOL)_inFastImageScalingMode
1528 return _private->page->inLowQualityImageInterpolationMode();
1532 - (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths
1534 if (!_private->pluginDatabase)
1535 _private->pluginDatabase = [[WebPluginDatabase alloc] init];
1537 [_private->pluginDatabase setPlugInPaths:newPaths];
1538 [_private->pluginDatabase refresh];
1541 - (void)_attachScriptDebuggerToAllFrames
1543 for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext())
1544 [kit(frame) _attachScriptDebugger];
1547 - (void)_detachScriptDebuggerFromAllFrames
1549 for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext())
1550 [kit(frame) _detachScriptDebugger];
1553 - (void)setBackgroundColor:(NSColor *)backgroundColor
1555 if ([_private->backgroundColor isEqual:backgroundColor])
1558 id old = _private->backgroundColor;
1559 _private->backgroundColor = [backgroundColor retain];
1562 [[self mainFrame] _updateBackground];
1565 - (NSColor *)backgroundColor
1567 return _private->backgroundColor;
1570 - (BOOL)defersCallbacks
1572 if (!_private->page)
1574 return _private->page->defersLoading();
1577 - (void)setDefersCallbacks:(BOOL)defer
1579 if (!_private->page)
1581 return _private->page->setDefersLoading(defer);
1584 // For backwards compatibility with the WebBackForwardList API, we honor both
1585 // a per-WebView and a per-preferences setting for whether to use the page cache.
1587 - (BOOL)usesPageCache
1589 return _private->usesPageCache && [[self preferences] usesPageCache];
1592 - (void)setUsesPageCache:(BOOL)usesPageCache
1594 _private->usesPageCache = usesPageCache;
1596 // Post a notification so the WebCore settings update.
1597 [[self preferences] _postPreferencesChangesNotification];
1600 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
1602 NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window];
1603 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window];
1606 - (void)_clearUndoRedoOperations
1608 if (!_private->page)
1610 _private->page->clearUndoRedoOperations();
1613 - (void)_setCatchesDelegateExceptions:(BOOL)f
1615 _private->catchesDelegateExceptions = f;
1618 - (BOOL)_catchesDelegateExceptions
1620 return _private->catchesDelegateExceptions;
1623 - (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value
1625 Frame* coreFrame = [[[self mainFrame] _bridge] _frame];
1628 coreFrame->editor()->command(name).execute(value);
1633 @implementation _WebSafeForwarder
1635 // Used to send messages to delegates that implement informal protocols.
1637 - (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c
1639 self = [super init];
1642 target = t; // Non retained.
1644 catchExceptions = c;
1648 - (void)forwardInvocation:(NSInvocation *)invocation
1650 if ([target respondsToSelector:[invocation selector]]) {
1651 if (catchExceptions) {
1653 [invocation invokeWithTarget:target];
1654 } @catch(id exception) {
1655 ReportDiscardedDelegateException([invocation selector], exception);
1658 [invocation invokeWithTarget:target];
1662 if ([defaultTarget respondsToSelector:[invocation selector]])
1663 [invocation invokeWithTarget:defaultTarget];
1665 // Do nothing quietly if method not implemented.
1668 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1670 return [defaultTarget methodSignatureForSelector:aSelector];
1675 @implementation WebView
1679 static BOOL initialized = NO;
1684 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp];
1685 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil];
1686 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil];
1689 + (void)_applicationWillTerminate
1691 applicationIsTerminating = YES;
1692 if (!pluginDatabaseClientCount)
1693 [WebPluginDatabase closeSharedDatabase];
1696 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1698 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1701 - (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType
1703 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType];
1705 return pluginPackage;
1707 if (_private->pluginDatabase)
1708 return [_private->pluginDatabase pluginForMIMEType:MIMEType];
1713 - (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension
1715 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension];
1717 return pluginPackage;
1719 if (_private->pluginDatabase)
1720 return [_private->pluginDatabase pluginForExtension:extension];
1725 - (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType
1727 if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType])
1730 if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType])
1736 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1738 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1741 + (NSArray *)MIMETypesShownAsHTML
1743 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1744 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1746 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1748 while ((key = [enumerator nextObject])) {
1749 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1750 [array addObject:key];
1756 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1758 NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy];
1759 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1761 while ((key = [enumerator nextObject])) {
1762 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1763 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1766 int i, count = [MIMETypes count];
1767 for (i = 0; i < count; i++) {
1768 [WebView registerViewClass:[WebHTMLView class]
1769 representationClass:[WebHTMLRepresentation class]
1770 forMIMEType:[MIMETypes objectAtIndex:i]];
1772 [viewTypes release];
1775 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1777 return [pasteboard _web_bestURL];
1780 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1782 return [pasteboard stringForType:WebURLNamePboardType];
1785 + (void)registerURLSchemeAsLocal:(NSString *)protocol
1787 FrameLoader::registerURLSchemeAsLocal(protocol);
1790 - (void)_registerDraggedTypes
1792 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1793 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1794 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1795 [types addObjectsFromArray:URLTypes];
1796 [self registerForDraggedTypes:[types allObjects]];
1800 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1802 WebPreferences *standardPreferences = [WebPreferences standardPreferences];
1803 [standardPreferences willAddToWebView];
1805 _private->preferences = [standardPreferences retain];
1806 _private->catchesDelegateExceptions = YES;
1807 _private->mainFrameDocumentReady = NO;
1808 _private->drawsBackground = YES;
1809 _private->smartInsertDeleteEnabled = YES;
1810 _private->backgroundColor = [[NSColor whiteColor] retain];
1812 NSRect f = [self frame];
1813 WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1814 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1815 [self addSubview:frameView];
1816 [frameView release];
1818 WebKitInitializeLoggingChannelsIfNecessary();
1819 WebCore::InitializeLoggingChannelsIfNecessary();
1820 [WebHistoryItem initWindowWatcherIfNecessary];
1821 WebKitInitializeDatabasesIfNecessary();
1823 _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self));
1824 [[[WebFrameBridge alloc] initMainFrameWithPage:_private->page frameName:frameName frameView:frameView] release];
1826 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES))
1827 [self scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
1829 [self scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
1831 [self _addToAllWebViewsSet];
1832 [self setGroupName:groupName];
1834 // If there's already a next key view (e.g., from a nib), wire it up to our
1835 // contained frame view. In any case, wire our next key view up to the our
1836 // contained frame view. This works together with our becomeFirstResponder
1837 // and setNextKeyView overrides.
1838 NSView *nextKeyView = [self nextKeyView];
1839 if (nextKeyView && nextKeyView != frameView)
1840 [frameView setNextKeyView:nextKeyView];
1841 [super setNextKeyView:frameView];
1845 [self _registerDraggedTypes];
1847 // initialize WebScriptDebugServer here so listeners can register before any pages are loaded.
1848 if ([WebView _scriptDebuggerEnabled])
1849 [WebScriptDebugServer sharedScriptDebugServer];
1851 WebPreferences *prefs = [self preferences];
1852 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1853 name:WebPreferencesChangedNotification object:prefs];
1855 // Post a notification so the WebCore settings update.
1856 [[self preferences] _postPreferencesChangesNotification];
1858 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION))
1859 FrameLoader::setRestrictAccessToLocal(false);
1862 - (id)initWithFrame:(NSRect)f
1864 return [self initWithFrame:f frameName:nil groupName:nil];
1867 - (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName;
1869 self = [super initWithFrame:f];
1873 #ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1874 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1875 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the
1876 // need for Safari to unset it to prevent it from being passed to applications it launches.
1877 // Unsetting it when a WebView is first created is as good a place as any.
1878 // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details.
1879 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1880 unsetenv("DYLD_FRAMEWORK_PATH");
1881 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1885 _private = [[WebViewPrivate alloc] init];
1886 [self _commonInitializationWithFrameName:frameName groupName:groupName];
1887 [self setMaintainsBackForwardList: YES];
1891 - (id)initWithCoder:(NSCoder *)decoder
1893 WebView *result = nil;
1896 NSString *frameName;
1897 NSString *groupName;
1898 WebPreferences *preferences;
1899 BOOL useBackForwardList = NO;
1900 BOOL allowsUndo = YES;
1902 result = [super initWithCoder:decoder];
1903 result->_private = [[WebViewPrivate alloc] init];
1905 // We don't want any of the archived subviews. The subviews will always
1906 // be created in _commonInitializationFrameName:groupName:.
1907 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1909 if ([decoder allowsKeyedCoding]) {
1910 frameName = [decoder decodeObjectForKey:@"FrameName"];
1911 groupName = [decoder decodeObjectForKey:@"GroupName"];
1912 preferences = [decoder decodeObjectForKey:@"Preferences"];
1913 useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1914 if ([decoder containsValueForKey:@"AllowsUndo"])
1915 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"];
1918 [decoder decodeValueOfObjCType:@encode(int) at:&version];
1919 frameName = [decoder decodeObject];
1920 groupName = [decoder decodeObject];
1921 preferences = [decoder decodeObject];
1923 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList];
1924 // The allowsUndo field is no longer written out in encodeWithCoder, but since there are
1925 // version 3 NIBs that have this field encoded, we still need to read it in.
1927 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo];
1930 if (![frameName isKindOfClass:[NSString class]])
1932 if (![groupName isKindOfClass:[NSString class]])
1934 if (![preferences isKindOfClass:[WebPreferences class]])
1937 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList);
1938 [result _commonInitializationWithFrameName:frameName groupName:groupName];
1939 [result page]->backForwardList()->setEnabled(useBackForwardList);
1940 result->_private->allowsUndo = allowsUndo;
1942 [result setPreferences:preferences];
1943 } @catch (NSException *localException) {
1951 - (void)encodeWithCoder:(NSCoder *)encoder
1953 // Set asside the subviews before we archive. We don't want to archive any subviews.
1954 // The subviews will always be created in _commonInitializationFrameName:groupName:.
1955 id originalSubviews = _subviews;
1958 [super encodeWithCoder:encoder];
1960 // Restore the subviews we set aside.
1961 _subviews = originalSubviews;
1963 BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled();
1964 if ([encoder allowsKeyedCoding]) {
1965 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1966 [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1967 [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1968 [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"];
1969 [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"];
1971 int version = WebViewVersion;
1972 [encoder encodeValueOfObjCType:@encode(int) at:&version];
1973 [encoder encodeObject:[[self mainFrame] name]];
1974 [encoder encodeObject:[self groupName]];
1975 [encoder encodeObject:[self preferences]];
1976 [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList];
1977 // DO NOT encode any new fields here, doing so will break older WebKit releases.
1980 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList);
1985 // call close to ensure we tear-down completely
1986 // this maintains our old behavior for existing applications
1992 // [super dealloc] can end up dispatching against _private (3466082)
2000 ASSERT(_private->closed);
2012 - (void)setShouldCloseWithWindow:(BOOL)close
2014 _private->shouldCloseWithWindow = close;
2017 - (BOOL)shouldCloseWithWindow
2019 return _private->shouldCloseWithWindow;
2022 - (void)viewWillMoveToWindow:(NSWindow *)window
2024 // Don't do anything if we aren't initialized. This happens when decoding a WebView.
2029 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
2032 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window];
2034 // Ensure that we will receive the events that WebHTMLView (at least) needs. It's expensive enough
2035 // that we don't want to call it over and over.
2036 [window setAcceptsMouseMovedEvents:YES];
2037 WKSetNSWindowShouldPostEventNotifications(window, YES);
2041 - (void)_windowWillClose:(NSNotification *)notification
2043 if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow])))
2047 - (void)setPreferences:(WebPreferences *)prefs
2050 prefs = [WebPreferences standardPreferences];
2052 if (_private->preferences == prefs)
2055 [prefs willAddToWebView];
2057 WebPreferences *oldPrefs = _private->preferences;
2059 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
2060 [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]];
2062 _private->preferences = [prefs retain];
2064 // After registering for the notification, post it so the WebCore settings update.
2065 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
2066 name:WebPreferencesChangedNotification object:[self preferences]];
2067 [[self preferences] _postPreferencesChangesNotification];
2069 [oldPrefs didRemoveFromWebView];
2073 - (WebPreferences *)preferences
2075 return _private->preferences;
2078 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
2080 if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) {
2081 WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier];
2082 [self setPreferences:prefs];
2087 - (NSString *)preferencesIdentifier
2089 return [[self preferences] identifier];
2093 - (void)setUIDelegate:delegate
2095 _private->UIDelegate = delegate;
2096 [_private->UIDelegateForwarder release];
2097 _private->UIDelegateForwarder = nil;
2102 return _private->UIDelegate;
2105 - (void)setResourceLoadDelegate: delegate
2107 _private->resourceProgressDelegate = delegate;
2108 [self _cacheResourceLoadDelegateImplementations];
2111 - resourceLoadDelegate
2113 return _private->resourceProgressDelegate;
2116 - (void)setDownloadDelegate: delegate
2118 _private->downloadDelegate = delegate;
2124 return _private->downloadDelegate;
2127 - (void)setPolicyDelegate:delegate
2129 _private->policyDelegate = delegate;
2130 [_private->policyDelegateForwarder release];
2131 _private->policyDelegateForwarder = nil;
2136 return _private->policyDelegate;
2139 - (void)setFrameLoadDelegate:delegate
2141 _private->frameLoadDelegate = delegate;
2142 [self _cacheFrameLoadDelegateImplementations];
2144 // If this delegate wants callbacks for icons, fire up the icon database.
2145 if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc)
2146 [WebIconDatabase sharedIconDatabase];
2151 return _private->frameLoadDelegate;
2154 - (WebFrame *)mainFrame
2156 // This can be called in initialization, before _private has been set up (3465613)
2159 if (!_private->page)
2161 return kit(_private->page->mainFrame());
2164 - (WebFrame *)selectedFrame
2166 // If the first responder is a view in our tree, we get the frame containing the first responder.
2167 // This is faster than searching the frame hierarchy, and will give us a result even in the case
2168 // where the focused frame doesn't actually contain a selection.
2169 WebFrame *focusedFrame = [self _focusedFrame];
2171 return focusedFrame;
2173 // If the first responder is outside of our view tree, we search for a frame containing a selection.
2174 // There should be at most only one of these.
2175 return [[self mainFrame] _findFrameWithSelection];
2178 - (WebBackForwardList *)backForwardList
2180 if (!_private->page)
2182 if (!_private->page->backForwardList()->enabled())
2184 return kit(_private->page->backForwardList());
2187 - (void)setMaintainsBackForwardList: (BOOL)flag
2189 if (!_private->page)
2191 _private->page->backForwardList()->setEnabled(flag);
2196 if (!_private->page)
2199 return _private->page->goBack();
2204 if (!_private->page)
2207 return _private->page->goForward();
2210 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
2212 if (!_private->page)
2215 _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward);
2219 - (void)setTextSizeMultiplier:(float)m
2221 // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>)
2222 if (_private->textSizeMultiplier == m)
2225 _private->textSizeMultiplier = m;
2226 [self _notifyTextSizeMultiplierChanged];
2229 - (float)textSizeMultiplier
2231 return _private->textSizeMultiplier;
2234 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
2236 NSString *name = [applicationName copy];
2237 [_private->applicationNameForUserAgent release];
2238 _private->applicationNameForUserAgent = name;
2239 if (!_private->userAgentOverridden)
2240 *_private->userAgent = String();
2243 - (NSString *)applicationNameForUserAgent
2245 return [[_private->applicationNameForUserAgent retain] autorelease];
2248 - (void)setCustomUserAgent:(NSString *)userAgentString
2250 *_private->userAgent = userAgentString;
2251 _private->userAgentOverridden = userAgentString != nil;
2254 - (NSString *)customUserAgent
2256 if (!_private->userAgentOverridden)
2258 return *_private->userAgent;
2261 - (void)setMediaStyle:(NSString *)mediaStyle
2263 if (_private->mediaStyle != mediaStyle) {
2264 [_private->mediaStyle release];
2265 _private->mediaStyle = [mediaStyle copy];
2269 - (NSString *)mediaStyle
2271 return _private->mediaStyle;
2274 - (BOOL)supportsTextEncoding
2276 id documentView = [[[self mainFrame] frameView] documentView];
2277 return [documentView conformsToProtocol:@protocol(WebDocumentText)]
2278 && [documentView supportsTextEncoding];
2281 - (void)setCustomTextEncodingName:(NSString *)encoding
2283 NSString *oldEncoding = [self customTextEncodingName];
2284 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding])
2286 FrameLoader* mainFrameLoader = [[self mainFrame] _frameLoader];
2287 if (mainFrameLoader)
2288 mainFrameLoader->reloadAllowingStaleData(encoding);
2291 - (NSString *)_mainFrameOverrideEncoding
2293 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
2294 if (dataSource == nil)
2295 dataSource = [[self mainFrame] _dataSource];
2296 if (dataSource == nil)
2298 return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding());
2301 - (NSString *)customTextEncodingName
2303 return [self _mainFrameOverrideEncoding];
2306 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
2308 // Return statements are only valid in a function but some applications pass in scripts
2309 // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions
2310 // silently ignored the return. If the application is linked against an earlier version
2311 // of WebKit we will strip the return so the script wont fail.
2312 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) {
2313 NSRange returnStringRange = [script rangeOfString:@"return "];
2314 if (returnStringRange.length && !returnStringRange.location)
2315 script = [script substringFromIndex:returnStringRange.location + returnStringRange.length];
2318 NSString *result = [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
2319 // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script
2320 // Since there's no way to get rid of the main frame, result will never ever be nil here.
2326 - (WebScriptObject *)windowScriptObject
2328 Frame* coreFrame = core([self mainFrame]);
2331 return coreFrame->windowScriptObject();
2334 // Get the appropriate user-agent string for a particular URL.
2335 - (NSString *)userAgentForURL:(NSURL *)url
2337 return [self _userAgentForURL:KURL([url absoluteURL])];
2340 - (void)setHostWindow:(NSWindow *)hostWindow
2342 if (!_private->closed && hostWindow != _private->hostWindow) {
2343 [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
2344 if (_private->hostWindow)
2345 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow];
2347 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow];
2348 [_private->hostWindow release];
2349 _private->hostWindow = [hostWindow retain];
2350 [[self mainFrame] _viewDidMoveToHostWindow];
2354 - (NSWindow *)hostWindow
2356 return _private->hostWindow;
2359 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
2361 return [[self _frameViewAtWindowPoint:point] documentView];
2364 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
2366 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
2369 NSView <WebDocumentView> *documentView = [frameView documentView];
2370 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
2371 NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
2372 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
2374 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
2377 - (NSDictionary *)elementAtPoint:(NSPoint)point
2379 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2382 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2383 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination.
2384 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination.
2385 // Forward these calls to the document subview to make its scroll view scroll.
2386 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2388 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2389 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2392 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2394 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2395 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2398 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2400 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2401 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2402 IntPoint client([draggingInfo draggingLocation]);
2403 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2404 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2405 return core(self)->dragController()->dragEntered(&dragData);
2408 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2410 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2411 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2412 IntPoint client([draggingInfo draggingLocation]);
2413 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2414 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2415 return core(self)->dragController()->dragUpdated(&dragData);
2418 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2420 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2421 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil);
2422 IntPoint client([draggingInfo draggingLocation]);
2423 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2424 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2425 core(self)->dragController()->dragExited(&dragData);
2428 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2433 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2435 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2436 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil);
2437 IntPoint client([draggingInfo draggingLocation]);
2438 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
2439 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper);
2440 return core(self)->dragController()->performDrag(&dragData);
2443 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2445 NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2446 if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2453 - (BOOL)acceptsFirstResponder
2455 return [[[self mainFrame] frameView] acceptsFirstResponder];
2458 - (BOOL)becomeFirstResponder
2460 if (_private->becomingFirstResponder) {
2461 // Fix for unrepro infinite recursion reported in radar 4448181. If we hit this assert on
2462 // a debug build, we should figure out what causes the problem and do a better fix.
2463 ASSERT_NOT_REACHED();
2467 // This works together with setNextKeyView to splice the WebView into
2468 // the key loop similar to the way NSScrollView does this. Note that
2469 // WebFrameView has very similar code.
2470 NSWindow *window = [self window];
2471 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2473 NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming];
2474 BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self);
2476 if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2477 NSView *previousValidKeyView = [self previousValidKeyView];
2478 if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2479 _private->becomingFirstResponder = YES;
2480 _private->becomingFirstResponderFromOutside = fromOutside;
2481 [window makeFirstResponder:previousValidKeyView];
2482 _private->becomingFirstResponderFromOutside = NO;
2483 _private->becomingFirstResponder = NO;
2490 if ([mainFrameView acceptsFirstResponder]) {
2491 _private->becomingFirstResponder = YES;
2492 _private->becomingFirstResponderFromOutside = fromOutside;
2493 [window makeFirstResponder:mainFrameView];
2494 _private->becomingFirstResponderFromOutside = NO;
2495 _private->becomingFirstResponder = NO;
2502 - (NSView *)_webcore_effectiveFirstResponder
2504 WebFrameView *frameView = [[self mainFrame] frameView];
2505 return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2508 - (void)setNextKeyView:(NSView *)aView
2510 // This works together with becomeFirstResponder to splice the WebView into
2511 // the key loop similar to the way NSScrollView does this. Note that
2512 // WebFrameView has very similar code.
2513 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2514 if (mainFrameView != nil) {
2515 [mainFrameView setNextKeyView:aView];
2517 [super setNextKeyView:aView];
2521 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2523 Frame* coreFrame = core(curr);
2525 ? coreFrame->tree()->traverseNextWithWrap(wrapFlag)
2526 : coreFrame->tree()->traversePreviousWithWrap(wrapFlag));
2529 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2531 return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
2534 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2536 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2537 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2539 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed)
2540 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner
2541 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness
2542 if ([viewClass class] == [WebHTMLView class])
2543 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType);
2546 - (void)setGroupName:(NSString *)groupName
2548 if (!_private->page)
2550 _private->page->setGroupName(groupName);
2553 - (NSString *)groupName
2555 if (!_private->page)
2557 return _private->page->groupName();
2560 - (double)estimatedProgress
2562 if (!_private->page)
2565 return _private->page->progress()->estimatedProgress();
2568 - (NSArray *)pasteboardTypesForSelection
2570 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
2571 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2572 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2574 return [NSArray array];
2577 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2579 WebFrame *frame = [self _selectedOrMainFrame];
2580 if (frame && [frame _hasSelection]) {
2581 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2582 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)])
2583 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2587 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2589 if ([element objectForKey:WebElementImageURLKey] != nil) {
2590 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2591 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2592 return [NSPasteboard _web_writableTypesForURL];
2593 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2594 return [self pasteboardTypesForSelection];
2596 return [NSArray array];
2599 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2601 if ([element objectForKey:WebElementImageURLKey] != nil) {
2602 [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2603 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2604 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2605 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2606 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2610 - (void)moveDragCaretToPoint:(NSPoint)point
2612 if (Page* page = core(self))
2613 page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil]));
2616 - (void)removeDragCaret
2618 if (Page* page = core(self))
2619 page->dragController()->dragEnded();
2622 - (void)setMainFrameURL:(NSString *)URLString
2624 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2627 - (NSString *)mainFrameURL
2630 ds = [[self mainFrame] provisionalDataSource];
2632 ds = [[self mainFrame] _dataSource];
2633 return [[[ds request] URL] _web_originalDataAsString];
2638 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2639 return [self _isLoading];
2642 - (NSString *)mainFrameTitle
2644 NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle];
2645 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
2648 - (NSImage *)mainFrameIcon
2650 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2653 - (DOMDocument *)mainFrameDocument
2655 // only return the actual value if the state we're in gives NSTreeController
2656 // enough time to release its observers on the old model
2657 if (_private->mainFrameDocumentReady)
2658 return [[self mainFrame] DOMDocument];
2662 - (void)setDrawsBackground:(BOOL)drawsBackground
2664 if (_private->drawsBackground == drawsBackground)
2666 _private->drawsBackground = drawsBackground;
2667 [[self mainFrame] _updateBackground];
2670 - (BOOL)drawsBackground
2672 return _private->drawsBackground;
2677 @implementation WebView (WebIBActions)
2679 - (IBAction)takeStringURLFrom: sender
2681 NSString *URLString = [sender stringValue];
2683 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2688 if (!_private->page)
2691 return !!_private->page->backForwardList()->backItem();
2694 - (BOOL)canGoForward
2696 if (!_private->page)
2699 return !!_private->page->backForwardList()->forwardItem();
2702 - (IBAction)goBack:(id)sender
2707 - (IBAction)goForward:(id)sender
2712 - (IBAction)stopLoading:(id)sender
2714 [[self mainFrame] stopLoading];
2717 - (IBAction)reload:(id)sender
2719 [[self mainFrame] reload];
2722 #define MinimumTextSizeMultiplier 0.5f
2723 #define MaximumTextSizeMultiplier 3.0f
2724 #define TextSizeMultiplierRatio 1.2f
2726 - (BOOL)canMakeTextSmaller
2728 BOOL canShrinkMore = _private->textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2729 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:0];
2732 - (BOOL)canMakeTextLarger
2734 BOOL canGrowMore = _private->textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2735 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:0];
2738 - (IBAction)makeTextSmaller:(id)sender
2740 float newScale = _private->textSizeMultiplier / TextSizeMultiplierRatio;
2741 BOOL canShrinkMore = newScale > MinimumTextSizeMultiplier;
2742 [self _performTextSizingSelector:@selector(_makeTextSmaller:) withObject:sender onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:newScale];
2745 - (IBAction)makeTextLarger:(id)sender
2747 float newScale = _private->textSizeMultiplier*TextSizeMultiplierRatio;
2748 BOOL canGrowMore = newScale < MaximumTextSizeMultiplier;
2749 [self _performTextSizingSelector:@selector(_makeTextLarger:) withObject:sender onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:newScale];
2752 - (IBAction)toggleSmartInsertDelete:(id)sender
2754 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2757 - (IBAction)toggleContinuousSpellChecking:(id)sender
2759 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2762 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2764 id responder = [self _responderForResponderOperations];
2765 if (responder != self && [responder respondsToSelector:[item action]]) {
2766 if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)])
2767 return [responder validateUserInterfaceItemWithoutDelegate:item];
2768 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)])
2769 return [responder validateUserInterfaceItem:item];
2775 - (BOOL)canMakeTextStandardSize
2777 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2778 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:0.0f];
2781 - (IBAction)makeTextStandardSize:(id)sender
2783 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0f;
2784 [self _performTextSizingSelector:@selector(_makeTextStandardSize:) withObject:sender onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:1.0f];
2787 #define VALIDATE(name) \
2788 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2790 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
2792 SEL action = [item action];
2794 if (action == @selector(goBack:)) {
2795 return [self canGoBack];
2796 } else if (action == @selector(goForward:)) {
2797 return [self canGoForward];
2798 } else if (action == @selector(makeTextLarger:)) {
2799 return [self canMakeTextLarger];
2800 } else if (action == @selector(makeTextSmaller:)) {
2801 return [self canMakeTextSmaller];
2802 } else if (action == @selector(makeTextStandardSize:)) {
2803 return [self canMakeTextStandardSize];
2804 } else if (action == @selector(reload:)) {
2805 return [[self mainFrame] _dataSource] != nil;
2806 } else if (action == @selector(stopLoading:)) {
2807 return [self _isLoading];
2808 } else if (action == @selector(toggleContinuousSpellChecking:)) {
2809 BOOL checkMark = NO;
2811 if ([self _continuousCheckingAllowed]) {
2812 checkMark = [self isContinuousSpellCheckingEnabled];
2815 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2816 NSMenuItem *menuItem = (NSMenuItem *)item;
2817 [menuItem setState:checkMark ? NSOnState : NSOffState];
2820 #ifndef BUILDING_ON_TIGER
2821 } else if (action == @selector(toggleGrammarChecking:)) {
2822 BOOL checkMark = [self isGrammarCheckingEnabled];
2823 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2824 NSMenuItem *menuItem = (NSMenuItem *)item;
2825 [menuItem setState:checkMark ? NSOnState : NSOffState];
2830 FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2835 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2837 BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
2838 return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
2843 @implementation WebView (WebPendingPublic)
2845 - (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
2847 if (runLoop && mode)
2848 core(self)->addSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode));
2851 - (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode
2853 if (runLoop && mode)
2854 core(self)->removeSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode));
2857 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection
2859 if (_private->closed)
2862 // Get the frame holding the selection, or start with the main frame
2863 WebFrame *startFrame = [self _selectedOrMainFrame];
2865 // Search the first frame, then all the other frames, in order
2866 NSView <WebDocumentSearching> *startSearchView = nil;
2867 WebFrame *frame = startFrame;
2869 WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag);
2871 BOOL onlyOneFrame = (frame == nextFrame);
2872 ASSERT(!onlyOneFrame || frame == startFrame);
2874 id <WebDocumentView> view = [[frame frameView] documentView];
2875 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2876 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2878 if (frame == startFrame)
2879 startSearchView = searchView;
2882 // In some cases we have to search some content twice; see comment later in this method.
2883 // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag
2884 // here, and then bailing out before we get to the code that would search again in the
2886 BOOL wrapOnThisPass = wrapFlag && onlyOneFrame;
2887 if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
2888 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection];
2890 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass];
2893 if (frame != startFrame)
2894 [startFrame _clearSelection];
2895 [[self window] makeFirstResponder:searchView];
2903 } while (frame && frame != startFrame);
2905 // If there are multiple frames and wrapFlag is true and we've visited each one without finding a result, we still need to search in the
2906 // first-searched frame up to the selection. However, the API doesn't provide a way to search only up to a particular point. The only
2907 // way to make sure the entire frame is searched is to pass YES for the wrapFlag. When there are no matches, this will search again
2908 // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice.
2909 // To fix this, we'd need to add a mechanism to specify a range in which to search.
2910 if (wrapFlag && startSearchView) {
2912 if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)])
2913 foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection];
2915 foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES];
2917 [[self window] makeFirstResponder:startSearchView];
2924 - (void)setHoverFeedbackSuspended:(BOOL)newValue
2926 if (_private->hoverFeedbackSuspended == newValue)
2929 _private->hoverFeedbackSuspended = newValue;
2930 id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView];
2931 // FIXME: in a perfect world we'd do this in a general way that worked with any document view,
2932 // such as by calling a protocol method or using respondsToSelector or sending a notification.
2933 // But until there is any need for these more general solutions, we'll just hardwire it to work
2934 // with WebHTMLView.
2935 // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not
2936 // on each subframe separately.
2937 if ([documentView isKindOfClass:[WebHTMLView class]])
2938 [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged];
2941 - (BOOL)isHoverFeedbackSuspended
2943 return _private->hoverFeedbackSuspended;
2946 - (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady
2948 // by setting this to NO, calls to mainFrameDocument are forced to return nil
2949 // setting this to YES lets it return the actual DOMDocument value
2950 // we use this to tell NSTreeController to reset its observers and clear its state
2951 if (_private->mainFrameDocumentReady == mainFrameDocumentReady)
2953 [self _willChangeValueForKey:_WebMainFrameDocumentKey];
2954 _private->mainFrameDocumentReady = mainFrameDocumentReady;
2955 [self _didChangeValueForKey:_WebMainFrameDocumentKey];
2956 // this will cause observers to call mainFrameDocument where this flag will be checked
2959 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it
2960 // until the day comes when we're no longer supporting Mail on Tiger.
2961 - (WebFrame *)_frameForCurrentSelection
2963 return [self _selectedOrMainFrame];
2966 - (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements
2968 _private->tabKeyCyclesThroughElementsChanged = YES;
2970 _private->page->setTabKeyCyclesThroughElements(cyclesElements);
2973 - (BOOL)tabKeyCyclesThroughElements
2975 return _private->page && _private->page->tabKeyCyclesThroughElements();
2978 - (void)setScriptDebugDelegate:(id)delegate
2980 _private->scriptDebugDelegate = delegate;
2981 [_private->scriptDebugDelegateForwarder release];
2982 _private->scriptDebugDelegateForwarder = nil;
2984 [self _attachScriptDebuggerToAllFrames];
2986 [self _detachScriptDebuggerFromAllFrames];
2989 - (id)scriptDebugDelegate
2991 return _private->scriptDebugDelegate;
2996 Frame* coreFrame = core([self mainFrame]);
2999 return coreFrame->shouldClose();
3002 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
3004 return [[[self mainFrame] _bridge] aeDescByEvaluatingJavaScriptFromString:script];
3007 - (BOOL)canMarkAllTextMatches
3009 WebFrame *frame = [self mainFrame];
3011 id <WebDocumentView> view = [[frame frameView] documentView];
3012 if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)])
3015 frame = incrementFrame(frame, YES, NO);
3021 - (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit
3023 WebFrame *frame = [self mainFrame];
3024 unsigned matchCount = 0;
3026 id <WebDocumentView> view = [[frame frameView] documentView];
3027 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
3028 [(NSView <WebMultipleTextMatches>*)view setMarkedTextMatchesAreHighlighted:highlight];
3030 ASSERT(limit == 0 || matchCount < limit);
3031 matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount];
3033 // Stop looking if we've reached the limit. A limit of 0 means no limit.
3034 if (limit > 0 && matchCount >= limit)
3038 frame = incrementFrame(frame, YES, NO);
3044 - (void)unmarkAllTextMatches
3046 WebFrame *frame = [self mainFrame];
3048 id <WebDocumentView> view = [[frame frameView] documentView];
3049 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)])
3050 [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches];
3052 frame = incrementFrame(frame, YES, NO);
3056 - (NSArray *)rectsForTextMatches
3058 NSMutableArray *result = [NSMutableArray array];
3059 WebFrame *frame = [self mainFrame];
3061 id <WebDocumentView> view = [[frame frameView] documentView];
3062 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) {
3063 NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view;
3064 NSRect documentViewVisibleRect = [documentView visibleRect];
3065 NSArray *originalRects = [documentView rectsForTextMatches];
3066 unsigned rectCount = [originalRects count];
3068 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3069 for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
3070 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue];
3071 // Clip rect to document view's visible rect so rect is confined to subframe
3072 r = NSIntersectionRect(r, documentViewVisibleRect);
3073 if (NSIsEmptyRect(r))
3076 // Convert rect to our coordinate system
3077 r = [documentView convertRect:r toView:self];
3078 [result addObject:[NSValue valueWithRect:r]];
3079 if (rectIndex % 10 == 0) {
3081 pool = [[NSAutoreleasePool alloc] init];
3087 frame = incrementFrame(frame, YES, NO);
3093 - (void)scrollDOMRangeToVisible:(DOMRange *)range
3095 [[[range startContainer] _bridge] scrollDOMRangeToVisible:range];
3100 return _private->allowsUndo;
3103 - (void)setAllowsUndo:(BOOL)flag
3105 _private->allowsUndo = flag;
3110 @implementation WebView (WebViewPrintingPrivate)
3112 - (float)_headerHeight
3114 return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:));
3117 - (float)_footerHeight
3119 return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:));
3122 - (void)_drawHeaderInRect:(NSRect)rect
3124 #ifdef DEBUG_HEADER_AND_FOOTER
3125 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3126 [currentContext saveGraphicsState];
3127 [[NSColor yellowColor] set];
3129 [currentContext restoreGraphicsState];
3132 SEL selector = @selector(webView:drawHeaderInRect:);
3133 if (![_private->UIDelegate respondsToSelector:selector])
3136 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3137 [currentContext saveGraphicsState];
3140 CallUIDelegate(self, selector, rect);
3142 [currentContext restoreGraphicsState];
3145 - (void)_drawFooterInRect:(NSRect)rect
3147 #ifdef DEBUG_HEADER_AND_FOOTER
3148 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3149 [currentContext saveGraphicsState];
3150 [[NSColor cyanColor] set];
3152 [currentContext restoreGraphicsState];
3155 SEL selector = @selector(webView:drawFooterInRect:);
3156 if (![_private->UIDelegate respondsToSelector:selector])
3159 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
3160 [currentContext saveGraphicsState];
3163 CallUIDelegate(self, selector, rect);
3165 [currentContext restoreGraphicsState];
3168 - (void)_adjustPrintingMarginsForHeaderAndFooter
3170 NSPrintOperation *op = [NSPrintOperation currentOperation];
3171 NSPrintInfo *info = [op printInfo];
3172 NSMutableDictionary *infoDictionary = [info dictionary];
3174 // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the
3175 // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087),
3176 // we stash away the unmodified top and bottom margins the first time this method is called, and we read from
3177 // those stashed-away values on subsequent calls.
3178 float originalTopMargin;
3179 float originalBottomMargin;
3180 NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey];
3181 if (!originalTopMarginNumber) {
3182 ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]);
3183 originalTopMargin = [info topMargin];
3184 originalBottomMargin = [info bottomMargin];
3185 [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey];
3186 [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey];
3188 ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]);
3189 ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]);
3190 originalTopMargin = [originalTopMarginNumber floatValue];
3191 originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue];
3194 float scale = [op _web_pageSetupScaleFactor];
3195 [info setTopMargin:originalTopMargin + [self _headerHeight] * scale];
3196 [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale];
3199 - (void)_drawHeaderAndFooter
3201 // The header and footer rect height scales with the page, but the width is always
3202 // all the way across the printed page (inset by printing margins).
3203 NSPrintOperation *op = [NSPrintOperation currentOperation];
3204 float scale = [op _web_pageSetupScaleFactor];
3205 NSPrintInfo *printInfo = [op printInfo];
3206 NSSize paperSize = [printInfo paperSize];
3207 float headerFooterLeft = [printInfo leftMargin]/scale;
3208 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
3209 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] ,
3210 headerFooterWidth, [self _footerHeight]);
3211 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale,
3212 headerFooterWidth, [self _headerHeight]);
3214 [self _drawHeaderInRect:headerRect];
3215 [self _drawFooterInRect:footerRect];
3219 @implementation WebView (WebDebugBinding)
3221 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
3223 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
3224 [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
3227 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
3229 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
3230 [super removeObserver:anObserver forKeyPath:keyPath];
3235 //==========================================================================================
3238 @implementation WebView (WebViewCSS)
3240 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
3242 // FIXME: is this the best level for this conversion?
3243 if (pseudoElement == nil)
3244 pseudoElement = @"";
3246 return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement];
3251 @implementation WebView (WebViewEditing)
3253 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
3255 Page* page = core(self);
3258 return kit(page->mainFrame()->editor()->rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get());
3261 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag;
3263 // FIXME: This quirk is needed due to <rdar://problem/4985321> - We can phase it out once Aperture can adopt the new behavior on their end
3264 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"])
3266 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
3269 - (BOOL)maintainsInactiveSelection
3274 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
3276 Frame* coreFrame = core([self _selectedOrMainFrame]);
3281 coreFrame->selectionController()->clear();
3283 // Derive the frame to use from the range passed in.
3284 // Using _bridgeForSelectedOrMainFrame could give us a different document than
3285 // the one the range uses.
3286 coreFrame = core([range startContainer])->document()->frame();
3290 coreFrame->selectionController()->setSelectedRange([range _range], core(selectionAffinity), true);
3294 - (DOMRange *)selectedDOMRange
3296 Frame* coreFrame = core([self _selectedOrMainFrame]);
3299 return kit(coreFrame->selectionController()->toRange().get());
3302 - (NSSelectionAffinity)selectionAffinity
3304 Frame* coreFrame = core([self _selectedOrMainFrame]);
3306 return NSSelectionAffinityDownstream;
3307 return kit(coreFrame->selectionController()->affinity());
3310 - (void)setEditable:(BOOL)flag
3312 if (_private->editable != flag) {
3313 _private->editable = flag;
3314 if (!_private->tabKeyCyclesThroughElementsChanged && _private->page)
3315 _private->page->setTabKeyCyclesThroughElements(!flag);
3316 Frame* mainFrame = [[[self mainFrame] _bridge] _frame];
3319 mainFrame->applyEditingStyleToBodyElement();
3320 // If the WebView is made editable and the selection is empty, set it to something.
3321 if (![self selectedDOMRange])
3322 mainFrame->setSelectionFromNone();
3324 mainFrame->removeEditingStyleFromBodyElement();
3331 return _private->editable;
3334 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
3336 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3337 // change the API to allow this.
3338 [[self _bridgeForSelectedOrMainFrame] setTypingStyle:style withUndoAction:EditActionUnspecified];
3341 - (DOMCSSStyleDeclaration *)typingStyle
3343 return [[self _bridgeForSelectedOrMainFrame] typingStyle];
3346 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
3348 _private->smartInsertDeleteEnabled = flag;
3351 - (BOOL)smartInsertDeleteEnabled
3353 return _private->smartInsertDeleteEnabled;
3356 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
3358 if (continuousSpellCheckingEnabled != flag) {
3359 continuousSpellCheckingEnabled = flag;
3360 [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled];
3363 if ([self isContinuousSpellCheckingEnabled]) {
3364 [[self class] _preflightSpellChecker];
3366 [[self mainFrame] _unmarkAllMisspellings];
3370 - (BOOL)isContinuousSpellCheckingEnabled
3372 return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]);
3375 - (NSInteger)spellCheckerDocumentTag
3377 if (!_private->hasSpellCheckerDocumentTag) {
3378 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
3379 _private->hasSpellCheckerDocumentTag = YES;
3381 return _private->spellCheckerDocumentTag;
3384 - (NSUndoManager *)undoManager
3386 if (!_private->allowsUndo)
3389 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
3393 return [super undoManager];
3396 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
3398 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3399 if ([_private->editingDelegate respondsToSelector:selector])
3400 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
3403 - (void)setEditingDelegate:(id)delegate
3405 if (_private->editingDelegate == delegate)
3408 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
3410 // remove notifications from current delegate
3411 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
3412 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
3413 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
3414 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
3415 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
3417 _private->editingDelegate = delegate;
3418 [_private->editingDelegateForwarder release];
3419 _private->editingDelegateForwarder = nil;
3421 // add notifications for new delegate
3422 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
3423 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
3424 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
3425 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
3426 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
3429 - (id)editingDelegate
3431 return _private->editingDelegate;
3434 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
3436 // FIXME: Should this really be attached to the document with the current selection?
3437 DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
3438 [decl setCssText:text];
3444 @implementation WebView (WebViewGrammarChecking)
3446 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze
3447 - (BOOL)isGrammarCheckingEnabled
3449 #ifdef BUILDING_ON_TIGER
3452 return grammarCheckingEnabled;
3456 #ifndef BUILDING_ON_TIGER
3457 // FIXME: This method should be merged into WebViewEditing when we're not in API freeze
3458 - (void)setGrammarCheckingEnabled:(BOOL)flag
3460 if (grammarCheckingEnabled == flag)
3463 grammarCheckingEnabled = flag;
3464 [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled];
3466 // FIXME 4811447: workaround for lack of API
3467 NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
3468 if ([spellChecker respondsToSelector:@selector(_updateGrammar)])
3469 [spellChecker performSelector:@selector(_updateGrammar)];
3471 // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
3472 // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
3474 if (![self isGrammarCheckingEnabled])
3475 [[self mainFrame] _unmarkAllBadGrammar];
3478 // FIXME: This method should be merged into WebIBActions when we're not in API freeze
3479 - (void)toggleGrammarChecking:(id)sender
3481 [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]];
3487 @implementation WebView (WebViewUndoableEditing)
3489 - (void)replaceSelectionWithNode:(DOMNode *)node
3491 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO];
3494 - (void)replaceSelectionWithText:(NSString *)text
3496 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
3499 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
3501 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
3504 - (void)replaceSelectionWithArchive:(WebArchive *)archive
3506 [[[[self _bridgeForSelectedOrMainFrame] webFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
3509 - (void)deleteSelection
3511 WebFrame *webFrame = [self _selectedOrMainFrame];
3512 Frame* coreFrame = core(webFrame);
3514 coreFrame->editor()->deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]);
3517 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
3519 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3520 // change the API to allow this.
3521 WebFrame *webFrame = [self _selectedOrMainFrame];
3522 Frame* coreFrame = core(webFrame);
3524 coreFrame->editor()->applyStyle(core(style));
3529 @implementation WebView (WebViewEditingActions)
3531 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
3533 static BOOL reentered = NO;
3535 [[self nextResponder] tryToPerform:selector with:parameter];
3539 // There are two possibilities here.
3541 // One is that WebView has been called in its role as part of the responder chain.
3542 // In that case, it's fine to call the first responder and end up calling down the
3543 // responder chain again. Later we will return here with reentered = YES and continue
3544 // past the WebView.
3546 // The other is that we are being called directly, in which case we want to pass the
3547 // selector down to the view inside us that can handle it, and continue down the
3548 // responder chain as usual.
3550 // Pass this selector down to the first responder.
3551 NSResponder *responder = [self _responderForResponderOperations];
3553 [responder tryToPerform:selector with:parameter];
3557 #define FORWARD(name) \
3558 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
3560 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
3562 - (void)insertText:(NSString *)text
3564 [self _performResponderOperation:_cmd with:text];
3569 @implementation WebView (WebViewEditingInMail)
3571 - (void)_insertNewlineInQuotedContent;
3573 [[self _bridgeForSelectedOrMainFrame] insertParagraphSeparatorInQuotedContent];
3576 - (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle
3578 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle];
3583 static WebFrameView *containingFrameView(NSView *view)
3585 while (view && ![view isKindOfClass:[WebFrameView class]])
3586 view = [view superview];
3587 return (WebFrameView *)view;
3590 @implementation WebView (WebFileInternal)
3592 + (void)_setCacheModel:(WebCacheModel)cacheModel
3594 if (s_didSetCacheModel && cacheModel == s_cacheModel)
3597 NSString *nsurlCacheDirectory = [(NSString *)WKCopyFoundationCacheDirectory() autorelease];
3598 if (!nsurlCacheDirectory)
3599 nsurlCacheDirectory = NSHomeDirectory();
3601 // As a fudge factor, use 1000 instead of 1024, in case the reported byte
3602 // count doesn't align exactly to a megabyte boundary.
3603 vm_size_t memSize = WebMemorySize() / 1024 / 1000;
3604 unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000;
3605 NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
3607 unsigned cacheTotalCapacity = 0;
3608 unsigned cacheMinDeadCapacity = 0;
3609 unsigned cacheMaxDeadCapacity = 0;
3611 unsigned pageCacheCapacity = 0;
3613 NSUInteger nsurlCacheMemoryCapacity = 0;
3614 NSUInteger nsurlCacheDiskCapacity = 0;
3616 switch (cacheModel) {
3617 case WebCacheModelDocumentViewer: {
3618 // Page cache capacity (in pages)
3619 pageCacheCapacity = 0;
3621 // Object cache capacities (in bytes)
3622 if (memSize >= 4096)
3623 cacheTotalCapacity = 256 * 1024 * 1024;
3624 else if (memSize >= 3072)
3625 cacheTotalCapacity = 192 * 1024 * 1024;
3626 else if (memSize >= 2048)
3627 cacheTotalCapacity = 128 * 1024 * 1024;
3628 else if (memSize >= 1536)
3629 cacheTotalCapacity = 86 * 1024 * 1024;
3630 else if (memSize >= 1024)
3631 cacheTotalCapacity = 64 * 1024 * 1024;
3632 else if (memSize >= 512)
3633 cacheTotalCapacity = 32 * 1024 * 1024;
3634 else if (memSize >= 256)
3635 cacheTotalCapacity = 16 * 1024 * 1024;
3637 cacheMinDeadCapacity = 0;
3638 cacheMaxDeadCapacity = 0;
3640 // Foundation memory cache capacity (in bytes)
3641 nsurlCacheMemoryCapacity = 0;
3643 // Foundation disk cache capacity (in bytes)
3644 nsurlCacheDiskCapacity = [nsurlCache diskCapacity];
3648 case WebCacheModelDocumentBrowser: {
3649 // Page cache capacity (in pages)
3650 if (memSize >= 1024)
3651 pageCacheCapacity = 3;
3652 else if (memSize >= 512)
3653 pageCacheCapacity = 2;
3654 else if (memSize >= 256)
3655 pageCacheCapacity = 1;
3657 pageCacheCapacity = 0;
3659 // Object cache capacities (in bytes)
3660 if (memSize >= 4096)
3661 cacheTotalCapacity = 256 * 1024 * 1024;
3662 else if (memSize >= 3072)
3663 cacheTotalCapacity = 192 * 1024 * 1024;
3664 else if (memSize >= 2048)
3665 cacheTotalCapacity = 128 * 1024 * 1024;
3666 else if (memSize >= 1536)
3667 cacheTotalCapacity = 86 * 1024 * 1024;
3668 else if (memSize >= 1024)
3669 cacheTotalCapacity = 64 * 1024 * 1024;
3670 else if (memSize >= 512)
3671 cacheTotalCapacity = 32 * 1024 * 1024;
3672 else if (memSize >= 256)
3673 cacheTotalCapacity = 16 * 1024 * 1024;
3675 cacheMinDeadCapacity = cacheTotalCapacity / 8;
3676 cacheMaxDeadCapacity = cacheTotalCapacity / 4;
3678 // Foundation memory cache capacity (in bytes)
3679 if (memSize >= 2048)
3680 nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
3681 else if (memSize >= 1024)
3682 nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
3683 else if (memSize >= 512)
3684 nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
3686 nsurlCacheMemoryCapacity = 512 * 1024;
3688 // Foundation disk cache capacity (in bytes)
3689 if (diskFreeSize >= 16384)
3690 nsurlCacheDiskCapacity = 50 * 1024 * 1024;
3691 else if (diskFreeSize >= 8192)
3692 nsurlCacheDiskCapacity = 40 * 1024 * 1024;
3693 else if (diskFreeSize >= 4096)
3694 nsurlCacheDiskCapacity = 30 * 1024 * 1024;
3696 nsurlCacheDiskCapacity = 20 * 1024 * 1024;
3700 case WebCacheModelPrimaryWebBrowser: {
3701 // Page cache capacity (in pages)
3702 // (Research indicates that value / page drops substantially after 3 pages.)
3703 if (memSize >= 8192)
3704 pageCacheCapacity = 7;
3705 if (memSize >= 4096)
3706 pageCacheCapacity = 6;
3707 else if (memSize >= 2048)
3708 pageCacheCapacity = 5;
3709 else if (memSize >= 1024)
3710 pageCacheCapacity = 4;
3711 else if (memSize >= 512)
3712 pageCacheCapacity = 3;
3713 else if (memSize >= 256)
3714 pageCacheCapacity = 2;
3716 pageCacheCapacity = 1;
3718 // Object cache capacities (in bytes)
3719 // (Testing indicates that value / MB depends heavily on content and
3720 // browsing pattern. Even growth above 128MB can have substantial
3721 // value / MB for some content / browsing patterns.)
3722 if (memSize >= 4096)
3723 cacheTotalCapacity = 512 * 1024 * 1024;
3724 else if (memSize >= 3072)
3725 cacheTotalCapacity = 384 * 1024 * 1024;
3726 else if (memSize >= 2048)
3727 cacheTotalCapacity = 256 * 1024 * 1024;
3728 else if (memSize >= 1536)
3729 cacheTotalCapacity = 172 * 1024 * 1024;
3730 else if (memSize >= 1024)
3731 cacheTotalCapacity = 128 * 1024 * 1024;
3732 else if (memSize >= 512)
3733 cacheTotalCapacity = 64 * 1024 * 1024;
3734 else if (memSize >= 256)
3735 cacheTotalCapacity = 32 * 1024 * 1024;
3737 cacheMinDeadCapacity = cacheTotalCapacity / 4;
3738 cacheMaxDeadCapacity = cacheTotalCapacity / 2;
3740 // This code is here to avoid a PLT regression. We can remove it if we
3741 // can prove that the overall system gain would justify the regression.
3742 cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);
3744 // Foundation memory cache capacity (in bytes)
3745 // (These values are small because WebCore does most caching itself.)
3746 if (memSize >= 1024)
3747 nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
3748 else if (memSize >= 512)
3749 nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
3750 else if (memSize >= 256)
3751 nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
3753 nsurlCacheMemoryCapacity = 512 * 1024;
3755 // Foundation disk cache capacity (in bytes)
3756 if (diskFreeSize >= 16384)
3757 nsurlCacheDiskCapacity = 175 * 1024 * 1024;
3758 else if (diskFreeSize >= 8192)
3759 nsurlCacheDiskCapacity = 150 * 1024 * 1024;
3760 else if (diskFreeSize >= 4096)
3761 nsurlCacheDiskCapacity = 125 * 1024 * 1024;
3762 else if (diskFreeSize >= 2048)
3763 nsurlCacheDiskCapacity = 100 * 1024 * 1024;
3764 else if (diskFreeSize >= 1024)
3765 nsurlCacheDiskCapacity = 75 * 1024 * 1024;
3767 nsurlCacheDiskCapacity = 50 * 1024 * 1024;
3772 ASSERT_NOT_REACHED();
3775 #ifdef BUILDING_ON_TIGER
3776 // Don't use a big Foundation disk cache on Tiger because, according to the
3777 // PLT, the Foundation disk cache on Tiger is slower than the network.
3778 nsurlCacheDiskCapacity = [nsurlCache diskCapacity];
3781 // Don't shrink a big disk cache, since that would cause churn.
3782 nsurlCacheDiskCapacity = max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]);
3784 cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
3785 pageCache()->setCapacity(pageCacheCapacity);
3786 [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity];
3787 [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity];
3789 s_cacheModel = cacheModel;
3790 s_didSetCacheModel = YES;
3793 + (WebCacheModel)_cacheModel
3795 return s_cacheModel;
3798 + (WebCacheModel)_didSetCacheModel
3800 return s_didSetCacheModel;
3803 + (WebCacheModel)_maxCacheModelInAnyInstance
3805 WebCacheModel cacheModel = WebCacheModelDocumentViewer;
3806 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator];
3807 while (WebPreferences *preferences = [[enumerator nextObject] preferences])
3808 cacheModel = max(cacheModel, [preferences cacheModel]);
3812 + (void)_preferencesChangedNotification:(NSNotification *)notification
3814 WebPreferences *preferences = (WebPreferences *)[notification object];
3815 ASSERT([preferences isKindOfClass:[WebPreferences class]]);
3817 WebCacheModel cacheModel = [preferences cacheModel];
3818 if (![self _didSetCacheModel] || cacheModel > [self _cacheModel])
3819 [self _setCacheModel:cacheModel];
3820 else if (cacheModel < [self _cacheModel])
3821 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
3824 + (void)_preferencesRemovedNotification:(NSNotification *)notification
3826 WebPreferences *preferences = (WebPreferences *)[notification object];
3827 ASSERT([preferences isKindOfClass:[WebPreferences class]]);
3829 if ([preferences cacheModel] == [self _cacheModel])
3830 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
3833 - (WebFrame *)_focusedFrame
3835 NSResponder *resp = [[self window] firstResponder];
3836 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) {
3837 WebFrameView *frameView = containingFrameView((NSView *)resp);
3838 ASSERT(frameView != nil);
3839 return [frameView webFrame];
3845 - (WebFrame *)_selectedOrMainFrame
3847 WebFrame *result = [self selectedFrame];
3849 result = [self mainFrame];
3853 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame
3855 return [[self _selectedOrMainFrame] _bridge];
3860 WebFrame *mainFrame = [self mainFrame];
3861 return [[mainFrame _dataSource] isLoading]
3862 || [[mainFrame provisionalDataSource] isLoading];
3865 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
3867 if (_private->closed)
3869 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
3870 if (![view isDescendantOf:[[self mainFrame] frameView]])
3872 WebFrameView *frameView = containingFrameView(view);
3877 + (void)_preflightSpellCheckerNow:(id)sender
3879 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
3882 + (void)_preflightSpellChecker
3884 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3885 if ([NSSpellChecker sharedSpellCheckerExists]) {
3886 [self _preflightSpellCheckerNow:self];
3888 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
3892 - (BOOL)_continuousCheckingAllowed
3894 static BOOL allowContinuousSpellChecking = YES;
3895 static BOOL readAllowContinuousSpellCheckingDefault = NO;
3896 if (!readAllowContinuousSpellCheckingDefault) {
3897 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
3898 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
3900 readAllowContinuousSpellCheckingDefault = YES;
3902 return allowContinuousSpellChecking;
3905 - (NSResponder *)_responderForResponderOperations
3907 NSResponder *responder = [[self window] firstResponder];
3908 WebFrameView *mainFrameView = [[self mainFrame] frameView];
3910 // If the current responder is outside of the webview, use our main frameView or its
3911 // document view. We also do this for subviews of self that are siblings of the main
3912 // frameView since clients might insert non-webview-related views there (see 4552713).
3913 if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) {
3914 responder = [mainFrameView documentView];
3916 responder = mainFrameView;
3921 - (void)_openFrameInNewWindowFromMenu:(NSMenuItem *)sender
3923 ASSERT_ARG(sender, [sender isKindOfClass:[NSMenuItem class]]);
3925 NSDictionary *element = [sender representedObject];
3926 ASSERT([element isKindOfClass:[NSDictionary class]]);
3928 NSURLRequest *request = [[[[element objectForKey:WebElementFrameKey] dataSource] request] copy];
3931 [self _openNewWindowWithRequest:request];
3935 - (void)_searchWithGoogleFromMenu:(id)sender
3937 id documentView = [[[self selectedFrame] frameView] documentView];
3938 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3942 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3943 if ([selectedString length] == 0) {
3947 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
3948 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
3949 NSMutableString *s = [selectedString mutableCopy];
3950 const unichar nonBreakingSpaceCharacter = 0xA0;
3951 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1];
3952 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
3953 [pasteboard setString:s forType:NSStringPboardType];
3956 // FIXME: seems fragile to use the service by name, but this is what AppKit does
3957 NSPerformService(@"Search With Google", pasteboard);
3960 - (void)_searchWithSpotlightFromMenu:(id)sender
3962 id documentView = [[[self selectedFrame] frameView] documentView];
3963 if (![documentView conformsToProtocol:@protocol(WebDocumentText)])
3966 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3967 if ([selectedString length] == 0) {
3971 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions);
3974 // Slightly funky method that lets us have one copy of the logic for finding docViews that can do
3975 // text sizing. It returns whether it found any "suitable" doc views. It sends sel to any suitable
3976 // doc views, or if sel==0 we do nothing to them. For doc views that track our size factor, they are
3977 // suitable if doTrackingViews==YES (which in practice means that our size factor isn't at its max or
3978 // min). For doc views that don't track it, we send them testSel to determine suitablility. If we
3979 // do find any suitable tracking doc views and newScaleFactor!=0, we will set the common scale factor
3980 // to that new factor before we send sel to any of them.
3981 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor
3983 if ([[self mainFrame] _dataSource] == nil)
3986 BOOL foundSome = NO;
3987 NSArray *docViews = [[self mainFrame] _documentViews];
3988 for (int i = [docViews count]-1; i >= 0; i--) {
3989 id docView = [docViews objectAtIndex:i];
3990 if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)]) {
3991 id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
3993 if ([sizingDocView _tracksCommonSizeFactor]) {
3994 isSuitable = doTrackingViews;
3995 if (isSuitable && newScaleFactor != 0)
3996 _private->textSizeMultiplier = newScaleFactor;
3998 // Incantation to perform a selector returning a BOOL.
3999 isSuitable = ((BOOL(*)(id, SEL))objc_msgSend)(sizingDocView, testSel);
4005 [sizingDocView performSelector:sel withObject:arg];
4007 // if we're just called for the benefit of the return value, we can return at first match
4017 - (void)_notifyTextSizeMultiplierChanged
4019 if ([[self mainFrame] _dataSource] == nil)
4022 NSArray *docViews = [[self mainFrame] _documentViews];
4023 for (int i = [docViews count]-1; i >= 0; i--) {
4024 id docView = [docViews objectAtIndex:i];
4025 if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)] == NO)
4028 id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
4029 if ([sizingDocView _tracksCommonSizeFactor])
4030 [sizingDocView _textSizeMultiplierChanged];
4037 @implementation WebView (WebViewInternal)
4039 - (BOOL)_becomingFirstResponderFromOutside
4041 return _private->becomingFirstResponderFromOutside;
4044 - (void)_receivedIconChangedNotification:(NSNotification *)notification
4046 // Get the URL for this notification
4047 NSDictionary *userInfo = [notification userInfo];
4048 ASSERT([userInfo isKindOfClass:[NSDictionary class]]);
4049 NSString *urlString = [userInfo objectForKey:WebIconNotificationUserInfoURLKey];
4050 ASSERT([urlString isKindOfClass:[NSString class]]);
4052 // If that URL matches the current main frame, dispatch the delegate call, which will also unregister
4053 // us for this notification
4054 if ([[self mainFrameURL] isEqualTo:urlString])
4055 [self _dispatchDidReceiveIconFromWebFrame:[self mainFrame]];
4058 - (void)_registerForIconNotification:(BOOL)listen
4061 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_receivedIconChangedNotification:) name:WebIconDatabaseDidAddIconNotification object:nil];
4063 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebIconDatabaseDidAddIconNotification object:nil];
4066 - (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame
4068 // FIXME: This willChangeValueForKey call is too late, because the icon has already changed by now.
4069 [self _willChangeValueForKey:_WebMainFrameIconKey];
4071 // Since we definitely have an icon and are about to send out the delegate call for that, this WebView doesn't need to listen for the general
4072 // notification any longer
4073 [self _registerForIconNotification:NO];
4075 WebFrameLoadDelegateImplementationCache* cache = &_private->frameLoadDelegateImplementations;
4076 if (cache->didReceiveIconForFrameFunc) {
4077 Image* image = iconDatabase()->iconForPageURL(core(webFrame)->loader()->url().string(), IntSize(16, 16));
4078 if (NSImage *icon = webGetNSImage(image, NSMakeSize(16, 16)))
4079 CallFrameLoadDelegate(cache->didReceiveIconForFrameFunc, self, @selector(webView:didReceiveIcon:forFrame:), icon, webFrame);
4082 [self _didChangeValueForKey:_WebMainFrameIconKey];
4085 - (NSString *)_userVisibleBundleVersionFromFullVersion:(NSString *)fullVersion
4087 // If the version is 4 digits long or longer, then the first digit represents
4088 // the version of the OS. Our user agent string should not include this first digit,
4089 // so strip it off and report the rest as the version. <rdar://problem/4997547>
4090 NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
4091 if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4)
4092 return [fullVersion substringFromIndex:1];
4093 if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4)
4094 return [fullVersion substringFromIndex:1];
4098 static inline int callGestalt(OSType selector)
4101 Gestalt(selector, &value);
4105 // Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4.
4106 static NSString *createMacOSXVersionString()
4108 // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want.
4109 int major = callGestalt(gestaltSystemVersionMajor);
4112 int minor = callGestalt(gestaltSystemVersionMinor);
4113 int bugFix = callGestalt(gestaltSystemVersionBugFix);
4115 return [[NSString alloc] initWithFormat:@"%d_%d_%d", major, minor, bugFix];
4117 return [[NSString alloc] initWithFormat:@"%d_%d", major, minor];
4118 return [[NSString alloc] initWithFormat:@"%d", major];
4121 - (NSString *)_userAgentWithApplicationName:(NSString *)applicationName andWebKitVersion:(NSString *)version
4123 // Note: Do *not* move the initialization of osVersion into the declaration.
4124 // Garbage collection won't correctly mark the global variable in that case <rdar://problem/5733674>.
4125 static NSString *osVersion;
4127 osVersion = createMacOSXVersionString();
4128 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
4129 if ([applicationName length])
4130 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
4131 osVersion, language, version, applicationName];
4132 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko)",
4133 osVersion, language, version];
4136 // Get the appropriate user-agent string for a particular URL.
4137 - (WebCore::String)_userAgentForURL:(const WebCore::KURL&)url
4139 if (_private->useSiteSpecificSpoofing) {
4140 // No current site-specific spoofs.
4143 if (_private->userAgent->isNull()) {
4144 NSString *sourceVersion = [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
4145 sourceVersion = [self _userVisibleBundleVersionFromFullVersion:sourceVersion];
4146 *_private->userAgent = [self _userAgentWithApplicationName:_private->applicationNameForUserAgent andWebKitVersion:sourceVersion];
4149 return *_private->userAgent;
4152 - (void)_addObject:(id)object forIdentifier:(unsigned long)identifier
4154 ASSERT(!_private->identifierMap->contains(identifier));
4156 // If the identifier map is initially empty it means we're starting a load
4157 // of something. The semantic is that the web view should be around as long
4158 // as something is loading. Because of that we retain the web view.
4159 if (_private->identifierMap->isEmpty())
4162 _private->identifierMap->set(identifier, object);
4165 - (id)_objectForIdentifier:(unsigned long)identifier
4167 return _private->identifierMap->get(identifier).get();
4170 - (void)_removeObjectForIdentifier:(unsigned long)identifier
4172 HashMap<unsigned long, RetainPtr<id> >::iterator it = _private->identifierMap->find(identifier);
4174 // FIXME: This is currently needed because of a bug that causes didFail to be sent twice
4175 // sometimes, see <rdar://problem/5009627> for more information.
4176 if (it == _private->identifierMap->end())
4179 _private->identifierMap->remove(it);
4181 // If the identifier map is now empty it means we're no longer loading anything
4182 // and we should release the web view.
4183 if (_private->identifierMap->isEmpty())
4189 // We use these functions to call the delegates and block exceptions. These functions are
4190 // declared inside a WebView category to get direct access to the delegate data memebers,
4191 // preventing more ObjC message dispatch and compensating for the expense of the @try/@catch.
4193 @implementation WebView (WebCallDelegateFunctions)
4195 #if !(defined(__i386__) || defined(__x86_64__))
4196 typedef double (*ObjCMsgSendFPRet)(id, SEL, ...);
4197 static const ObjCMsgSendFPRet objc_msgSend_fpret = reinterpret_cast<ObjCMsgSendFPRet>(objc_msgSend);
4200 static inline id CallDelegate(WebView *self, id delegate, SEL selector)
4202 if (!delegate || ![delegate respondsToSelector:selector])
4204 if (!self->_private->catchesDelegateExceptions)
4205 return objc_msgSend(delegate, selector, self);
4207 return objc_msgSend(delegate, selector, self);
4208 } @catch(id exception) {
4209 ReportDiscardedDelegateException(selector, exception);
4214 static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object)
4216 if (!delegate || ![delegate respondsToSelector:selector])
4218 if (!self->_private->catchesDelegateExceptions)
4219 return objc_msgSend(delegate, selector, self, object);
4221 return objc_msgSend(delegate, selector, self, object);
4222 } @catch(id exception) {
4223 ReportDiscardedDelegateException(selector, exception);
4228 static inline id CallDelegate(WebView *self, id delegate, SEL selector, NSRect rect)
4230 if (!delegate || ![delegate respondsToSelector:selector])
4232 if (!self->_private->catchesDelegateExceptions)
4233 return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect);
4235 return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect);
4236 } @catch(id exception) {
4237 ReportDiscardedDelegateException(selector, exception);
4242 static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2)
4244 if (!delegate || ![delegate respondsToSelector:selector])
4246 if (!self->_private->catchesDelegateExceptions)
4247 return objc_msgSend(delegate, selector, self, object1, object2);
4249 return objc_msgSend(delegate, selector, self, object1, object2);
4250 } @catch(id exception) {
4251 ReportDiscardedDelegateException(selector, exception);
4256 static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, BOOL boolean)
4258 if (!delegate || ![delegate respondsToSelector:selector])
4260 if (!self->_private->catchesDelegateExceptions)
4261 return objc_msgSend(delegate, selector, self, object, boolean);
4263 return objc_msgSend(delegate, selector, self, object, boolean);
4264 } @catch(id exception) {
4265 ReportDiscardedDelegateException(selector, exception);
4270 static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2, id object3)
4272 if (!delegate || ![delegate respondsToSelector:selector])
4274 if (!self->_private->catchesDelegateExceptions)
4275 return objc_msgSend(delegate, selector, self, object1, object2, object3);
4277 return objc_msgSend(delegate, selector, self, object1, object2, object3);
4278 } @catch(id exception) {
4279 ReportDiscardedDelegateException(selector, exception);
4284 static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, NSUInteger integer)
4286 if (!delegate || ![delegate respondsToSelector:selector])
4288 if (!self->_private->catchesDelegateExceptions)
4289 return objc_msgSend(delegate, selector, self, object, integer);
4291 return objc_msgSend(delegate, selector, self, object, integer);
4292 } @catch(id exception) {
4293 ReportDiscardedDelegateException(selector, exception);
4298 static inline float CallDelegateReturningFloat(WebView *self, id delegate, SEL selector)
4300 if (!delegate || ![delegate respondsToSelector:selector])
4302 if (!self->_private->catchesDelegateExceptions)
4303 return static_cast<float>(objc_msgSend_fpret(delegate, selector, self));
4305 return static_cast<float>(objc_msgSend_fpret(delegate, selector, self));
4306 } @catch(id exception) {
4307 ReportDiscardedDelegateException(selector, exception);
4312 static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector)
4314 if (!delegate || ![delegate respondsToSelector:selector])
4316 if (!self->_private->catchesDelegateExceptions)
4317 return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self);
4319 return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self);
4320 } @catch(id exception) {
4321 ReportDiscardedDelegateException(selector, exception);
4326 static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object)
4328 if (!delegate || ![delegate respondsToSe