2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import <WebKit/WebViewInternal.h>
31 #import <WebKit/DOM.h>
32 #import <WebKit/DOMExtensions.h>
33 #import <WebKit/WebAssertions.h>
34 #import <WebKit/WebBackForwardList.h>
35 #import <WebKit/WebBaseNetscapePluginView.h>
36 #import <WebKit/WebFrameBridge.h>
37 #import <WebKit/WebPageBridge.h>
38 #import <WebKit/WebDashboardRegion.h>
39 #import <WebKit/WebDataProtocol.h>
40 #import <WebKit/WebDataSourcePrivate.h>
41 #import <WebKit/WebDefaultEditingDelegate.h>
42 #import <WebKit/WebDefaultFrameLoadDelegate.h>
43 #import <WebKit/WebDefaultPolicyDelegate.h>
44 #import <WebKit/WebDefaultResourceLoadDelegate.h>
45 #import <WebKit/WebDefaultScriptDebugDelegate.h>
46 #import <WebKit/WebDefaultUIDelegate.h>
47 #import <WebKit/WebDOMOperationsPrivate.h>
48 #import <WebKit/WebDocument.h>
49 #import <WebKit/WebDocumentInternal.h>
50 #import <WebKit/WebDynamicScrollBarsView.h>
51 #import <WebKit/WebDownload.h>
52 #import <WebKit/WebDownloadInternal.h>
53 #import <WebKit/WebEditingDelegate.h>
54 #import <WebKit/WebFormDelegatePrivate.h>
55 #import <WebKit/WebFrameInternal.h>
56 #import <WebKit/WebFrameViewInternal.h>
57 #import <WebKit/WebHistoryItemPrivate.h>
58 #import <WebKit/WebHTMLRepresentation.h>
59 #import <WebKit/WebHTMLViewInternal.h>
60 #import <WebKit/WebIconDatabase.h>
61 #import <WebKit/WebKitErrors.h>
62 #import <WebKit/WebKitLogging.h>
63 #import <WebKit/WebLocalizableStrings.h>
64 #import <WebKit/WebKitNSStringExtras.h>
65 #import <WebKit/WebKitStatisticsPrivate.h>
66 #import <WebKit/WebNSDataExtras.h>
67 #import <WebKit/WebNSDataExtrasPrivate.h>
68 #import <WebKit/WebNSDictionaryExtras.h>
69 #import <WebKit/WebNSObjectExtras.h>
70 #import <WebKit/WebNSPasteboardExtras.h>
71 #import <WebKit/WebNSPrintOperationExtras.h>
72 #import <WebKit/WebNSEventExtras.h>
73 #import <WebKit/WebNSURLExtras.h>
74 #import <WebKit/WebNSURLRequestExtras.h>
75 #import <WebKit/WebNSUserDefaultsExtras.h>
76 #import <WebKit/WebNSViewExtras.h>
77 #import <WebKit/WebPluginDatabase.h>
78 #import <WebKit/WebPolicyDelegate.h>
79 #import <WebKit/WebPreferencesPrivate.h>
80 #import <WebKit/WebResourceLoadDelegate.h>
81 #import <WebKit/WebScriptDebugDelegatePrivate.h>
82 #import <WebKit/WebTextView.h>
83 #import <WebKit/WebTextRepresentation.h>
84 #import <WebKit/WebTextRenderer.h>
85 #import <WebKit/WebUIDelegate.h>
86 #import <WebKit/WebUIDelegatePrivate.h>
87 #import <WebKit/WebInspector.h>
88 #import <WebKitSystemInterface.h>
90 #import <WebCore/WebCoreEncodings.h>
91 #import <WebCore/WebCoreSettings.h>
92 #import <WebCore/WebCoreView.h>
94 #import <CoreFoundation/CFSet.h>
96 #import <Foundation/NSURLConnection.h>
97 #import <objc/objc-runtime.h>
100 #define PROCESSOR "PPC"
102 #define PROCESSOR "Intel"
104 #error Unknown architecture
107 #define FOR_EACH_RESPONDER_SELECTOR(macro) \
109 macro(alignJustified) \
112 macro(capitalizeWord) \
113 macro(centerSelectionInVisibleArea) \
114 macro(changeAttributes) \
116 macro(changeDocumentBackgroundColor) \
118 macro(checkSpelling) \
124 macro(deleteBackward) \
125 macro(deleteBackwardByDecomposingPreviousCharacter) \
126 macro(deleteForward) \
127 macro(deleteToBeginningOfLine) \
128 macro(deleteToBeginningOfParagraph) \
129 macro(deleteToEndOfLine) \
130 macro(deleteToEndOfParagraph) \
131 macro(deleteWordBackward) \
132 macro(deleteWordForward) \
133 macro(ignoreSpelling) \
135 macro(insertBacktab) \
136 macro(insertNewline) \
137 macro(insertNewlineIgnoringFieldEditor) \
138 macro(insertParagraphSeparator) \
140 macro(insertTabIgnoringFieldEditor) \
141 macro(lowercaseWord) \
142 macro(moveBackward) \
143 macro(moveBackwardAndModifySelection) \
145 macro(moveDownAndModifySelection) \
147 macro(moveForwardAndModifySelection) \
149 macro(moveLeftAndModifySelection) \
151 macro(moveRightAndModifySelection) \
152 macro(moveToBeginningOfDocument) \
153 macro(moveToBeginningOfDocumentAndModifySelection) \
154 macro(moveToBeginningOfLine) \
155 macro(moveToBeginningOfLineAndModifySelection) \
156 macro(moveToBeginningOfParagraph) \
157 macro(moveToBeginningOfParagraphAndModifySelection) \
158 macro(moveToEndOfDocument) \
159 macro(moveToEndOfDocumentAndModifySelection) \
160 macro(moveToEndOfLine) \
161 macro(moveToEndOfLineAndModifySelection) \
162 macro(moveToEndOfParagraph) \
163 macro(moveToEndOfParagraphAndModifySelection) \
165 macro(moveUpAndModifySelection) \
166 macro(moveWordBackward) \
167 macro(moveWordBackwardAndModifySelection) \
168 macro(moveWordForward) \
169 macro(moveWordForwardAndModifySelection) \
170 macro(moveWordLeft) \
171 macro(moveWordLeftAndModifySelection) \
172 macro(moveWordRight) \
173 macro(moveWordRightAndModifySelection) \
177 macro(pasteAsPlainText) \
178 macro(pasteAsRichText) \
180 macro(performFindPanelAction) \
181 macro(scrollLineDown) \
182 macro(scrollLineUp) \
183 macro(scrollPageDown) \
184 macro(scrollPageUp) \
185 macro(scrollToBeginningOfDocument) \
186 macro(scrollToEndOfDocument) \
189 macro(selectParagraph) \
191 macro(showGuessPanel) \
192 macro(startSpeaking) \
193 macro(stopSpeaking) \
198 macro(uppercaseWord) \
200 macro(yankAndSelect) \
202 @interface NSSpellChecker (AppKitSecretsIKnow)
203 - (void)_preflightChosenSpellServer;
206 @interface NSView (AppKitSecretsIKnow)
207 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types;
208 - (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta;
209 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo;
212 @interface WebViewPrivate : NSObject
215 WebPageBridge *_pageBridge;
218 id UIDelegateForwarder;
219 id resourceProgressDelegate;
220 id resourceProgressDelegateForwarder;
223 id policyDelegateForwarder;
224 id frameLoadDelegate;
225 id frameLoadDelegateForwarder;
226 id <WebFormDelegate> formDelegate;
228 id editingDelegateForwarder;
229 id scriptDebugDelegate;
230 id scriptDebugDelegateForwarder;
232 WebBackForwardList *backForwardList;
233 BOOL useBackForwardList;
235 float textSizeMultiplier;
237 NSString *applicationNameForUserAgent;
239 BOOL userAgentOverridden;
241 BOOL defersCallbacks;
243 WebPreferences *preferences;
244 WebCoreSettings *settings;
246 BOOL lastElementWasNonNil;
248 NSWindow *hostWindow;
250 int programmaticFocusCount;
252 WebResourceDelegateImplementationCache resourceLoadDelegateImplementations;
254 long long totalPageAndResourceBytesToLoad;
255 long long totalBytesReceived;
256 double progressValue;
257 double lastNotifiedProgressValue;
258 double lastNotifiedProgressTime;
259 double progressNotificationInterval;
260 double progressNotificationTimeInterval;
261 BOOL finalProgressChangedSent;
262 WebFrame *orginatingProgressFrame;
264 int numProgressTrackedFrames;
265 NSMutableDictionary *progressItems;
267 void *observationInfo;
269 BOOL drawsBackground;
273 NSString *mediaStyle;
275 NSView <WebDocumentDragging> *draggingDocumentView;
276 unsigned int dragDestinationActionMask;
277 WebFrameBridge *dragCaretBridge;
279 BOOL hasSpellCheckerDocumentTag;
280 WebNSInt spellCheckerDocumentTag;
282 BOOL continuousSpellCheckingEnabled;
283 BOOL smartInsertDeleteEnabled;
285 BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
286 BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
287 BOOL dashboardBehaviorAlwaysAcceptsFirstMouse;
288 BOOL dashboardBehaviorAllowWheelScrolling;
290 BOOL shouldUseFontSmoothing;
291 BOOL selectWordBeforeMenuEvent;
295 @interface WebView (WebFileInternal)
296 - (WebFrame *)_selectedOrMainFrame;
297 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame;
299 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point;
300 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point;
301 - (WebFrame *)_focusedFrame;
302 + (void)_preflightSpellChecker;
303 - (BOOL)_continuousCheckingAllowed;
304 - (NSResponder *)_responderForResponderOperations;
305 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor;
308 NSString *WebElementDOMNodeKey = @"WebElementDOMNode";
309 NSString *WebElementFrameKey = @"WebElementFrame";
310 NSString *WebElementImageKey = @"WebElementImage";
311 NSString *WebElementImageAltStringKey = @"WebElementImageAltString";
312 NSString *WebElementImageRectKey = @"WebElementImageRect";
313 NSString *WebElementImageURLKey = @"WebElementImageURL";
314 NSString *WebElementIsSelectedKey = @"WebElementIsSelected";
315 NSString *WebElementLinkURLKey = @"WebElementLinkURL";
316 NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame";
317 NSString *WebElementLinkLabelKey = @"WebElementLinkLabel";
318 NSString *WebElementLinkTitleKey = @"WebElementLinkTitle";
320 NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification";
321 NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification";
322 NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification";
324 NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification";
325 NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification";
326 NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification";
327 NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification";
328 NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification";
330 enum { WebViewVersion = 2 };
332 #define timedLayoutSize 4096
334 static NSMutableSet *schemesWithRepresentationsSet;
336 NSString *_WebCanGoBackKey = @"canGoBack";
337 NSString *_WebCanGoForwardKey = @"canGoForward";
338 NSString *_WebEstimatedProgressKey = @"estimatedProgress";
339 NSString *_WebIsLoadingKey = @"isLoading";
340 NSString *_WebMainFrameIconKey = @"mainFrameIcon";
341 NSString *_WebMainFrameTitleKey = @"mainFrameTitle";
342 NSString *_WebMainFrameURLKey = @"mainFrameURL";
344 @interface WebProgressItem : NSObject
347 long long bytesReceived;
348 long long estimatedLength;
352 @implementation WebProgressItem
355 static BOOL shouldUseFontSmoothing = YES;
357 @implementation WebViewPrivate
365 backForwardList = [[WebBackForwardList alloc] init];
366 textSizeMultiplier = 1;
367 progressNotificationInterval = 0.02;
368 progressNotificationTimeInterval = 0.1;
369 settings = [[WebCoreSettings alloc] init];
370 dashboardBehaviorAllowWheelScrolling = YES;
377 ASSERT(!_pageBridge);
378 ASSERT(draggingDocumentView == nil);
379 ASSERT(dragCaretBridge == nil);
381 [backForwardList release];
382 [applicationNameForUserAgent release];
385 [preferences release];
387 [hostWindow release];
389 [policyDelegateForwarder release];
390 [resourceProgressDelegateForwarder release];
391 [UIDelegateForwarder release];
392 [frameLoadDelegateForwarder release];
393 [editingDelegateForwarder release];
394 [scriptDebugDelegateForwarder release];
396 [progressItems release];
398 [mediaStyle release];
405 @implementation WebView (AllWebViews)
407 static CFSetCallBacks NonRetainingSetCallbacks = {
416 static CFMutableSetRef allWebViewsSet;
418 + (void)_makeAllWebViewsPerformSelector:(SEL)selector
423 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector];
426 - (void)_removeFromAllWebViewsSet
429 CFSetRemoveValue(allWebViewsSet, self);
432 - (void)_addToAllWebViewsSet
435 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks);
437 CFSetSetValue(allWebViewsSet, self);
442 @implementation WebView (WebPrivate)
444 #ifdef DEBUG_WIDGET_DRAWING
445 static bool debugWidget = true;
446 - (void)drawRect:(NSRect)rect
448 [[NSColor blueColor] set];
451 NSRect htmlViewRect = [[[[self mainFrame] frameView] documentView] frame];
454 while (debugWidget) {
459 NSLog (@"%s: rect: (%0.f,%0.f) %0.f %0.f, htmlViewRect: (%0.f,%0.f) %0.f %0.f\n",
460 __PRETTY_FUNCTION__, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height,
461 htmlViewRect.origin.x, htmlViewRect.origin.y, htmlViewRect.size.width, htmlViewRect.size.height
464 [super drawRect:rect];
468 + (NSArray *)_supportedMIMETypes
470 // Load the plug-in DB allowing plug-ins to install types.
471 [WebPluginDatabase installedPlugins];
472 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys];
475 + (NSArray *)_supportedFileExtensions
477 NSMutableSet *extensions = [[NSMutableSet alloc] init];
478 NSArray *MIMETypes = [self _supportedMIMETypes];
479 NSEnumerator *enumerator = [MIMETypes objectEnumerator];
481 while ((MIMEType = [enumerator nextObject]) != nil) {
482 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType);
483 if (extensionsForType) {
484 [extensions addObjectsFromArray:extensionsForType];
487 NSArray *uniqueExtensions = [extensions allObjects];
488 [extensions release];
489 return uniqueExtensions;
492 + (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType;
494 MIMEType = [MIMEType lowercaseString];
495 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
496 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType];
498 if (!viewClass || !repClass) {
499 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed.
500 // Load the plug-in DB allowing plug-ins to install types.
501 [WebPluginDatabase installedPlugins];
503 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types.
504 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
505 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType];
508 if (viewClass && repClass) {
509 // Special-case WebTextView for text types that shouldn't be shown.
510 if (viewClass == [WebTextView class] &&
511 repClass == [WebTextRepresentation class] &&
512 [[WebTextView unsupportedTextMIMETypes] containsObject:MIMEType]) {
525 + (void)_setAlwaysUseATSU:(BOOL)f
527 [WebTextRenderer setAlwaysUseATSU:f];
530 + (BOOL)canShowFile:(NSString *)path
532 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]];
535 + (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type
537 return WKGetPreferredExtensionForMIMEType(type);
542 [self _removeFromAllWebViewsSet];
543 [self setGroupName:nil];
545 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint.
546 [self removeDragCaret];
548 [[self mainFrame] _detachFromParent];
549 [_private->_pageBridge release];
550 _private->_pageBridge = nil;
552 // Clear the page cache so we call destroy on all the plug-ins in the page cache to break any retain cycles.
553 // See comment in [WebHistoryItem _releaseAllPendingPageCaches] for more information.
554 [_private->backForwardList _clearPageCache];
556 if (_private->hasSpellCheckerDocumentTag) {
557 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag];
558 _private->hasSpellCheckerDocumentTag = NO;
562 - (void)_finishedLoadingResourceFromDataSource:(WebDataSource *)dataSource
564 WebFrame *frame = [dataSource webFrame];
566 ASSERT(dataSource != nil);
568 // This resource has completed, so check if the load is complete for all frames.
570 [frame _checkLoadComplete];
573 - (void)_mainReceivedBytesSoFar:(unsigned)bytesSoFar fromDataSource:(WebDataSource *)dataSource complete: (BOOL)isComplete
575 WebFrame *frame = [dataSource webFrame];
577 ASSERT(dataSource != nil);
579 // The frame may be nil if a previously cancelled load is still making progress callbacks.
583 // This resource has completed, so check if the load is complete for this frame and its ancestors
585 // If the load is complete, mark the primary load as done. The primary load is the load
586 // of the main document. Other resources may still be arriving.
587 [dataSource _setPrimaryLoadComplete:YES];
588 [frame _checkLoadComplete];
592 - (void)_receivedError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
594 WebFrame *frame = [dataSource webFrame];
596 [frame _checkLoadComplete];
599 - (void)_mainReceivedError:(NSError *)error fromDataSource:(WebDataSource *)dataSource complete:(BOOL)isComplete
602 ASSERT([dataSource webFrame]);
604 [dataSource _setMainDocumentError: error];
607 [dataSource _setPrimaryLoadComplete:YES];
608 [[dataSource webFrame] _checkLoadComplete];
612 + (NSString *)_MIMETypeForFile:(NSString *)path
614 NSString *extension = [path pathExtension];
615 NSString *MIMEType = nil;
617 // Get the MIME type from the extension.
618 if ([extension length] != 0) {
619 MIMEType = WKGetMIMETypeForExtension(extension);
622 // If we can't get a known MIME type from the extension, sniff.
623 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) {
624 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
625 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH];
627 if ([data length] != 0) {
628 MIMEType = [data _webkit_guessedMIMEType];
630 if ([MIMEType length] == 0) {
631 MIMEType = @"application/octet-stream";
638 - (void)_downloadURL:(NSURL *)URL
640 [self _downloadURL:URL toDirectory:nil];
643 - (void)_downloadURL:(NSURL *)URL toDirectory:(NSString *)directory
647 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
648 [WebDownload _downloadWithRequest:request
649 delegate:_private->downloadDelegate
650 directory:[directory isAbsolutePath] ? directory : nil];
654 - (BOOL)defersCallbacks
656 return _private->defersCallbacks;
659 - (void)setDefersCallbacks:(BOOL)defers
661 if (defers == _private->defersCallbacks) {
665 _private->defersCallbacks = defers;
666 [[self mainFrame] _defersCallbacksChanged];
669 - (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request
671 id wd = [self UIDelegate];
672 WebView *newWindowWebView = nil;
673 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
674 newWindowWebView = [wd webView:self createWebViewWithRequest:request];
676 newWindowWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:self createWebViewWithRequest: request];
679 [[newWindowWebView _UIDelegateForwarder] webViewShow: newWindowWebView];
681 return newWindowWebView;
684 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items
686 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate]
687 webView:self contextMenuItemsForElement:element defaultMenuItems:items];
688 NSArray *menuItems = defaultMenuItems;
692 if (_private->UIDelegate) {
693 id cd = _private->UIDelegate;
695 if ([cd respondsToSelector:@selector(webView:contextMenuItemsForElement:defaultMenuItems:)])
696 menuItems = [cd webView:self contextMenuItemsForElement:element defaultMenuItems:defaultMenuItems];
699 if (menuItems && [menuItems count] > 0) {
700 menu = [[[NSMenu alloc] init] autorelease];
702 for (i=0; i<[menuItems count]; i++) {
703 [menu addItem:[menuItems objectAtIndex:i]];
708 BOOL enableInspectElement = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitDeveloperExtras"];
709 enableInspectElement |= [[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeDebugMenu"];
710 // FIXME: remove the following check later, once everyone switches to the new generic default name
711 enableInspectElement |= [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitEnableInspectElementContextMenuItem"];
713 BOOL enableInspectElement = YES; // always enable in debug builds
716 // optionally add the Inspect Element menu item it if preference is set or in debug builds
717 // and only showing the menu item if we are working with a WebHTMLView
718 WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
719 if (enableInspectElement && [[[webFrame frameView] documentView] isKindOfClass:[WebHTMLView class]]) {
721 menu = [[[NSMenu alloc] init] autorelease];
722 else if ([menu numberOfItems])
723 [menu addItem:[NSMenuItem separatorItem]];
724 NSMenuItem *menuItem = [[[NSMenuItem alloc] init] autorelease];
725 [menuItem setAction:@selector(_inspectElement:)];
726 [menuItem setTitle:UI_STRING("Inspect Element", "Inspect Element context menu item")];
727 [menuItem setRepresentedObject:element];
728 [menu addItem:menuItem];
734 - (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(WebNSUInt)modifierFlags
736 // When the mouse isn't over this view at all, we'll get called with a dictionary of nil over
737 // and over again. So it's a good idea to catch that here and not send multiple calls to the delegate
740 if (dictionary && _private->lastElementWasNonNil) {
741 [[self _UIDelegateForwarder] webView:self mouseDidMoveOverElement:dictionary modifierFlags:modifierFlags];
743 _private->lastElementWasNonNil = dictionary != nil;
746 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
748 // We never go back/forward on a per-frame basis, so the target must be the main frame
749 //ASSERT([item target] == nil || [self _findFrameNamed:[item target]] == [self mainFrame]);
751 // abort any current load if we're going back/forward
752 [[self mainFrame] stopLoading];
753 [[self mainFrame] _goToItem:item withLoadType:type];
756 // Not used now, but could be if we ever store frames in bookmarks or history
757 - (void)_loadItem:(WebHistoryItem *)item
759 WebHistoryItem *newItem = [item copy]; // Makes a deep copy, happily
760 [[self backForwardList] addItem:newItem];
761 [self _goToItem:newItem withLoadType:WebFrameLoadTypeIndexedBackForward];
764 - (void)_loadBackForwardListFromOtherView:(WebView *)otherView
766 // It turns out the right combination of behavior is done with the back/forward load
767 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items
768 // in the back forward list, and go to the current one.
770 WebBackForwardList *bfList = [self backForwardList];
771 ASSERT(![bfList currentItem]); // destination list should be empty
773 WebBackForwardList *otherBFList = [otherView backForwardList];
774 if (![otherBFList currentItem]) {
775 return; // empty back forward list, bail
778 WebHistoryItem *newItemToGoTo = nil;
779 int lastItemIndex = [otherBFList forwardListCount];
781 for (i = -[otherBFList backListCount]; i <= lastItemIndex; i++) {
783 // If this item is showing , save away its current scroll and form state,
784 // since that might have changed since loading and it is normally not saved
785 // until we leave that page.
786 [[otherView mainFrame] _saveDocumentAndScrollState];
788 WebHistoryItem *newItem = [[otherBFList itemAtIndex:i] copy];
789 [bfList addItem:newItem];
791 newItemToGoTo = newItem;
795 [self _goToItem:newItemToGoTo withLoadType:WebFrameLoadTypeIndexedBackForward];
798 - (void)_setFormDelegate: (id<WebFormDelegate>)delegate
800 _private->formDelegate = delegate;
803 - (id<WebFormDelegate>)_formDelegate
805 if (!_private->formDelegate) {
806 // create lazily, to give the client a chance to set one before we bother to alloc the shared one
807 _private->formDelegate = [WebFormDelegate _sharedWebFormDelegate];
809 return _private->formDelegate;
812 - (WebCoreSettings *)_settings
814 return _private->settings;
817 - (void)_updateWebCoreSettingsFromPreferences:(WebPreferences *)preferences
819 [_private->settings setCursiveFontFamily:[preferences cursiveFontFamily]];
820 [_private->settings setDefaultFixedFontSize:[preferences defaultFixedFontSize]];
821 [_private->settings setDefaultFontSize:[preferences defaultFontSize]];
822 [_private->settings setDefaultTextEncoding:[preferences defaultTextEncodingName]];
823 [_private->settings setFantasyFontFamily:[preferences fantasyFontFamily]];
824 [_private->settings setFixedFontFamily:[preferences fixedFontFamily]];
825 [_private->settings setJavaEnabled:[preferences isJavaEnabled]];
826 [_private->settings setJavaScriptEnabled:[preferences isJavaScriptEnabled]];
827 [_private->settings setJavaScriptCanOpenWindowsAutomatically:[preferences javaScriptCanOpenWindowsAutomatically]];
828 [_private->settings setMinimumFontSize:[preferences minimumFontSize]];
829 [_private->settings setMinimumLogicalFontSize:[preferences minimumLogicalFontSize]];
830 [_private->settings setPluginsEnabled:[preferences arePlugInsEnabled]];
831 [_private->settings setSansSerifFontFamily:[preferences sansSerifFontFamily]];
832 [_private->settings setSerifFontFamily:[preferences serifFontFamily]];
833 [_private->settings setStandardFontFamily:[preferences standardFontFamily]];
834 [_private->settings setWillLoadImagesAutomatically:[preferences loadsImagesAutomatically]];
836 if ([preferences userStyleSheetEnabled]) {
837 [_private->settings setUserStyleSheetLocation:[[preferences userStyleSheetLocation] _web_originalDataAsString]];
839 [_private->settings setUserStyleSheetLocation:@""];
841 [_private->settings setShouldPrintBackgrounds:[preferences shouldPrintBackgrounds]];
842 [_private->settings setTextAreasAreResizable:[preferences textAreasAreResizable]];
845 - (void)_preferencesChangedNotification: (NSNotification *)notification
847 WebPreferences *preferences = (WebPreferences *)[notification object];
849 ASSERT(preferences == [self preferences]);
850 if (!_private->userAgentOverridden) {
851 [_private->userAgent release];
852 _private->userAgent = nil;
854 [self _updateWebCoreSettingsFromPreferences: preferences];
857 - _frameLoadDelegateForwarder
859 if (!_private->frameLoadDelegateForwarder)
860 _private->frameLoadDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self frameLoadDelegate] defaultTarget: [WebDefaultFrameLoadDelegate sharedFrameLoadDelegate] templateClass: [WebDefaultFrameLoadDelegate class]];
861 return _private->frameLoadDelegateForwarder;
864 - _resourceLoadDelegateForwarder
866 if (!_private->resourceProgressDelegateForwarder)
867 _private->resourceProgressDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self resourceLoadDelegate] defaultTarget: [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] templateClass: [WebDefaultResourceLoadDelegate class]];
868 return _private->resourceProgressDelegateForwarder;
871 - (void)_cacheResourceLoadDelegateImplementations
873 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
874 id delegate = [self resourceLoadDelegate];
876 cache->delegateImplementsDidCancelAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didCancelAuthenticationChallenge:fromDataSource:)];
877 cache->delegateImplementsDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)];
878 cache->delegateImplementsDidFinishLoadingFromDataSource = [delegate respondsToSelector:@selector(webView:resource:didFinishLoadingFromDataSource:)];
879 cache->delegateImplementsDidReceiveContentLength = [delegate respondsToSelector:@selector(webView:resource:didReceiveContentLength:fromDataSource:)];
880 cache->delegateImplementsDidReceiveResponse = [delegate respondsToSelector:@selector(webView:resource:didReceiveResponse:fromDataSource:)];
881 cache->delegateImplementsWillSendRequest = [delegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)];
882 cache->delegateImplementsIdentifierForRequest = [delegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)];
885 - (WebResourceDelegateImplementationCache)_resourceLoadDelegateImplementations
887 return _private->resourceLoadDelegateImplementations;
890 - _policyDelegateForwarder
892 if (!_private->policyDelegateForwarder)
893 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self policyDelegate] defaultTarget: [WebDefaultPolicyDelegate sharedPolicyDelegate] templateClass: [WebDefaultPolicyDelegate class]];
894 return _private->policyDelegateForwarder;
897 - _UIDelegateForwarder
899 if (!_private->UIDelegateForwarder)
900 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self UIDelegate] defaultTarget: [WebDefaultUIDelegate sharedUIDelegate] templateClass: [WebDefaultUIDelegate class]];
901 return _private->UIDelegateForwarder;
904 - _editingDelegateForwarder
906 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in.
907 // Not sure if that is a bug or not.
910 if (!_private->editingDelegateForwarder)
911 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self editingDelegate] defaultTarget: [WebDefaultEditingDelegate sharedEditingDelegate] templateClass: [WebDefaultEditingDelegate class]];
912 return _private->editingDelegateForwarder;
915 - _scriptDebugDelegateForwarder
917 if (!_private->scriptDebugDelegateForwarder)
918 _private->scriptDebugDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget: [self scriptDebugDelegate] defaultTarget: [WebDefaultScriptDebugDelegate sharedScriptDebugDelegate] templateClass: [WebDefaultScriptDebugDelegate class]];
919 return _private->scriptDebugDelegateForwarder;
924 [[self _UIDelegateForwarder] webViewClose:self];
927 + (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType;
929 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
930 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType];
933 + (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme;
935 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme];
936 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType];
938 // This is used to make _representationExistsForURLScheme faster.
939 // Without this set, we'd have to create the MIME type each time.
940 if (schemesWithRepresentationsSet == nil) {
941 schemesWithRepresentationsSet = [[NSMutableSet alloc] init];
943 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]];
946 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
948 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]];
951 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
953 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]];
956 + (BOOL)_canHandleRequest:(NSURLRequest *)request
958 if ([NSURLConnection canHandleRequest:request]) {
962 // We're always willing to load alternate content for unreachable URLs
963 if ([request _webDataRequestUnreachableURL]) {
967 return [self _representationExistsForURLScheme:[[request URL] scheme]];
970 + (NSString *)_decodeData:(NSData *)data
972 return [WebCoreEncodings decodeData:data];
975 - (void)_pushPerformingProgrammaticFocus
977 _private->programmaticFocusCount++;
980 - (void)_popPerformingProgrammaticFocus
982 _private->programmaticFocusCount--;
985 - (BOOL)_isPerformingProgrammaticFocus
987 return _private->programmaticFocusCount != 0;
990 #define UnknownTotalBytes -1
991 #define WebProgressItemDefaultEstimatedLength 1024*16
993 - (void)_didChangeValueForKey: (NSString *)key
995 LOG (Bindings, "calling didChangeValueForKey: %@", key);
996 [self didChangeValueForKey: key];
999 - (void)_willChangeValueForKey: (NSString *)key
1001 LOG (Bindings, "calling willChangeValueForKey: %@", key);
1002 [self willChangeValueForKey: key];
1005 // Always start progress at INITIAL_PROGRESS_VALUE so it appears progress indicators
1006 // will immediately show some progress. This helps provide feedback as soon as a load
1008 #define INITIAL_PROGRESS_VALUE 0.1
1010 - (void)_resetProgress
1012 [_private->progressItems release];
1013 _private->progressItems = nil;
1014 _private->totalPageAndResourceBytesToLoad = 0;
1015 _private->totalBytesReceived = 0;
1016 _private->progressValue = 0;
1017 _private->lastNotifiedProgressValue = 0;
1018 _private->lastNotifiedProgressTime = 0;
1019 _private->finalProgressChangedSent = NO;
1020 _private->numProgressTrackedFrames = 0;
1021 [_private->orginatingProgressFrame release];
1022 _private->orginatingProgressFrame = nil;
1024 - (void)_progressStarted:(WebFrame *)frame
1026 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1027 [self _willChangeValueForKey: @"estimatedProgress"];
1028 if (_private->numProgressTrackedFrames == 0 || _private->orginatingProgressFrame == frame){
1029 [self _resetProgress];
1030 _private->progressValue = INITIAL_PROGRESS_VALUE;
1031 _private->orginatingProgressFrame = [frame retain];
1032 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressStartedNotification object:self];
1034 _private->numProgressTrackedFrames++;
1035 [self _didChangeValueForKey: @"estimatedProgress"];
1038 - (void)_finalProgressComplete
1042 // Before resetting progress value be sure to send client a least one notification
1043 // with final progress value.
1044 if (!_private->finalProgressChangedSent) {
1045 _private->progressValue = 1;
1046 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1049 [self _resetProgress];
1051 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressFinishedNotification object:self];
1054 - (void)_progressCompleted:(WebFrame *)frame
1056 LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1058 if (_private->numProgressTrackedFrames <= 0)
1061 [self _willChangeValueForKey: @"estimatedProgress"];
1063 _private->numProgressTrackedFrames--;
1064 if (_private->numProgressTrackedFrames == 0 ||
1065 (frame == _private->orginatingProgressFrame && _private->numProgressTrackedFrames != 0)){
1066 [self _finalProgressComplete];
1068 [self _didChangeValueForKey: @"estimatedProgress"];
1071 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate response:(NSURLResponse *)response;
1073 if (!connectionDelegate)
1076 LOG (Progress, "_private->numProgressTrackedFrames %d, _private->orginatingProgressFrame %p", _private->numProgressTrackedFrames, _private->orginatingProgressFrame);
1078 if (_private->numProgressTrackedFrames <= 0)
1081 WebProgressItem *item = [[WebProgressItem alloc] init];
1086 long long length = [response expectedContentLength];
1088 length = WebProgressItemDefaultEstimatedLength;
1090 item->estimatedLength = length;
1091 _private->totalPageAndResourceBytesToLoad += length;
1093 if (!_private->progressItems)
1094 _private->progressItems = [[NSMutableDictionary alloc] init];
1096 [_private->progressItems _webkit_setObject:item forUncopiedKey:connectionDelegate];
1100 - (void)_incrementProgressForConnectionDelegate:(id)connectionDelegate data:(NSData *)data
1102 if (!connectionDelegate)
1105 WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
1110 [self _willChangeValueForKey: @"estimatedProgress"];
1112 unsigned bytesReceived = [data length];
1113 double increment = 0, percentOfRemainingBytes;
1114 long long remainingBytes, estimatedBytesForPendingRequests;
1116 item->bytesReceived += bytesReceived;
1117 if (item->bytesReceived > item->estimatedLength){
1118 _private->totalPageAndResourceBytesToLoad += ((item->bytesReceived*2) - item->estimatedLength);
1119 item->estimatedLength = item->bytesReceived*2;
1122 int numPendingOrLoadingRequests = [[self mainFrame] _numPendingOrLoadingRequests:YES];
1123 estimatedBytesForPendingRequests = WebProgressItemDefaultEstimatedLength * numPendingOrLoadingRequests;
1124 remainingBytes = ((_private->totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - _private->totalBytesReceived);
1125 percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes;
1126 increment = (1.0 - _private->progressValue) * percentOfRemainingBytes;
1128 _private->totalBytesReceived += bytesReceived;
1130 _private->progressValue += increment;
1132 if (_private->progressValue < 0.0)
1133 _private->progressValue = 0.0;
1135 if (_private->progressValue > 1.0)
1136 _private->progressValue = 1.0;
1138 double now = CFAbsoluteTimeGetCurrent();
1139 double notifiedProgressTimeDelta = CFAbsoluteTimeGetCurrent() - _private->lastNotifiedProgressTime;
1140 _private->lastNotifiedProgressTime = now;
1142 LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
1143 double notificationProgressDelta = _private->progressValue - _private->lastNotifiedProgressValue;
1144 if ((notificationProgressDelta >= _private->progressNotificationInterval ||
1145 notifiedProgressTimeDelta >= _private->progressNotificationTimeInterval) &&
1146 _private->numProgressTrackedFrames > 0) {
1147 if (!_private->finalProgressChangedSent) {
1148 if (_private->progressValue == 1)
1149 _private->finalProgressChangedSent = YES;
1150 [[NSNotificationCenter defaultCenter] postNotificationName:WebViewProgressEstimateChangedNotification object:self];
1151 _private->lastNotifiedProgressValue = _private->progressValue;
1155 [self _didChangeValueForKey: @"estimatedProgress"];
1158 - (void)_completeProgressForConnectionDelegate:(id)connectionDelegate
1160 WebProgressItem *item = [_private->progressItems objectForKey:connectionDelegate];
1165 // Adjust the total expected bytes to account for any overage/underage.
1166 long long delta = item->bytesReceived - item->estimatedLength;
1167 _private->totalPageAndResourceBytesToLoad += delta;
1168 item->estimatedLength = item->bytesReceived;
1171 // Required to prevent automatic observer notifications.
1172 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
1176 - (NSArray *)_declaredKeys {
1177 static NSArray *declaredKeys = nil;
1179 if (!declaredKeys) {
1180 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, nil];
1183 return declaredKeys;
1186 - (void)setObservationInfo:(void *)info
1188 _private->observationInfo = info;
1191 - (void *)observationInfo
1193 return _private->observationInfo;
1196 - (void)_willChangeBackForwardKeys
1198 [self _willChangeValueForKey: _WebCanGoBackKey];
1199 [self _willChangeValueForKey: _WebCanGoForwardKey];
1202 - (void)_didChangeBackForwardKeys
1204 [self _didChangeValueForKey: _WebCanGoBackKey];
1205 [self _didChangeValueForKey: _WebCanGoForwardKey];
1208 - (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame
1210 [self _willChangeBackForwardKeys];
1211 if (frame == [self mainFrame]){
1212 // Force an observer update by sending a will/did.
1213 [self _willChangeValueForKey: _WebIsLoadingKey];
1214 [self _didChangeValueForKey: _WebIsLoadingKey];
1216 [self _willChangeValueForKey: _WebMainFrameURLKey];
1218 [NSApp setWindowsNeedUpdate:YES];
1221 - (void)_didCommitLoadForFrame:(WebFrame *)frame
1223 if (frame == [self mainFrame]){
1224 [self _didChangeValueForKey: _WebMainFrameURLKey];
1226 [NSApp setWindowsNeedUpdate:YES];
1229 - (void)_didFinishLoadForFrame:(WebFrame *)frame
1231 [self _didChangeBackForwardKeys];
1232 if (frame == [self mainFrame]){
1233 // Force an observer update by sending a will/did.
1234 [self _willChangeValueForKey: _WebIsLoadingKey];
1235 [self _didChangeValueForKey: _WebIsLoadingKey];
1237 [NSApp setWindowsNeedUpdate:YES];
1240 - (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1242 [self _didChangeBackForwardKeys];
1243 if (frame == [self mainFrame]){
1244 // Force an observer update by sending a will/did.
1245 [self _willChangeValueForKey: _WebIsLoadingKey];
1246 [self _didChangeValueForKey: _WebIsLoadingKey];
1248 [NSApp setWindowsNeedUpdate:YES];
1251 - (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
1253 [self _didChangeBackForwardKeys];
1254 if (frame == [self mainFrame]){
1255 // Force an observer update by sending a will/did.
1256 [self _willChangeValueForKey: _WebIsLoadingKey];
1257 [self _didChangeValueForKey: _WebIsLoadingKey];
1259 [self _didChangeValueForKey: _WebMainFrameURLKey];
1261 [NSApp setWindowsNeedUpdate:YES];
1264 - (void)_reloadForPluginChanges
1266 [[self mainFrame] _reloadForPluginChanges];
1269 - (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL
1271 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1272 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]];
1273 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
1275 return cachedResponse;
1278 - (void)_writeImageElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1280 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
1281 [pasteboard _web_writeImage:nil
1282 element:[element objectForKey:WebElementDOMNodeKey]
1283 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey]
1284 title:[element objectForKey:WebElementImageAltStringKey]
1285 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive]
1289 - (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
1291 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey]
1292 andTitle:[element objectForKey:WebElementLinkLabelKey]
1296 - (void)_setInitiatedDrag:(BOOL)initiatedDrag
1298 _private->initiatedDrag = initiatedDrag;
1301 #define DASHBOARD_CONTROL_LABEL @"control"
1303 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views
1305 // Add scroller regions for NSScroller and KWQScrollBar
1306 int i, count = [views count];
1308 for (i = 0; i < count; i++) {
1309 NSView *aView = [views objectAtIndex:i];
1311 if ([aView isKindOfClass:[NSScroller class]] ||
1312 [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) {
1313 NSRect bounds = [aView bounds];
1314 NSRect adjustedBounds;
1315 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView];
1316 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y;
1318 // AppKit has horrible hack of placing absent scrollers at -100,-100
1319 if (adjustedBounds.origin.y == -100)
1321 adjustedBounds.size = bounds.size;
1322 NSRect clip = [aView visibleRect];
1323 NSRect adjustedClip;
1324 adjustedClip.origin = [self convertPoint:clip.origin fromView:aView];
1325 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y;
1326 adjustedClip.size = clip.size;
1327 WebDashboardRegion *aRegion =
1328 [[[WebDashboardRegion alloc] initWithRect:adjustedBounds
1329 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease];
1330 NSMutableArray *scrollerRegions;
1331 scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL];
1332 if (!scrollerRegions) {
1333 scrollerRegions = [NSMutableArray array];
1334 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL];
1336 [scrollerRegions addObject:aRegion];
1338 [self _addScrollerDashboardRegions:regions from:[aView subviews]];
1342 - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions
1344 [self _addScrollerDashboardRegions:regions from:[self subviews]];
1347 - (NSDictionary *)_dashboardRegions
1349 // Only return regions from main frame.
1350 NSMutableDictionary *regions = [[[self mainFrame] _bridge] dashboardRegions];
1351 [self _addScrollerDashboardRegions:regions];
1355 - (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag;
1358 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1359 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag;
1362 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1363 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag;
1366 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1367 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag;
1370 case WebDashboardBehaviorAllowWheelScrolling: {
1371 _private->dashboardBehaviorAllowWheelScrolling = flag;
1377 - (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior
1380 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: {
1381 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows;
1383 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: {
1384 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns;
1386 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: {
1387 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse;
1389 case WebDashboardBehaviorAllowWheelScrolling: {
1390 return _private->dashboardBehaviorAllowWheelScrolling;
1396 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource
1398 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:self resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:dataSource];
1401 + (void)_setShouldUseFontSmoothing:(BOOL)f
1403 shouldUseFontSmoothing = f;
1406 + (BOOL)_shouldUseFontSmoothing
1408 return shouldUseFontSmoothing;
1411 + (NSString *)_minimumRequiredSafariBuildNumber
1419 @implementation _WebSafeForwarder
1421 - initWithTarget: t defaultTarget: dt templateClass: (Class)aClass
1423 self = [super init];
1427 target = t; // Non retained.
1429 templateClass = aClass;
1434 // Used to send messages to delegates that implement informal protocols.
1435 + safeForwarderWithTarget: t defaultTarget: dt templateClass: (Class)aClass;
1437 return [[[_WebSafeForwarder alloc] initWithTarget: t defaultTarget: dt templateClass: aClass] autorelease];
1441 NSMutableDictionary *countInvocations;
1444 - (void)forwardInvocation:(NSInvocation *)anInvocation
1447 if (!countInvocations){
1448 countInvocations = [[NSMutableDictionary alloc] init];
1450 NSNumber *count = [countInvocations objectForKey: NSStringFromSelector([anInvocation selector])];
1452 count = [NSNumber numberWithInt: 1];
1454 count = [NSNumber numberWithInt: [count intValue] + 1];
1455 [countInvocations setObject: count forKey: NSStringFromSelector([anInvocation selector])];
1457 if ([target respondsToSelector: [anInvocation selector]])
1458 [anInvocation invokeWithTarget: target];
1459 else if ([defaultTarget respondsToSelector: [anInvocation selector]])
1460 [anInvocation invokeWithTarget: defaultTarget];
1461 // Do nothing quietly if method not implemented.
1464 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
1466 return [templateClass instanceMethodSignatureForSelector: aSelector];
1471 @implementation WebView
1473 #if REMOVE_SAFARI_DOM_TREE_DEBUG_ITEM
1474 // this prevents open source users from crashing when using the Show DOM Tree menu item in Safari
1475 // FIXME: remove this when it is no longer needed to prevent Safari from crashing
1478 static BOOL tooLate = NO;
1480 if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeDebugMenu"])
1481 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_finishedLaunching) name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1486 +(void)_finishedLaunching
1488 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_removeDOMTreeMenuItem:) name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1489 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:NSApp];
1492 +(void)_removeDOMTreeMenuItem:(NSNotification *)notification
1494 NSMenu *debugMenu = [[[[NSApp mainMenu] itemArray] lastObject] submenu];
1495 NSMenuItem *domTree = [debugMenu itemWithTitle:@"Show DOM Tree"];
1497 [debugMenu removeItem:domTree];
1498 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidAddItemNotification object:[NSApp mainMenu]];
1502 + (BOOL)canShowMIMEType:(NSString *)MIMEType
1504 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType];
1507 + (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType
1509 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType];
1512 + (NSArray *)MIMETypesShownAsHTML
1514 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1515 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1517 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
1519 while ((key = [enumerator nextObject])) {
1520 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1521 [array addObject:key];
1527 + (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes
1529 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES];
1530 NSEnumerator *enumerator = [viewTypes keyEnumerator];
1532 while ((key = [enumerator nextObject])) {
1533 if ([viewTypes objectForKey:key] == [WebHTMLView class])
1534 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key];
1537 int i, count = [MIMETypes count];
1538 for (i = 0; i < count; i++) {
1539 [WebView registerViewClass:[WebHTMLView class]
1540 representationClass:[WebHTMLRepresentation class]
1541 forMIMEType:[MIMETypes objectAtIndex:i]];
1545 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard
1547 return [pasteboard _web_bestURL];
1550 + (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard
1552 return [pasteboard stringForType:WebURLNamePboardType];
1555 - (void)_registerDraggedTypes
1557 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes];
1558 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL];
1559 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes];
1560 [types addObjectsFromArray:URLTypes];
1561 [self registerForDraggedTypes:[types allObjects]];
1565 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
1567 static bool CGContextInitialized = false;
1568 if (!CGContextInitialized) {
1569 WKDisableCGDeferredUpdates();
1570 CGContextInitialized = true;
1573 _private->drawsBackground = YES;
1574 _private->smartInsertDeleteEnabled = YES;
1576 NSRect f = [self frame];
1577 WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
1578 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
1579 [self addSubview:frameView];
1580 [frameView release];
1582 _private->_pageBridge = [[WebPageBridge alloc] initWithMainFrameName:frameName webView:self frameView:frameView];
1584 [self _addToAllWebViewsSet];
1585 [self setGroupName:groupName];
1587 // If there's already a next key view (e.g., from a nib), wire it up to our
1588 // contained frame view. In any case, wire our next key view up to the our
1589 // contained frame view. This works together with our becomeFirstResponder
1590 // and setNextKeyView overrides.
1591 NSView *nextKeyView = [self nextKeyView];
1592 if (nextKeyView != nil && nextKeyView != frameView) {
1593 [frameView setNextKeyView:nextKeyView];
1595 [super setNextKeyView:frameView];
1599 [self _registerDraggedTypes];
1601 // Update WebCore with preferences. These values will either come from an archived WebPreferences,
1602 // or from the standard preferences, depending on whether this method was called from initWithCoder:
1603 // or initWithFrame, respectively.
1604 [self _updateWebCoreSettingsFromPreferences: [self preferences]];
1606 // Register to receive notifications whenever preference values change.
1607 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1608 name:WebPreferencesChangedNotification object:[self preferences]];
1613 return [self initWithFrame: NSZeroRect frameName: nil groupName: nil];
1616 - initWithFrame: (NSRect)f
1618 return [self initWithFrame: f frameName:nil groupName:nil];
1621 - initWithFrame: (NSRect)f frameName: (NSString *)frameName groupName: (NSString *)groupName;
1623 self = [super initWithFrame:f];
1627 #if ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH
1628 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which
1629 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the
1630 // need for Safari to unset it to prevent it from being passed to applications it launches.
1631 // Unsetting it when a WebView is first created is as good a place as any.
1632 // See <http://bugzilla.opendarwin.org/show_bug.cgi?id=4286> for more details.
1633 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) {
1634 unsetenv("DYLD_FRAMEWORK_PATH");
1635 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH");
1639 _private = [[WebViewPrivate alloc] init];
1640 [self _commonInitializationWithFrameName:frameName groupName:groupName];
1641 [self setMaintainsBackForwardList: YES];
1645 - (id)initWithCoder:(NSCoder *)decoder
1647 WebView *result = nil;
1651 NSString *frameName;
1652 NSString *groupName;
1654 result = [super initWithCoder:decoder];
1655 result->_private = [[WebViewPrivate alloc] init];
1657 // We don't want any of the archived subviews. The subviews will always
1658 // be created in _commonInitializationFrameName:groupName:.
1659 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
1661 if ([decoder allowsKeyedCoding]){
1662 frameName = [decoder decodeObjectForKey:@"FrameName"];
1663 groupName = [decoder decodeObjectForKey:@"GroupName"];
1665 [result setPreferences: [decoder decodeObjectForKey:@"Preferences"]];
1666 result->_private->useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"];
1668 LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)_private->useBackForwardList);
1673 [decoder decodeValueOfObjCType:@encode(int) at:&version];
1674 frameName = [decoder decodeObject];
1675 groupName = [decoder decodeObject];
1676 [result setPreferences: [decoder decodeObject]];
1678 [decoder decodeValuesOfObjCTypes:"c",&result->_private->useBackForwardList];
1680 [result _commonInitializationWithFrameName:frameName groupName:groupName];
1692 - (void)encodeWithCoder:(NSCoder *)encoder
1694 [super encodeWithCoder:encoder];
1696 if ([encoder allowsKeyedCoding]){
1697 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"];
1698 [encoder encodeObject:[self groupName] forKey:@"GroupName"];
1699 [encoder encodeObject:[self preferences] forKey:@"Preferences"];
1700 [encoder encodeBool:_private->useBackForwardList forKey:@"UseBackForwardList"];
1702 LOG (Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)_private->useBackForwardList);
1705 int version = WebViewVersion;
1706 [encoder encodeValueOfObjCType:@encode(int) at:&version];
1707 [encoder encodeObject:[[self mainFrame] name]];
1708 [encoder encodeObject:[self groupName]];
1709 [encoder encodeObject:[self preferences]];
1710 [encoder encodeValuesOfObjCTypes:"c",&_private->useBackForwardList];
1720 [[NSNotificationCenter defaultCenter] removeObserver:self];
1722 [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1725 // [super dealloc] can end up dispatching against _private (3466082)
1737 [[NSNotificationCenter defaultCenter] removeObserver:self];
1739 [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
1744 - (void)setPreferences: (WebPreferences *)prefs
1746 if (_private->preferences != prefs){
1747 [[NSNotificationCenter defaultCenter] removeObserver: self name: WebPreferencesChangedNotification object: [self preferences]];
1748 [WebPreferences _removeReferenceForIdentifier: [_private->preferences identifier]];
1749 [_private->preferences release];
1750 _private->preferences = [prefs retain];
1751 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1752 name:WebPreferencesChangedNotification object:[self preferences]];
1754 [[NSNotificationCenter defaultCenter]
1755 postNotificationName:WebPreferencesChangedNotification object:prefs userInfo:nil];
1759 - (WebPreferences *)preferences
1761 return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
1764 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
1766 if (![anIdentifier isEqual: [[self preferences] identifier]]){
1767 [self setPreferences: [[WebPreferences alloc] initWithIdentifier:anIdentifier]];
1771 - (NSString *)preferencesIdentifier
1773 return [[self preferences] identifier];
1777 - (void)setUIDelegate:delegate
1779 _private->UIDelegate = delegate;
1780 [_private->UIDelegateForwarder release];
1781 _private->UIDelegateForwarder = nil;
1786 return _private->UIDelegate;
1789 - (void)setResourceLoadDelegate: delegate
1791 _private->resourceProgressDelegate = delegate;
1792 [_private->resourceProgressDelegateForwarder release];
1793 _private->resourceProgressDelegateForwarder = nil;
1794 [self _cacheResourceLoadDelegateImplementations];
1798 - resourceLoadDelegate
1800 return _private->resourceProgressDelegate;
1804 - (void)setDownloadDelegate: delegate
1806 _private->downloadDelegate = delegate;
1812 return _private->downloadDelegate;
1815 - (void)setPolicyDelegate:delegate
1817 _private->policyDelegate = delegate;
1818 [_private->policyDelegateForwarder release];
1819 _private->policyDelegateForwarder = nil;
1824 return _private->policyDelegate;
1827 - (void)setFrameLoadDelegate:delegate
1829 _private->frameLoadDelegate = delegate;
1830 [_private->frameLoadDelegateForwarder release];
1831 _private->frameLoadDelegateForwarder = nil;
1836 return _private->frameLoadDelegate;
1839 - (WebFrame *)mainFrame
1841 // This can be called in initialization, before _private has been set up (3465613)
1845 return [(WebFrameBridge *)[_private->_pageBridge mainFrame] webFrame];
1850 - (WebBackForwardList *)backForwardList
1852 if (_private->useBackForwardList)
1853 return _private->backForwardList;
1857 - (void)setMaintainsBackForwardList: (BOOL)flag
1859 _private->useBackForwardList = flag;
1864 WebHistoryItem *item = [[self backForwardList] backItem];
1867 [self _goToItem: item withLoadType: WebFrameLoadTypeBack];
1875 WebHistoryItem *item = [[self backForwardList] forwardItem];
1878 [self _goToItem: item withLoadType: WebFrameLoadTypeForward];
1884 - (BOOL)goToBackForwardItem:(WebHistoryItem *)item
1886 [self _goToItem: item withLoadType: WebFrameLoadTypeIndexedBackForward];
1890 - (void)setTextSizeMultiplier:(float)m
1892 if (_private->textSizeMultiplier == m) {
1895 _private->textSizeMultiplier = m;
1898 - (float)textSizeMultiplier
1900 return _private->textSizeMultiplier;
1903 - (void)setApplicationNameForUserAgent:(NSString *)applicationName
1905 NSString *name = [applicationName copy];
1906 [_private->applicationNameForUserAgent release];
1907 _private->applicationNameForUserAgent = name;
1908 if (!_private->userAgentOverridden) {
1909 [_private->userAgent release];
1910 _private->userAgent = nil;
1914 - (NSString *)applicationNameForUserAgent
1916 return [[_private->applicationNameForUserAgent retain] autorelease];
1919 - (void)setCustomUserAgent:(NSString *)userAgentString
1921 NSString *override = [userAgentString copy];
1922 [_private->userAgent release];
1923 _private->userAgent = override;
1924 _private->userAgentOverridden = override != nil;
1927 - (NSString *)customUserAgent
1929 return _private->userAgentOverridden ? [[_private->userAgent retain] autorelease] : nil;
1932 - (void)setMediaStyle:(NSString *)mediaStyle
1934 if (_private->mediaStyle != mediaStyle) {
1935 [_private->mediaStyle release];
1936 _private->mediaStyle = [mediaStyle copy];
1940 - (NSString *)mediaStyle
1942 return _private->mediaStyle;
1945 - (BOOL)supportsTextEncoding
1947 id documentView = [[[self mainFrame] frameView] documentView];
1948 return [documentView conformsToProtocol:@protocol(WebDocumentText)]
1949 && [documentView supportsTextEncoding];
1952 - (void)setCustomTextEncodingName:(NSString *)encoding
1954 NSString *oldEncoding = [self customTextEncodingName];
1955 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) {
1958 [[self mainFrame] _reloadAllowingStaleDataWithOverrideEncoding:encoding];
1961 - (NSString *)_mainFrameOverrideEncoding
1963 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource];
1964 if (dataSource == nil) {
1965 dataSource = [[self mainFrame] dataSource];
1967 if (dataSource == nil) {
1970 return [dataSource _overrideEncoding];
1973 - (NSString *)customTextEncodingName
1975 return [self _mainFrameOverrideEncoding];
1978 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
1980 return [[[self mainFrame] _bridge] stringByEvaluatingJavaScriptFromString:script];
1983 - (WebScriptObject *)windowScriptObject
1985 return [[[self mainFrame] _bridge] windowScriptObject];
1989 // Get the appropriate user-agent string for a particular URL.
1990 // Since we no longer automatically spoof, this no longer requires looking at the URL.
1991 - (NSString *)userAgentForURL:(NSURL *)URL
1993 NSString *userAgent = _private->userAgent;
1995 return [[userAgent retain] autorelease];
1998 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode];
1999 id sourceVersion = [[NSBundle bundleForClass:[WebView class]]
2000 objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
2001 NSString *applicationName = _private->applicationNameForUserAgent;
2003 if ([applicationName length]) {
2004 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko) %@",
2005 language, sourceVersion, applicationName];
2007 userAgent = [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X; %@) AppleWebKit/%@ (KHTML, like Gecko)",
2008 language, sourceVersion];
2011 _private->userAgent = [userAgent retain];
2015 - (void)setHostWindow:(NSWindow *)hostWindow
2017 if (hostWindow != _private->hostWindow) {
2018 [[self mainFrame] _viewWillMoveToHostWindow:hostWindow];
2019 [_private->hostWindow release];
2020 _private->hostWindow = [hostWindow retain];
2021 [[self mainFrame] _viewDidMoveToHostWindow];
2025 - (NSWindow *)hostWindow
2027 return _private->hostWindow;
2030 - (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point
2032 return [[self _frameViewAtWindowPoint:point] documentView];
2035 - (NSView <WebDocumentDragging> *)_draggingDocumentViewAtWindowPoint:(NSPoint)point
2037 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:point];
2038 if ([documentView conformsToProtocol:@protocol(WebDocumentDragging)]) {
2039 return (NSView <WebDocumentDragging> *)documentView;
2044 - (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint
2046 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint];
2049 NSView <WebDocumentView> *documentView = [frameView documentView];
2050 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) {
2051 NSPoint point = [documentView convertPoint:windowPoint fromView:nil];
2052 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point];
2054 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey];
2057 - (NSDictionary *)elementAtPoint:(NSPoint)point
2059 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]];
2062 - (void)_setDraggingDocumentView:(NSView <WebDocumentDragging> *)newDraggingView
2064 if (_private->draggingDocumentView != newDraggingView) {
2065 [_private->draggingDocumentView release];
2066 _private->draggingDocumentView = [newDraggingView retain];
2070 - (NSDragOperation)_loadingDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2072 if (_private->dragDestinationActionMask & WebDragDestinationActionLoad) {
2073 NSPoint windowPoint = [draggingInfo draggingLocation];
2074 NSView *view = [self hitTest:[[self superview] convertPoint:windowPoint toView:nil]];
2075 // Don't accept the drag over a plug-in since plug-ins may want to handle it.
2076 if (![view isKindOfClass:[WebBaseNetscapePluginView class]] && !_private->editable && !_private->initiatedDrag) {
2077 // If not editing or dragging, use _web_dragOperationForDraggingInfo to find a URL to load on the pasteboard.
2078 return [self _web_dragOperationForDraggingInfo:draggingInfo];
2081 return NSDragOperationNone;
2084 - (NSDragOperation)_delegateDragOperationForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
2086 NSPoint windowPoint = [draggingInfo draggingLocation];
2087 NSView <WebDocumentDragging> *newDraggingView = [self _draggingDocumentViewAtWindowPoint:windowPoint];
2088 if (_private->draggingDocumentView != newDraggingView) {
2089 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2090 [self _setDraggingDocumentView:newDraggingView];
2093 _private->dragDestinationActionMask = [[self _UIDelegateForwarder] webView:self dragDestinationActionMaskForDraggingInfo:draggingInfo];
2094 NSDragOperation operation = NSDragOperationNone;
2096 if (_private->dragDestinationActionMask == WebDragDestinationActionNone) {
2097 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2099 operation = [_private->draggingDocumentView draggingUpdatedWithDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask];
2100 if (operation == NSDragOperationNone) {
2101 return [self _loadingDragOperationForDraggingInfo:draggingInfo];
2108 // The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work.
2109 // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination.
2110 // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination.
2111 // Forward these calls to the document subview to make its scroll view scroll.
2112 - (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta
2114 if (![self isEditable])
2117 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2118 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta];
2121 - (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo
2123 if (![self isEditable])
2126 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]];
2127 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo];
2130 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2132 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2135 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2137 return [self _delegateDragOperationForDraggingInfo:draggingInfo];
2140 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2142 [_private->draggingDocumentView draggingCancelledWithDraggingInfo:draggingInfo];
2143 [self _setDraggingDocumentView:nil];
2146 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2151 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2153 ASSERT(_private->draggingDocumentView == [self _draggingDocumentViewAtWindowPoint:[draggingInfo draggingLocation]]);
2155 if ([_private->draggingDocumentView concludeDragForDraggingInfo:draggingInfo actionMask:_private->dragDestinationActionMask]) {
2156 [self _setDraggingDocumentView:nil];
2160 [self _setDraggingDocumentView:nil];
2162 if ([self _loadingDragOperationForDraggingInfo:draggingInfo] != NSDragOperationNone) {
2163 NSURL *URL = [[self class] URLFromPasteboard:[draggingInfo draggingPasteboard]];
2165 [[self _UIDelegateForwarder] webView:self willPerformDragDestinationAction:WebDragDestinationActionLoad forDraggingInfo:draggingInfo];
2166 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
2167 [[self mainFrame] loadRequest:request];
2176 - (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types
2178 NSView *hitView = [super _hitTest:aPoint dragTypes:types];
2179 if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) {
2186 - (BOOL)acceptsFirstResponder
2188 return [[[self mainFrame] frameView] acceptsFirstResponder];
2191 - (BOOL)becomeFirstResponder
2193 // This works together with setNextKeyView to splice the WebView into
2194 // the key loop similar to the way NSScrollView does this. Note that
2195 // WebFrameView has very similar code.
2196 NSWindow *window = [self window];
2197 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2199 if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
2200 NSView *previousValidKeyView = [self previousValidKeyView];
2201 if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) {
2202 [window makeFirstResponder:previousValidKeyView];
2209 if ([mainFrameView acceptsFirstResponder]) {
2210 [window makeFirstResponder:mainFrameView];
2217 - (NSView *)_webcore_effectiveFirstResponder
2219 WebFrameView *frameView = [[self mainFrame] frameView];
2220 return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
2223 - (void)setNextKeyView:(NSView *)aView
2225 // This works together with becomeFirstResponder to splice the WebView into
2226 // the key loop similar to the way NSScrollView does this. Note that
2227 // WebFrameView has very similar code.
2228 WebFrameView *mainFrameView = [[self mainFrame] frameView];
2229 if (mainFrameView != nil) {
2230 [mainFrameView setNextKeyView:aView];
2232 [super setNextKeyView:aView];
2236 static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag)
2238 return forward ? [curr _nextFrameWithWrap:wrapFlag]
2239 : [curr _previousFrameWithWrap:wrapFlag];
2242 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
2244 // Get the frame holding the selection, or start with the main frame
2245 WebFrame *startFrame = [self _selectedOrMainFrame];
2247 // Search the first frame, then all the other frames, in order
2248 NSView <WebDocumentSearching> *startSearchView = nil;
2249 BOOL startHasSelection = NO;
2250 WebFrame *frame = startFrame;
2252 id <WebDocumentView> view = [[frame frameView] documentView];
2253 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) {
2254 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view;
2256 // first time through
2257 if (frame == startFrame) {
2258 // Remember if start even has a selection, to know if we need to search more later
2259 if ([searchView isKindOfClass:[WebHTMLView class]]) {
2260 // optimization for the common case, to avoid making giant string for selection
2261 startHasSelection = [[startFrame _bridge] selectedDOMRange] != nil;
2262 } else if ([searchView conformsToProtocol:@protocol(WebDocumentText)]) {
2263 startHasSelection = [(id <WebDocumentText>)searchView selectedString] != nil;
2265 startSearchView = searchView;
2268 if ([searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:NO]) {
2269 WebFrame *newSelectedFrame = [(WebFrameView *)[searchView _web_superviewOfClass:[WebFrameView class]] webFrame];
2270 if (newSelectedFrame != startFrame)
2271 [startFrame _clearSelection];
2272 [[self window] makeFirstResponder:searchView];
2276 frame = incrementFrame(frame, forward, wrapFlag);
2277 } while (frame != nil && frame != startFrame);
2279 // Search contents of startFrame, on the other side of the selection that we did earlier.
2280 // We cheat a bit and just research with wrap on
2281 if (wrapFlag && startHasSelection && startSearchView) {
2282 if ([startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]) {
2283 [[self window] makeFirstResponder:startSearchView];
2290 + (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType
2292 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType];
2293 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType];
2296 - (void)setGroupName:(NSString *)groupName
2298 [[self mainFrame] _setFrameNamespace:groupName];
2301 - (NSString *)groupName
2303 return [[self mainFrame] _frameNamespace];
2306 - (double)estimatedProgress
2308 return _private->progressValue;
2311 - (NSArray *)pasteboardTypesForSelection
2313 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView];
2314 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2315 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection];
2317 return [NSArray array];
2320 - (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2322 WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
2323 if ([bridge selectionState] != WebSelectionStateRange) {
2324 NSView <WebDocumentView> *documentView = [[[bridge webFrame] frameView] documentView];
2325 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) {
2326 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2331 - (NSArray *)pasteboardTypesForElement:(NSDictionary *)element
2333 if ([element objectForKey:WebElementImageURLKey] != nil) {
2334 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)];
2335 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2336 return [NSPasteboard _web_writableTypesForURL];
2337 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2338 return [self pasteboardTypesForSelection];
2340 return [NSArray array];
2343 - (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard
2345 if ([element objectForKey:WebElementImageURLKey] != nil) {
2346 [self _writeImageElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2347 } else if ([element objectForKey:WebElementLinkURLKey] != nil) {
2348 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard];
2349 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
2350 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2354 - (void)moveDragCaretToPoint:(NSPoint)point
2356 WebFrameBridge *bridge = [self _bridgeAtPoint:point];
2357 if (bridge != _private->dragCaretBridge) {
2358 [_private->dragCaretBridge removeDragCaret];
2359 _private->dragCaretBridge = [bridge retain];
2361 [_private->dragCaretBridge moveDragCaretToPoint:[self convertPoint:point toView:[[[_private->dragCaretBridge webFrame] frameView] documentView]]];
2364 - (void)removeDragCaret
2366 [_private->dragCaretBridge removeDragCaret];
2367 [_private->dragCaretBridge release];
2368 _private->dragCaretBridge = nil;
2371 - (void)_inspectElement:(id)sender
2373 NSDictionary *element = [sender representedObject];
2374 WebFrame *frame = [element objectForKey:WebElementFrameKey];
2375 DOMNode *node = [element objectForKey:WebElementDOMNodeKey];
2376 if (!node || !frame)
2379 if ([node nodeType] != DOM_ELEMENT_NODE || [node nodeType] != DOM_DOCUMENT_NODE)
2380 node = [node parentNode];
2382 WebInspector *inspector = [WebInspector sharedWebInspector];
2383 [inspector setWebFrame:frame];
2384 [inspector setFocusedDOMNode:node];
2386 node = [node parentNode];
2387 node = [node parentNode];
2388 if (node) // set the root node to something retivally close to the focused node
2389 [inspector setRootDOMNode:node];
2391 [inspector showWindow:nil];
2395 @implementation WebView (WebIBActions)
2397 - (IBAction)takeStringURLFrom: sender
2399 NSString *URLString = [sender stringValue];
2401 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2406 return [[self backForwardList] backItem] != nil;
2409 - (BOOL)canGoForward
2411 return [[self backForwardList] forwardItem] != nil;
2414 - (IBAction)goBack:(id)sender
2419 - (IBAction)goForward:(id)sender
2424 - (IBAction)stopLoading:(id)sender
2426 [[self mainFrame] stopLoading];
2429 - (IBAction)reload:(id)sender
2431 [[self mainFrame] reload];
2434 #define MinimumTextSizeMultiplier 0.5
2435 #define MaximumTextSizeMultiplier 3.0
2436 #define TextSizeMultiplierRatio 1.2
2438 - (BOOL)canMakeTextSmaller
2440 BOOL canShrinkMore = _private->textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2441 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:0];
2444 - (BOOL)canMakeTextLarger
2446 BOOL canGrowMore = _private->textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2447 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:0];
2450 - (IBAction)makeTextSmaller:(id)sender
2452 float newScale = _private->textSizeMultiplier/TextSizeMultiplierRatio;
2453 BOOL canShrinkMore = newScale > MinimumTextSizeMultiplier;
2454 [self _performTextSizingSelector:@selector(_makeTextSmaller:) withObject:sender onTrackingDocs:canShrinkMore selForNonTrackingDocs:@selector(_canMakeTextSmaller) newScaleFactor:newScale];
2457 - (IBAction)makeTextLarger:(id)sender
2459 float newScale = _private->textSizeMultiplier*TextSizeMultiplierRatio;
2460 BOOL canGrowMore = newScale < MaximumTextSizeMultiplier;
2461 [self _performTextSizingSelector:@selector(_makeTextLarger:) withObject:sender onTrackingDocs:canGrowMore selForNonTrackingDocs:@selector(_canMakeTextLarger) newScaleFactor:newScale];
2464 - (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2466 id responder = [self _responderForResponderOperations];
2467 if (responder != self && [responder respondsToSelector:[item action]]) {
2468 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) {
2469 return [responder validateUserInterfaceItem:item];
2476 #define VALIDATE(name) \
2477 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; }
2479 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2481 SEL action = [item action];
2483 if (action == @selector(goBack:)) {
2484 return [self canGoBack];
2485 } else if (action == @selector(goForward:)) {
2486 return [self canGoForward];
2487 } else if (action == @selector(makeTextLarger:)) {
2488 return [self canMakeTextLarger];
2489 } else if (action == @selector(makeTextSmaller:)) {
2490 return [self canMakeTextSmaller];
2491 } else if (action == @selector(makeTextStandardSize:)) {
2492 return [self canMakeTextStandardSize];
2493 } else if (action == @selector(reload:)) {
2494 return [[self mainFrame] dataSource] != nil;
2495 } else if (action == @selector(stopLoading:)) {
2496 return [self _isLoading];
2497 } else if (action == @selector(toggleContinuousSpellChecking:)) {
2498 BOOL checkMark = NO;
2500 if ([self isEditable] && [self _continuousCheckingAllowed]) {
2501 checkMark = [self isContinuousSpellCheckingEnabled];
2504 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) {
2505 NSMenuItem *menuItem = (NSMenuItem *)item;
2506 [menuItem setState:checkMark ? NSOnState : NSOffState];
2510 FOR_EACH_RESPONDER_SELECTOR(VALIDATE)
2517 @implementation WebView (WebPendingPublic)
2519 - (void)setMainFrameURL:(NSString *)URLString
2521 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]];
2524 - (NSString *)mainFrameURL
2527 ds = [[self mainFrame] provisionalDataSource];
2529 ds = [[self mainFrame] dataSource];
2530 return [[[ds request] URL] _web_originalDataAsString];
2535 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]);
2536 return [self _isLoading];
2539 - (NSString *)mainFrameTitle
2541 NSString *mainFrameTitle = [[[self mainFrame] dataSource] pageTitle];
2542 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@"";
2545 - (NSImage *)mainFrameIcon
2547 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
2550 - (void)setDrawsBackground:(BOOL)drawsBackground
2552 if (_private->drawsBackground == drawsBackground)
2554 _private->drawsBackground = drawsBackground;
2555 [[self mainFrame] _updateDrawsBackground];
2558 - (BOOL)drawsBackground
2560 return _private->drawsBackground;
2563 - (void)toggleSmartInsertDelete:(id)sender
2565 if ([self isEditable]) {
2566 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]];
2570 - (IBAction)toggleContinuousSpellChecking:(id)sender
2572 if ([self isEditable]) {
2573 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]];
2577 - (BOOL)maintainsInactiveSelection
2579 return [self isEditable];
2582 // This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it
2583 // until the day comes when we're no longer supporting Mail on Tiger.
2584 - (WebFrame *)_frameForCurrentSelection
2586 return [self _selectedOrMainFrame];
2589 - (WebFrame *)selectedFrame
2591 // If the first responder is a view in our tree, we get the frame containing the first responder.
2592 // This is faster than searching the frame hierarchy, and will give us a result even in the case
2593 // where the focused frame doesn't actually contain a selection.
2594 WebFrame *focusedFrame = [self _focusedFrame];
2597 WebFrame *frameWithSelection = [[self mainFrame] _findFrameWithSelection];
2599 ASSERT(frameWithSelection == nil || frameWithSelection == focusedFrame);
2600 return focusedFrame;
2603 // If the first responder is outside of our view tree, we search for a frame containing a selection.
2604 // There should be at most only one of these.
2605 return [[self mainFrame] _findFrameWithSelection];
2610 - (BOOL)canMakeTextStandardSize
2612 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0;
2613 return [self _performTextSizingSelector:(SEL)0 withObject:nil onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:0];
2616 - (IBAction)makeTextStandardSize:(id)sender
2618 BOOL notAlreadyStandard = _private->textSizeMultiplier != 1.0;
2619 [self _performTextSizingSelector:@selector(_makeTextStandardSize:) withObject:sender onTrackingDocs:notAlreadyStandard selForNonTrackingDocs:@selector(_canMakeTextStandardSize) newScaleFactor:1.0];
2622 - (void)setScriptDebugDelegate:delegate
2624 _private->scriptDebugDelegate = delegate;
2625 [_private->scriptDebugDelegateForwarder release];
2626 _private->scriptDebugDelegateForwarder = nil;
2629 - scriptDebugDelegate
2631 return _private->scriptDebugDelegate;
2636 WebFrameBridge *bridge = [[self mainFrame] _bridge];
2639 return [bridge shouldClose];
2642 - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script
2644 return [[[self mainFrame] _bridge] aeDescByEvaluatingJavaScriptFromString:script];
2647 - (unsigned)highlightAllMatchesForString:(NSString *)string caseSensitive:(BOOL)caseFlag
2649 WebFrame *frame = [self mainFrame];
2650 unsigned matchCount = 0;
2652 id <WebDocumentView> view = [[frame frameView] documentView];
2653 // FIXME: introduce a protocol, or otherwise make this work with other types
2654 if ([view isKindOfClass:[WebHTMLView class]])
2655 matchCount += [(WebHTMLView *)view highlightAllMatchesForString:string caseSensitive:caseFlag];
2657 frame = incrementFrame(frame, YES, NO);
2663 - (void)clearHighlightedMatches
2665 WebFrame *frame = [self mainFrame];
2667 id <WebDocumentView> view = [[frame frameView] documentView];
2668 // FIXME: introduce a protocol, or otherwise make this work with other types
2669 if ([view isKindOfClass:[WebHTMLView class]])
2670 [(WebHTMLView *)view clearHighlightedMatches];
2672 frame = incrementFrame(frame, YES, NO);
2678 @implementation WebView (WebViewPrintingPrivate)
2680 - (float)_headerHeight
2682 if ([[self UIDelegate] respondsToSelector:@selector(webViewHeaderHeight:)]) {
2683 return [[self UIDelegate] webViewHeaderHeight:self];
2686 #ifdef DEBUG_HEADER_AND_FOOTER
2693 - (float)_footerHeight
2695 if ([[self UIDelegate] respondsToSelector:@selector(webViewFooterHeight:)]) {
2696 return [[self UIDelegate] webViewFooterHeight:self];
2699 #ifdef DEBUG_HEADER_AND_FOOTER
2706 - (void)_drawHeaderInRect:(NSRect)rect
2708 #ifdef DEBUG_HEADER_AND_FOOTER
2709 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2710 [currentContext saveGraphicsState];
2711 [[NSColor yellowColor] set];
2713 [currentContext restoreGraphicsState];
2716 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawHeaderInRect:)]) {
2717 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2718 [currentContext saveGraphicsState];
2720 [[self UIDelegate] webView:self drawHeaderInRect:rect];
2721 [currentContext restoreGraphicsState];
2725 - (void)_drawFooterInRect:(NSRect)rect
2727 #ifdef DEBUG_HEADER_AND_FOOTER
2728 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2729 [currentContext saveGraphicsState];
2730 [[NSColor cyanColor] set];
2732 [currentContext restoreGraphicsState];
2735 if ([[self UIDelegate] respondsToSelector:@selector(webView:drawFooterInRect:)]) {
2736 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
2737 [currentContext saveGraphicsState];
2739 [[self UIDelegate] webView:self drawFooterInRect:rect];
2740 [currentContext restoreGraphicsState];
2744 - (void)_adjustPrintingMarginsForHeaderAndFooter
2746 NSPrintOperation *op = [NSPrintOperation currentOperation];
2747 NSPrintInfo *info = [op printInfo];
2748 float scale = [op _web_pageSetupScaleFactor];
2749 [info setTopMargin:[info topMargin] + [self _headerHeight]*scale];
2750 [info setBottomMargin:[info bottomMargin] + [self _footerHeight]*scale];
2753 - (void)_drawHeaderAndFooter
2755 // The header and footer rect height scales with the page, but the width is always
2756 // all the way across the printed page (inset by printing margins).
2757 NSPrintOperation *op = [NSPrintOperation currentOperation];
2758 float scale = [op _web_pageSetupScaleFactor];
2759 NSPrintInfo *printInfo = [op printInfo];
2760 NSSize paperSize = [printInfo paperSize];
2761 float headerFooterLeft = [printInfo leftMargin]/scale;
2762 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale;
2763 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] ,
2764 headerFooterWidth, [self _footerHeight]);
2765 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale,
2766 headerFooterWidth, [self _headerHeight]);
2768 [self _drawHeaderInRect:headerRect];
2769 [self _drawFooterInRect:footerRect];
2773 @implementation WebView (WebDebugBinding)
2775 - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
2777 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context);
2778 [super addObserver:anObserver forKeyPath:keyPath options:options context:context];
2781 - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
2783 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath);
2784 [super removeObserver:anObserver forKeyPath:keyPath];
2789 //==========================================================================================
2792 @implementation WebView (WebViewCSS)
2794 - (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement
2796 // FIXME: is this the best level for this conversion?
2797 if (pseudoElement == nil) {
2798 pseudoElement = @"";
2800 return [[element ownerDocument] getComputedStyle:element :pseudoElement];
2805 @implementation WebView (WebViewEditing)
2807 - (DOMRange *)editableDOMRangeForPoint:(NSPoint)point
2809 WebFrameBridge *bridge = [self _bridgeAtPoint:point];
2810 return [bridge editableDOMRangeForPoint:[self convertPoint:point toView:[[[bridge webFrame] frameView] documentView]]];
2813 - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag;
2815 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag];
2818 - (BOOL)_shouldBeginEditingInDOMRange:(DOMRange *)range
2820 return [[self _editingDelegateForwarder] webView:self shouldBeginEditingInDOMRange:range];
2823 - (BOOL)_shouldEndEditingInDOMRange:(DOMRange *)range
2825 return [[self _editingDelegateForwarder] webView:self shouldEndEditingInDOMRange:range];
2830 id documentView = [[[self mainFrame] frameView] documentView];
2831 return [documentView respondsToSelector:@selector(_canPaste)] && [documentView _canPaste];
2834 - (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity
2837 [[self _bridgeForSelectedOrMainFrame] deselectText];
2839 // Derive the bridge to use from the range passed in.
2840 // Using _bridgeForSelectedOrMainFrame could give us a different document than
2841 // the one the range uses.
2842 [[[range startContainer] _bridge] setSelectedDOMRange:range affinity:selectionAffinity closeTyping:YES];
2846 - (DOMRange *)selectedDOMRange
2848 return [[self _bridgeForSelectedOrMainFrame] selectedDOMRange];
2851 - (NSSelectionAffinity)selectionAffinity
2853 return [[self _bridgeForSelectedOrMainFrame] selectionAffinity];
2856 - (void)setEditable:(BOOL)flag
2858 if (_private->editable != flag) {
2859 _private->editable = flag;
2860 WebFrameBridge *bridge = [[self mainFrame] _bridge];
2862 [bridge applyEditingStyleToBodyElement];
2863 // If the WebView is made editable and the selection is empty, set it to something.
2864 if ([self selectedDOMRange] == nil)
2865 [bridge setSelectionFromNone];
2868 [bridge removeEditingStyleFromBodyElement];
2875 return _private->editable;
2878 - (void)setTypingStyle:(DOMCSSStyleDeclaration *)style
2880 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
2881 // change the API to allow this.
2882 [[self _bridgeForSelectedOrMainFrame] setTypingStyle:style withUndoAction:WebUndoActionUnspecified];
2885 - (DOMCSSStyleDeclaration *)typingStyle
2887 return [[self _bridgeForSelectedOrMainFrame] typingStyle];
2890 - (void)setSmartInsertDeleteEnabled:(BOOL)flag
2892 _private->smartInsertDeleteEnabled = flag;
2895 - (BOOL)smartInsertDeleteEnabled
2897 return _private->smartInsertDeleteEnabled;
2900 - (void)setContinuousSpellCheckingEnabled:(BOOL)flag
2902 _private->continuousSpellCheckingEnabled = flag;
2903 if ([self isContinuousSpellCheckingEnabled]) {
2904 [[self class] _preflightSpellChecker];
2906 [[self mainFrame] _unmarkAllMisspellings];
2910 - (BOOL)isContinuousSpellCheckingEnabled
2912 return _private->continuousSpellCheckingEnabled && [self _continuousCheckingAllowed];
2915 - (WebNSInt)spellCheckerDocumentTag
2917 if (!_private->hasSpellCheckerDocumentTag) {
2918 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
2919 _private->hasSpellCheckerDocumentTag = YES;
2921 return _private->spellCheckerDocumentTag;
2924 - (NSUndoManager *)undoManager
2926 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self];
2930 return [super undoManager];
2933 - (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector
2935 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
2936 if ([_private->editingDelegate respondsToSelector:selector])
2937 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self];
2940 - (void)setEditingDelegate:(id)delegate
2942 if (_private->editingDelegate == delegate)
2945 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
2947 // remove notifications from current delegate
2948 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self];
2949 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self];
2950 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self];
2951 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self];
2952 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self];
2954 _private->editingDelegate = delegate;
2955 [_private->editingDelegateForwarder release];
2956 _private->editingDelegateForwarder = nil;
2958 // add notifications for new delegate
2959 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)];
2960 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)];
2961 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)];
2962 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)];
2963 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)];
2966 - (id)editingDelegate
2968 return _private->editingDelegate;
2971 - (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text
2973 // FIXME: Should this really be attached to the document with the current selection?
2974 DOMCSSStyleDeclaration *decl = [[[self _bridgeForSelectedOrMainFrame] DOMDocument] createCSSStyleDeclaration];
2975 [decl setCssText:text];
2981 @implementation WebView (WebViewUndoableEditing)
2983 - (void)replaceSelectionWithNode:(DOMNode *)node
2985 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO];
2988 - (void)replaceSelectionWithText:(NSString *)text
2990 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
2993 - (void)replaceSelectionWithMarkupString:(NSString *)markupString
2995 [[self _bridgeForSelectedOrMainFrame] replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO];
2998 - (void)replaceSelectionWithArchive:(WebArchive *)archive
3000 [[[[self _bridgeForSelectedOrMainFrame] webFrame] dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES];
3003 - (void)deleteSelection
3005 WebFrameBridge *bridge = [self _bridgeForSelectedOrMainFrame];
3006 [bridge deleteSelectionWithSmartDelete:[(WebHTMLView *)[[[bridge webFrame] frameView] documentView] _canSmartCopyOrDelete]];
3009 - (void)applyStyle:(DOMCSSStyleDeclaration *)style
3011 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to
3012 // change the API to allow this.
3013 [[self _bridgeForSelectedOrMainFrame] applyStyle:style withUndoAction:WebUndoActionUnspecified];
3018 @implementation WebView (WebViewEditingActions)
3020 - (void)_performResponderOperation:(SEL)selector with:(id)parameter
3022 static BOOL reentered = NO;
3024 [[self nextResponder] tryToPerform:selector with:parameter];
3028 // There are two possibilities here.
3030 // One is that WebView has been called in its role as part of the responder chain.
3031 // In that case, it's fine to call the first responder and end up calling down the
3032 // responder chain again. Later we will return here with reentered = YES and continue
3033 // past the WebView.
3035 // The other is that we are being called directly, in which case we want to pass the
3036 // selector down to the view inside us that can handle it, and continue down the
3037 // responder chain as usual.
3039 // Pass this selector down to the first responder.
3040 NSResponder *responder = [self _responderForResponderOperations];
3042 [responder tryToPerform:selector with:parameter];
3046 #define FORWARD(name) \
3047 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; }
3049 FOR_EACH_RESPONDER_SELECTOR(FORWARD)
3051 - (void)insertText:(NSString *)text
3053 [self _performResponderOperation:_cmd with:text];
3058 @implementation WebView (WebViewEditingInMail)
3060 - (void)_insertNewlineInQuotedContent;
3062 [[self _bridgeForSelectedOrMainFrame] insertParagraphSeparatorInQuotedContent];
3065 - (BOOL)_selectWordBeforeMenuEvent
3067 return _private->selectWordBeforeMenuEvent;
3070 - (void)_setSelectWordBeforeMenuEvent:(BOOL)flag
3072 _private->selectWordBeforeMenuEvent = flag;
3077 @implementation WebView (WebFileInternal)
3079 - (WebFrame *)_focusedFrame
3081 NSResponder *resp = [[self window] firstResponder];
3082 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:self]) {
3083 WebFrameView *frameView = [resp isKindOfClass:[WebFrameView class]]
3084 ? (WebFrameView *)resp
3085 : (WebFrameView *)[(NSView *)resp _web_superviewOfClass:[WebFrameView class]];
3086 ASSERT(frameView != nil);
3087 return [frameView webFrame];
3093 - (WebFrame *)_selectedOrMainFrame
3095 WebFrame *result = [self selectedFrame];
3097 result = [self mainFrame];
3101 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame
3103 return [[self _selectedOrMainFrame] _bridge];
3108 WebFrame *mainFrame = [self mainFrame];
3109 return [[mainFrame dataSource] isLoading]
3110 || [[mainFrame provisionalDataSource] isLoading];
3113 - (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point
3115 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]];
3116 return (WebFrameView *)[view _web_superviewOfClass:[WebFrameView class] stoppingAtClass:[self class]];
3119 - (WebFrameBridge *)_bridgeAtPoint:(NSPoint)point
3121 return [[[self _frameViewAtWindowPoint:[self convertPoint:point toView:nil]] webFrame] _bridge];
3124 + (void)_preflightSpellCheckerNow:(id)sender
3126 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
3129 + (void)_preflightSpellChecker
3131 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3132 if ([NSSpellChecker sharedSpellCheckerExists]) {
3133 [self _preflightSpellCheckerNow:self];
3135 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0];
3139 - (BOOL)_continuousCheckingAllowed
3141 static BOOL allowContinuousSpellChecking = YES;
3142 static BOOL readAllowContinuousSpellCheckingDefault = NO;
3143 if (!readAllowContinuousSpellCheckingDefault) {
3144 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) {
3145 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
3147 readAllowContinuousSpellCheckingDefault = YES;
3149 return allowContinuousSpellChecking;
3152 - (NSResponder *)_responderForResponderOperations
3154 NSResponder *responder = [[self window] firstResponder];
3155 if (![self _web_firstResponderIsSelfOrDescendantView]) {
3156 responder = [[[self mainFrame] frameView] documentView];
3158 responder = [[self mainFrame] frameView];
3164 - (void)_searchWithGoogleFromMenu:(id)sender
3166 id documentView = [[[self mainFrame] frameView] documentView];
3167 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3171 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3172 if ([selectedString length] == 0) {
3176 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
3177 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
3178 NSMutableString *s = [selectedString mutableCopy];
3179 const unichar nonBreakingSpaceCharacter = 0xA0;
3180 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1];
3181 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
3182 [pasteboard setString:s forType:NSStringPboardType];
3185 // FIXME: seems fragile to use the service by name, but this is what AppKit does
3186 NSPerformService(@"Search With Google", pasteboard);
3189 - (void)_searchWithSpotlightFromMenu:(id)sender
3191 id documentView = [[[self mainFrame] frameView] documentView];
3192 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) {
3196 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString];
3197 if ([selectedString length] == 0) {
3201 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions);
3204 // Slightly funky method that lets us have one copy of the logic for finding docViews that can do
3205 // text sizing. It returns whether it found any "suitable" doc views. It sends sel to any suitable
3206 // doc views, or if sel==0 we do nothing to them. For doc views that track our size factor, they are
3207 // suitable if doTrackingViews==YES (which in practice means that our size factor isn't at its max or
3208 // min). For doc views that don't track it, we send them testSel to determine suitablility. If we
3209 // do find any suitable tracking doc views and newScaleFactor!=0, we will set the common scale factor
3210 // to that new factor before we send sel to any of them.
3211 - (BOOL)_performTextSizingSelector:(SEL)sel withObject:(id)arg onTrackingDocs:(BOOL)doTrackingViews selForNonTrackingDocs:(SEL)testSel newScaleFactor:(float)newScaleFactor
3213 if ([[self mainFrame] dataSource] == nil) {
3217 BOOL foundSome = NO;
3218 NSArray *docViews = [[self mainFrame] _documentViews];
3220 for (i = [docViews count]-1; i >= 0; i--) {
3221 id docView = [docViews objectAtIndex:i];
3222 if ([docView conformsToProtocol:@protocol(_WebDocumentTextSizing)]) {
3223 id <_WebDocumentTextSizing> sizingDocView = (id <_WebDocumentTextSizing>)docView;
3225 if ([sizingDocView _tracksCommonSizeFactor]) {
3226 isSuitable = doTrackingViews;
3227 if (isSuitable && newScaleFactor != 0) {
3228 [self setTextSizeMultiplier:newScaleFactor];
3231 // Incantation to perform a selector returning a BOOL.
3232 isSuitable = ((BOOL(*)(id, SEL))objc_msgSend)(sizingDocView, testSel);
3238 [sizingDocView performSelector:sel withObject:arg];
3240 // if we're just called for the benefit of the return value, we can return at first match