3 Copyright (c) 2001, Apple, Inc. All rights reserved.
6 #import <WebKit/WebFrameInternal.h>
9 #import <WebKit/WebArchive.h>
10 #import <WebKit/WebBackForwardList.h>
11 #import <WebKit/WebBridge.h>
12 #import <WebKit/WebDataProtocol.h>
13 #import <WebKit/WebDataSourcePrivate.h>
14 #import <WebKit/WebDefaultResourceLoadDelegate.h>
15 #import <WebKit/WebDefaultUIDelegate.h>
16 #import <WebKit/WebDocumentInternal.h>
17 #import <WebKit/WebFormDataStream.h>
18 #import <WebKit/WebFrameLoadDelegate.h>
19 #import <WebKit/WebFrameViewInternal.h>
20 #import <WebKit/WebHistoryPrivate.h>
21 #import <WebKit/WebHistoryItemPrivate.h>
22 #import <WebKit/WebHTMLRepresentationPrivate.h>
23 #import <WebKit/WebHTMLViewPrivate.h>
24 #import <WebKit/WebKitErrorsPrivate.h>
25 #import <WebKit/WebKitLogging.h>
26 #import <WebKit/WebKitStatisticsPrivate.h>
27 #import <WebKit/WebNetscapePluginDocumentView.h>
28 #import <WebKit/WebNetscapePluginEmbeddedView.h>
29 #import <WebKit/WebNSObjectExtras.h>
30 #import <WebKit/WebNSURLExtras.h>
31 #import <WebKit/WebNullPluginView.h>
32 #import <WebKit/WebPreferencesPrivate.h>
33 #import <WebKit/WebPlugin.h>
34 #import <WebKit/WebPluginController.h>
35 #import <WebKit/WebPluginDocumentView.h>
36 #import <WebKit/WebResourceLoadDelegate.h>
37 #import <WebKit/WebResourcePrivate.h>
38 #import <WebKit/WebViewInternal.h>
39 #import <WebKit/WebUIDelegate.h>
41 #import <Foundation/NSDictionary_NSURLExtras.h>
42 #import <Foundation/NSString_NSURLExtras.h>
43 #import <Foundation/NSURLRequestPrivate.h>
45 #import <objc/objc-runtime.h>
48 static const char * const stateNames[] = {
49 "WebFrameStateProvisional",
50 "WebFrameStateCommittedPage",
51 "WebFrameStateLayoutAcceptable",
52 "WebFrameStateComplete"
57 Here is the current behavior matrix for four types of navigations:
61 Restore form state: YES
62 Restore scroll and focus state: YES
63 WF Cache policy: NSURLRequestUseProtocolCachePolicy
64 Add to back/forward list: YES
68 Restore form state: YES
69 Restore scroll and focus state: YES
70 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
71 Add to back/forward list: NO
73 Reload (meaning only the reload button):
75 Restore form state: NO
76 Restore scroll and focus state: YES
77 WF Cache policy: NSURLRequestReloadIgnoringCacheData
78 Add to back/forward list: NO
80 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
82 Restore form state: NO
83 Restore scroll and focus state: NO, reset to initial conditions
84 WF Cache policy: NSURLRequestReloadIgnoringCacheData
85 Add to back/forward list: NO
88 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
89 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
90 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
92 @interface NSObject (WebExtraPerformMethod)
94 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3;
98 @implementation NSObject (WebExtraPerformMethod)
100 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3
102 return objc_msgSend(self, aSelector, object1, object2, object3);
107 @interface NSArray (WebSafeMakePerform)
109 - (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector;
114 @implementation NSArray (WebSafeMakePerform)
116 - (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector
118 unsigned count = [self count];
123 [[self copy] makeObjectsPerformSelector:aSelector];
128 [self getObjects:batch range:NSMakeRange(0, count)];
130 for (i = 0; i < count; i++) {
131 objc_msgSend(batch[i], aSelector);
137 // One day we might want to expand the use of this kind of class such that we'd receive one
138 // over the bridge, and possibly hand it on through to the FormsDelegate.
139 // Today it is just used internally to keep some state as we make our way through a bunch
140 // layers while doing a load.
141 @interface WebFormState : NSObject
144 NSDictionary *_values;
145 WebFrame *_sourceFrame;
147 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame;
148 - (DOMElement *)form;
149 - (NSDictionary *)values;
150 - (WebFrame *)sourceFrame;
153 @interface WebFrame (ForwardDecls)
154 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState;
155 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
156 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
158 - (void)_saveScrollPositionToItem:(WebHistoryItem *)item;
159 - (void)_restoreScrollPosition;
160 - (void)_scrollToTop;
162 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
163 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
164 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
167 @implementation WebFramePrivate
176 state = WebFrameStateComplete;
177 loadType = WebFrameLoadTypeStandard;
185 [webFrameView release];
186 [dataSource release];
187 [provisionalDataSource release];
191 [currentItem release];
192 [provisionalItem release];
193 [previousItem release];
195 ASSERT(listener == nil);
196 ASSERT(policyRequest == nil);
197 ASSERT(policyFrameName == nil);
198 ASSERT(policyTarget == nil);
199 ASSERT(policyFormState == nil);
200 ASSERT(policyDataSource == nil);
205 - (NSString *)name { return name; }
206 - (void)setName:(NSString *)n
208 NSString *newName = [n copy];
213 - (WebFrameView *)webFrameView { return webFrameView; }
214 - (void)setWebFrameView: (WebFrameView *)v
217 [webFrameView release];
221 - (WebDataSource *)dataSource { return dataSource; }
222 - (void)setDataSource: (WebDataSource *)d
225 [dataSource release];
229 - (WebView *)webView { return webView; }
230 - (void)setWebView: (WebView *)wv
232 webView = wv; // not retained (yet)
235 - (WebDataSource *)provisionalDataSource { return provisionalDataSource; }
236 - (void)setProvisionalDataSource: (WebDataSource *)d
238 ASSERT(!d || !provisionalDataSource);
240 [provisionalDataSource release];
241 provisionalDataSource = d;
244 - (WebFrameLoadType)loadType { return loadType; }
245 - (void)setLoadType: (WebFrameLoadType)t
250 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
251 - (void)setProvisionalItem: (WebHistoryItem *)item
254 [provisionalItem release];
255 provisionalItem = item;
258 - (WebHistoryItem *)previousItem { return previousItem; }
259 - (void)setPreviousItem:(WebHistoryItem *)item
262 [previousItem release];
266 - (WebHistoryItem *)currentItem { return currentItem; }
267 - (void)setCurrentItem:(WebHistoryItem *)item
270 [currentItem release];
276 @implementation WebFrame (WebPrivate)
278 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
280 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
281 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
282 [request _webDataRequestSetData:data];
283 [request _webDataRequestSetEncoding:encodingName];
284 [request _webDataRequestSetBaseURL:URL];
285 [request _webDataRequestSetUnreachableURL:unreachableURL];
286 [request _webDataRequestSetMIMEType:MIMEType?MIMEType:@"text/html"];
290 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
292 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
293 if (unreachableURL == nil) {
297 if (_private->policyLoadType != WebFrameLoadTypeForward
298 && _private->policyLoadType != WebFrameLoadTypeBack
299 && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
303 // We only treat unreachableURLs specially during the delegate callbacks
304 // for provisional load errors and navigation policy decisions. The former
305 // case handles well-formed URLs that can't be loaded, and the latter
306 // case handles malformed URLs and unknown schemes. Loading alternate content
307 // at other times behaves like a standard load.
308 WebDataSource *compareDataSource = nil;
309 if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
310 compareDataSource = _private->policyDataSource;
311 } else if (_private->delegateIsHandlingProvisionalLoadError) {
312 compareDataSource = [self provisionalDataSource];
315 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
318 - (void)_loadRequest:(NSURLRequest *)request subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
320 WebFrameLoadType loadType;
322 // note this copies request
323 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
324 NSMutableURLRequest *r = [newDataSource request];
325 [self _addExtraFieldsToRequest:r alwaysFromRequest: NO];
326 if ([self _shouldTreatURLAsSameAsCurrent:[request URL]]) {
327 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
328 loadType = WebFrameLoadTypeSame;
330 loadType = WebFrameLoadTypeStandard;
333 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
334 [newDataSource _addSubresources:subresources];
335 [newDataSource _addSubframeArchives:subframeArchives];
337 // When we loading alternate content for an unreachable URL that we're
338 // visiting in the b/f list, we treat it as a reload so the b/f list
339 // is appropriately maintained.
340 if ([self _shouldReloadToHandleUnreachableURLFromRequest:request]) {
341 ASSERT(loadType == WebFrameLoadTypeStandard);
342 loadType = WebFrameLoadTypeReload;
345 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
346 [newDataSource release];
349 - (void)_setWebView:(WebView *)v
351 // To set to nil, we have to use _detachFromParent, not this.
353 [_private setWebView:v];
356 // helper method used in various nav cases below
357 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
359 if ([[self dataSource] _URLForHistory] != nil) {
360 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
361 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
362 [[[self webView] backForwardList] addItem:bfItem];
366 - (WebHistoryItem *)_createItem: (BOOL)useOriginal
368 WebDataSource *dataSrc = [self dataSource];
369 NSURLRequest *request;
370 NSURL *unreachableURL = [dataSrc unreachableURL];
373 WebHistoryItem *bfItem;
376 request = [dataSrc _originalRequest];
378 request = [dataSrc request];
381 if (unreachableURL != nil) {
382 URL = unreachableURL;
383 originalURL = unreachableURL;
386 originalURL = [[dataSrc _originalRequest] URL];
389 LOG (History, "creating item for %@", request);
391 // Frames that have never successfully loaded any content
392 // may have no URL at all. Currently our history code can't
393 // deal with such things, so we nip that in the bud here.
394 // Later we may want to learn to live with nil for URL.
395 // See bug 3368236 and related bugs for more information.
397 URL = [NSURL URLWithString:@"about:blank"];
399 if (originalURL == nil) {
400 originalURL = [NSURL URLWithString:@"about:blank"];
403 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
404 [dataSrc _addBackForwardItem:bfItem];
405 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
407 // save form state if this is a POST
408 [bfItem _setFormInfoFromRequest:request];
410 // Set the item for which we will save document state
411 [_private setPreviousItem:[_private currentItem]];
412 [_private setCurrentItem:bfItem];
418 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
419 The item that was the target of the user's navigation is designated as the "targetItem".
420 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
421 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
423 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
425 WebHistoryItem *bfItem = [self _createItem: [self parentFrame]?YES:NO];
427 [self _saveScrollPositionToItem:[_private previousItem]];
428 if (!(doClip && self == targetFrame)) {
429 // save frame state for items that aren't loading (khtml doesn't save those)
430 [_private->bridge saveDocumentState];
432 if (_private->children) {
434 for (i = 0; i < [_private->children count]; i++) {
435 WebFrame *child = [_private->children objectAtIndex:i];
436 WebHistoryItem *childItem = [child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip];
437 [bfItem addChildItem:childItem];
441 if (self == targetFrame) {
442 [bfItem setIsTargetItem:YES];
447 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
450 for (i = [_private->children count]-1; i >= 0; i--) {
451 WebFrame *frame = [_private->children objectAtIndex:i];
452 if ([[frame name] isEqualToString:name]) {
459 - (void)_setName:(NSString *)name
461 // It's wrong to name a frame "_blank".
462 if (![name isEqualToString:@"_blank"]) {
463 [_private setName:name];
467 - (BOOL)_isDescendantOfFrame:(WebFrame *)frame
472 NSArray *children = [frame _internalChildFrames];
474 for (i = 0; i < [children count]; i++) {
475 WebFrame *child = [children objectAtIndex:i];
476 if (self == child || [self _isDescendantOfFrame:child]) {
485 return [_private->bridge isFrameSet];
488 - (BOOL)_shouldAllowAccessFrom:(WebFrame *)source
490 // if no source frame, allow access
495 // - allow access if the two frames are in the same window
496 if ([self webView] == [source webView]) {
500 // - allow if the request is made from a local file.
501 NSString *sourceDomain = [[source _bridge] domain];
502 if ([sourceDomain length] == 0) {
506 // - allow access if this frame or one of its ancestors
507 // has the same origin as source
508 WebFrame *ancestor = self;
509 while (ancestor != nil) {
510 NSString *ancestorDomain = [[ancestor _bridge] domain];
511 if (ancestorDomain != nil && [sourceDomain _web_isCaseInsensitiveEqualToString:ancestorDomain]) {
514 ancestor = [ancestor parentFrame];
517 // - allow access if this frame is a toplevel window and the source
518 // can access its opener. Note that we only allow one level of
520 if ([self parentFrame] == nil) {
521 NSString *openerDomain = [[[self _bridge] opener] domain];
522 if (openerDomain != nil && [sourceDomain _web_isCaseInsensitiveEqualToString:openerDomain]) {
527 // otherwise deny access
532 - (WebFrame *)_descendantFrameNamed:(NSString *)name sourceFrame:(WebFrame *)source
534 // for security reasons, we do not want to even make frames visible to frames that
536 if ([[self name] isEqualToString: name] && [self _shouldAllowAccessFrom:source]) {
540 // It's OK to use the internal version of getting the child
541 // frames, since we know this method won't change the set of
543 NSArray *children = [self _internalChildFrames];
547 for (i = 0; i < [children count]; i++){
548 frame = [children objectAtIndex: i];
549 frame = [frame _descendantFrameNamed:name sourceFrame:source];
558 - (void)_detachChildren
560 // Note we have to be careful to remove the kids as we detach each one,
561 // since detaching stops loading, which checks loadComplete, which runs the whole
562 // frame tree, at which point we don't want to trip on already detached kids.
563 if (_private->children) {
565 for (i = [_private->children count]-1; i >=0; i--) {
566 [[_private->children objectAtIndex:i] _detachFromParent];
567 [_private->children removeObjectAtIndex:i];
569 [_private->children release];
570 _private->children = nil;
574 - (void)_closeOldDataSources
576 if (_private->children) {
578 for (i = [_private->children count]-1; i >=0; i--) {
579 [[_private->children objectAtIndex:i] _closeOldDataSources];
582 if (_private->dataSource) {
583 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView willCloseFrame:self];
587 - (void)_detachFromParent
589 WebBridge *bridge = _private->bridge;
590 _private->bridge = nil;
593 [self _saveScrollPositionToItem:[_private currentItem]];
597 [self _detachChildren];
599 [_private setWebView:nil];
600 [_private->webFrameView _setWebView:nil];
601 [_private->dataSource _setWebView:nil];
602 [_private->provisionalDataSource _setWebView:nil];
604 [self _setDataSource:nil];
605 [_private setWebFrameView:nil];
612 - (void)_setDataSource:(WebDataSource *)ds
614 if (ds == nil && _private->dataSource == nil) {
618 ASSERT(ds != _private->dataSource);
620 if (_private->dataSource) {
621 // Make sure that any work that is triggered by resigning first reponder can get done.
622 // The main example where this came up is the textDidEndEditing that is sent to the
623 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
624 // remove the views as a side-effect of freeing the bridge, at which point we can't
625 // post the FormDelegate messages.
627 // Note that this can also take FirstResponder away from a child of our frameView that
628 // is not in a child frame's view. This is OK because we are in the process
629 // of loading new content, which will blow away all editors in this top frame, and if
630 // a non-editor is firstReponder it will not be affected by endEditingFor:.
631 // Potentially one day someone could write a DocView whose editors were not all
632 // replaced by loading new content, but that does not apply currently.
633 NSView *frameView = [self frameView];
634 NSWindow *window = [frameView window];
635 NSResponder *firstResp = [window firstResponder];
636 if ([firstResp isKindOfClass:[NSView class]]
637 && [(NSView *)firstResp isDescendantOf:frameView])
639 [window endEditingFor:firstResp];
642 [self _detachChildren];
644 [_private->dataSource _setWebFrame:nil];
646 ASSERT(!_private->children);
649 [_private setDataSource:ds];
650 [ds _setWebView:[self webView]];
651 [ds _setWebFrame:self];
654 - (void)_setLoadType: (WebFrameLoadType)t
656 [_private setLoadType: t];
659 - (WebFrameLoadType)_loadType
661 return [_private loadType];
664 - (void)_transitionToLayoutAcceptable
666 switch ([self _state]) {
667 case WebFrameStateCommittedPage:
669 [self _setState: WebFrameStateLayoutAcceptable];
670 if (!([[self dataSource] _isDocumentHTML])) {
671 // Go ahead and lay out/display non-HTML the minute we have some data. This makes
672 // more sense for text files (which can always be immediately displayed).
673 WebFrameView *thisView = [self frameView];
674 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
675 ASSERT(thisDocumentView != nil);
676 [thisDocumentView setNeedsLayout:YES];
677 [thisDocumentView layout];
678 [thisDocumentView setNeedsDisplay:YES];
683 case WebFrameStateProvisional:
684 case WebFrameStateComplete:
685 case WebFrameStateLayoutAcceptable:
688 ASSERT_NOT_REACHED();
691 - (void)_makeDocumentView
693 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:_private->dataSource];
698 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
699 WebFrameView *v = _private->webFrameView;
700 [_private->bridge createKHTMLViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
701 [self _updateDrawsBackground];
702 [_private->bridge installInFrame:[v _scrollView]];
704 // Call setDataSource on the document view after it has been placed in the view hierarchy.
705 // This what we for the top-level view, so should do this for views in subframes as well.
706 [documentView setDataSource:_private->dataSource];
709 - (void)_receivedMainResourceError:(NSError *)error
711 if ([self _state] == WebFrameStateProvisional) {
712 NSURL *failedURL = [[_private->provisionalDataSource _originalRequest] URL];
713 // When we are pre-commit, the currentItem is where the pageCache data resides
714 NSDictionary *pageCache = [[_private currentItem] pageCache];
715 [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
716 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
717 [[_private currentItem] setHasPageCache:NO];
721 - (void)_transitionToCommitted: (NSDictionary *)pageCache
723 ASSERT([self webView] != nil);
725 switch ([self _state]) {
726 case WebFrameStateProvisional:
728 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
730 WebFrameLoadType loadType = [self _loadType];
731 if (loadType == WebFrameLoadTypeForward ||
732 loadType == WebFrameLoadTypeBack ||
733 loadType == WebFrameLoadTypeIndexedBackForward ||
734 (loadType == WebFrameLoadTypeReload && [_private->provisionalDataSource unreachableURL] != nil))
736 // Once committed, we want to use current item for saving DocState, and
737 // the provisional item for restoring state.
738 // Note previousItem must be set before we close the URL, which will
739 // happen when the data source is made non-provisional below
740 [_private setPreviousItem:[_private currentItem]];
741 ASSERT([_private provisionalItem]);
742 [_private setCurrentItem:[_private provisionalItem]];
743 [_private setProvisionalItem:nil];
746 // Set the committed data source on the frame.
747 [self _setDataSource:_private->provisionalDataSource];
749 [self _setProvisionalDataSource: nil];
751 [self _setState: WebFrameStateCommittedPage];
753 // Handle adding the URL to the back/forward list.
754 WebDataSource *ds = [self dataSource];
755 WebHistoryItem *entry = nil;
756 NSString *ptitle = [ds pageTitle];
759 case WebFrameLoadTypeForward:
760 case WebFrameLoadTypeBack:
761 case WebFrameLoadTypeIndexedBackForward:
762 if ([[self webView] backForwardList]) {
763 // Must grab the current scroll position before disturbing it
764 [self _saveScrollPositionToItem:[_private previousItem]];
766 // Create a document view for this document, or used the cached view.
768 NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
769 ASSERT(cachedView != nil);
770 [[self frameView] _setDocumentView: cachedView];
773 [self _makeDocumentView];
775 // FIXME - I'm not sure this call does anything. Should be dealt with as
777 [self _restoreScrollPosition];
781 case WebFrameLoadTypeReload:
782 case WebFrameLoadTypeSame:
784 WebHistoryItem *currItem = [_private currentItem];
785 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
786 // FIXME: rjw sez this cache clearing is no longer needed
787 [currItem setHasPageCache:NO];
788 if (loadType == WebFrameLoadTypeReload) {
789 [self _saveScrollPositionToItem:currItem];
791 // Update the last visited time. Mostly interesting for URL autocompletion
793 NSURL *URL = [[[ds _originalRequest] URL] _webkit_canonicalize];
794 WebHistoryItem *oldItem = [[WebHistory optionalSharedHistory] itemForURL:URL];
796 [oldItem _setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate]];
798 [self _makeDocumentView];
802 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
803 case WebFrameLoadTypeReloadAllowingStaleData:
804 [self _makeDocumentView];
807 case WebFrameLoadTypeStandard:
808 if (![ds _isClientRedirect]) {
809 // Add item to history and BF list
810 NSURL *URL = [ds _URLForHistory];
811 if (URL && ![URL _web_isEmpty]){
812 ASSERT([self webView]);
813 if (![[[self webView] preferences] privateBrowsingEnabled]) {
814 entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
816 [entry setTitle: ptitle];
818 [self _addBackForwardItemClippedAtTarget:YES];
822 NSURLRequest *request = [ds request];
824 // update the URL in the BF list that we made before the redirect, unless
825 // this is alternate content for an unreachable URL (we want the BF list
826 // item to remember the unreachable URL in case it becomes reachable later)
827 if ([request _webDataRequestUnreachableURL] == nil) {
828 [[_private currentItem] setURL:[request URL]];
830 // clear out the form data so we don't repost it to the wrong place if we
831 // ever go back/forward to this item
832 [[_private currentItem] _setFormInfoFromRequest:request];
834 // We must also clear out form data so we don't try to restore it into the incoming page,
838 [self _makeDocumentView];
841 case WebFrameLoadTypeInternal:
842 // Add an item to the item tree for this frame
843 ASSERT(![ds _isClientRedirect]);
844 WebFrame *parentFrame = [self parentFrame];
846 WebHistoryItem *parentItem = [parentFrame->_private currentItem];
847 // The only case where parentItem==nil should be when a parent frame loaded an
848 // empty URL, which doesn't set up a current item in that parent.
850 [parentItem addChildItem:[self _createItem: YES]];
853 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
854 // for a top-level frame, but that was a likely explanation for those crashes,
855 // so let's guard against it.
856 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
857 ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
859 [self _makeDocumentView];
862 // FIXME Remove this check when dummy ds is removed. An exception should be thrown
863 // if we're in the WebFrameLoadTypeUninitialized state.
865 ASSERT_NOT_REACHED();
869 // Tell the client we've committed this URL.
870 ASSERT([[self frameView] documentView] != nil);
871 [[self webView] _didCommitLoadForFrame: self];
872 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView didCommitLoadForFrame:self];
874 // If we have a title let the WebView know about it.
876 [entry setTitle:ptitle];
877 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
878 didReceiveTitle:ptitle
884 case WebFrameStateCommittedPage:
885 case WebFrameStateLayoutAcceptable:
886 case WebFrameStateComplete:
889 ASSERT_NOT_REACHED();
894 - (BOOL)_canCachePage
896 return [[[self webView] backForwardList] _usesPageCache];
899 - (void)_purgePageCache
901 // This method implements the rule for purging the page cache.
902 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
903 unsigned pagesCached = 0;
904 WebBackForwardList *backForwardList = [[self webView] backForwardList];
905 NSArray *backList = [backForwardList backListWithLimit: 999999];
906 WebHistoryItem *oldestItem = nil;
909 for (i = 0; i < [backList count]; i++){
910 WebHistoryItem *item = [backList objectAtIndex: i];
911 if ([item hasPageCache]){
912 if (oldestItem == nil)
918 // Snapback items are never directly purged here.
919 if (pagesCached >= sizeLimit && ![oldestItem alwaysAttemptToUsePageCache]){
920 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestItem URL]);
921 [oldestItem setHasPageCache: NO];
925 - (WebFrameState)_state
927 return _private->state;
930 static CFAbsoluteTime _timeOfLastCompletedLoad;
931 + (CFAbsoluteTime)_timeOfLastCompletedLoad
933 return _timeOfLastCompletedLoad;
936 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
938 NSMutableDictionary *pageCache;
940 [item setHasPageCache: YES];
942 if (![_private->bridge saveDocumentToPageCache]){
943 [item setHasPageCache: NO];
947 pageCache = [item pageCache];
948 [[self dataSource] _setStoredInPageCache: YES];
949 [pageCache setObject: [NSDate date] forKey: WebPageCacheEntryDateKey];
950 [pageCache setObject: [self dataSource] forKey: WebPageCacheDataSourceKey];
951 [pageCache setObject: [[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
956 - (void)_setState: (WebFrameState)newState
958 LOG(Loading, "%@: transition from %s to %s", [self name], stateNames[_private->state], stateNames[newState]);
960 LOG(Timing, "%@: transition from %s to %s, %f seconds since start of document load", [self name], stateNames[_private->state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[self webView] mainFrame] dataSource] _loadingStartedTime]);
962 if (newState == WebFrameStateComplete && self == [[self webView] mainFrame]){
963 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[self dataSource] _loadingStartedTime]);
966 _private->state = newState;
968 if (_private->state == WebFrameStateProvisional) {
969 [_private->bridge provisionalLoadStarted];
971 // FIXME: This is OK as long as no one resizes the window,
972 // but in the case where someone does, it means garbage outside
973 // the occupied part of the scroll view.
974 [[[self frameView] _scrollView] setDrawsBackground:NO];
976 // Cache the page, if possible.
977 // Don't write to the cache if in the middle of a redirect, since we will want to
978 // store the final page we end up on.
979 // No point writing to the cache on a reload or loadSame, since we will just write
980 // over it again when we leave that page.
981 WebHistoryItem *item = [_private currentItem];
982 WebFrameLoadType loadType = [self _loadType];
983 if ([self _canCachePage]
984 && [_private->bridge canCachePage]
986 && !_private->quickRedirectComing
987 && loadType != WebFrameLoadTypeReload
988 && loadType != WebFrameLoadTypeReloadAllowingStaleData
989 && loadType != WebFrameLoadTypeSame
990 && ![[self dataSource] isLoading]
991 && ![[self dataSource] _isStopping])
993 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
994 if (![item pageCache]){
996 // Add the items to this page's cache.
997 if ([self _createPageCacheForItem:item]) {
998 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
1000 // See if any page caches need to be purged after the addition of this
1002 [self _purgePageCache];
1005 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
1010 // Put the document into a null state, so it can be restored correctly.
1011 [_private->bridge clear];
1015 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
1019 if (_private->state == WebFrameStateComplete) {
1020 NSScrollView *sv = [[self frameView] _scrollView];
1021 if ([[self webView] drawsBackground])
1022 [sv setDrawsBackground:YES];
1023 [_private setPreviousItem:nil];
1024 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
1026 [[self dataSource] _stopRecordingResponses];
1030 // Called after we send an openURL:... down to WebCore.
1033 if ([self _loadType] == WebFrameLoadTypeStandard && [[self dataSource] _isClientRedirect]) {
1034 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
1035 // khtml has closed the URL and saved away the form state.
1036 WebHistoryItem *item = [_private currentItem];
1037 [item setDocumentState:nil];
1038 [item setScrollPoint:NSZeroPoint];
1041 if ([[self dataSource] _loadingFromPageCache]){
1042 // Force a layout to update view size and thereby update scrollbars.
1043 NSView <WebDocumentView> *view = [[self frameView] documentView];
1044 if ([view isKindOfClass:[WebHTMLView class]]) {
1045 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
1047 [view setNeedsLayout: YES];
1049 [self _restoreScrollPosition];
1051 NSArray *responses = [[self dataSource] _responses];
1052 NSURLResponse *response;
1053 int i, count = [responses count];
1054 for (i = 0; i < count; i++){
1055 response = [responses objectAtIndex: i];
1056 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1059 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
1060 [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
1061 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:[response expectedContentLength] error:error];
1065 // Release the resources kept in the page cache. They will be
1066 // reset when we leave this page. The core side of the page cache
1067 // will have already been invalidated by the bridge to prevent
1068 // premature release.
1069 [[_private currentItem] setHasPageCache: NO];
1071 [[self dataSource] _setPrimaryLoadComplete: YES];
1072 [self _checkLoadCompleteForThisFrame];
1076 - (void)_checkLoadCompleteForThisFrame
1078 ASSERT([self webView] != nil);
1080 switch ([self _state]) {
1081 case WebFrameStateProvisional:
1083 WebDataSource *pd = [self provisionalDataSource];
1085 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
1086 // If we've received any errors we may be stuck in the provisional state and actually
1088 NSError *error = [pd _mainDocumentError];
1090 // Check all children first.
1091 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
1092 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
1093 BOOL shouldReset = YES;
1094 if (![pd isLoading]) {
1095 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
1096 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
1097 _private->delegateIsHandlingProvisionalLoadError = YES;
1098 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1099 didFailProvisionalLoadWithError:error
1101 _private->delegateIsHandlingProvisionalLoadError = NO;
1102 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1105 // Finish resetting the load state, but only if another load hasn't been started by the
1106 // delegate callback.
1107 if (pd == _private->provisionalDataSource) {
1108 [self _setProvisionalDataSource:nil];
1110 [[self webView] _progressCompleted: self];
1112 [self _setState:WebFrameStateComplete];
1114 NSURL *unreachableURL = [_private->provisionalDataSource unreachableURL];
1115 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
1120 if (shouldReset && resetItem != nil) {
1121 [[[self webView] backForwardList] goToItem:resetItem];
1127 case WebFrameStateCommittedPage:
1128 case WebFrameStateLayoutAcceptable:
1130 WebDataSource *ds = [self dataSource];
1132 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
1133 if (![ds isLoading]) {
1134 WebFrameView *thisView = [self frameView];
1135 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1136 ASSERT(thisDocumentView != nil);
1138 // FIXME: need to avoid doing this in the non-HTML case or the bridge may assert.
1139 // Should instead make sure the bridge/part is in the proper state even for
1140 // non-HTML content, or make a call to the document and let it deal with the bridge.
1142 [self _setState:WebFrameStateComplete];
1144 // FIXME: Is this subsequent work important if we already navigated away?
1145 // Maybe there are bugs because of that, or extra work we can skip because
1146 // the new page is ready.
1148 // Tell the just loaded document to layout. This may be necessary
1149 // for non-html content that needs a layout message.
1150 if (!([[self dataSource] _isDocumentHTML])) {
1151 [thisDocumentView setNeedsLayout:YES];
1152 [thisDocumentView layout];
1153 [thisDocumentView setNeedsDisplay:YES];
1156 // If the user had a scroll point scroll to it. This will override
1157 // the anchor point. After much discussion it was decided by folks
1158 // that the user scroll point should override the anchor point.
1159 if ([[self webView] backForwardList]) {
1160 switch ([self _loadType]) {
1161 case WebFrameLoadTypeForward:
1162 case WebFrameLoadTypeBack:
1163 case WebFrameLoadTypeIndexedBackForward:
1164 case WebFrameLoadTypeReload:
1165 [self _restoreScrollPosition];
1168 case WebFrameLoadTypeStandard:
1169 case WebFrameLoadTypeInternal:
1170 case WebFrameLoadTypeReloadAllowingStaleData:
1171 case WebFrameLoadTypeSame:
1176 ASSERT_NOT_REACHED();
1181 NSError *error = [ds _mainDocumentError];
1183 [[self webView] _didFailLoadWithError:error forFrame:self];
1184 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1185 didFailLoadWithError:error
1187 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1189 [[self webView] _didFinishLoadForFrame:self];
1190 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1191 didFinishLoadForFrame:self];
1192 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1195 [[self webView] _progressCompleted: self];
1202 case WebFrameStateComplete:
1204 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
1205 // Even if already complete, we might have set a previous item on a frame that
1206 // didn't do any data loading on the past transaction. Make sure to clear these out.
1207 [_private setPreviousItem:nil];
1212 // Yikes! Serious horkage.
1213 ASSERT_NOT_REACHED();
1216 - (void)_recursiveCheckLoadComplete
1218 // Checking for load complete may indeed alter the set of child
1219 // frames. However, _web_safeMakeObjectsPerformSelector: makes
1220 // sure to copy the array so it is safe against changes.
1221 [[self _internalChildFrames] _web_safeMakeObjectsPerformSelector:@selector(_recursiveCheckLoadComplete)];
1222 [self _checkLoadCompleteForThisFrame];
1225 // Called every time a resource is completely loaded, or an error is received.
1226 - (void)_checkLoadComplete
1228 ASSERT([self webView] != nil);
1230 // Now walk the frame tree to see if any frame that may have initiated a load is done.
1231 [[[self webView] mainFrame] _recursiveCheckLoadComplete];
1234 - (WebBridge *)_bridge
1236 return _private->bridge;
1239 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1241 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1242 WebView *wv = [self webView];
1243 _private->delegateIsHandlingUnimplementablePolicy = YES;
1244 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];
1245 _private->delegateIsHandlingUnimplementablePolicy = NO;
1248 - (void)_clearProvisionalDataSource
1250 [self _setProvisionalDataSource:nil];
1253 // helper method that determines whether the subframes described by the item's subitems
1254 // match our own current frameset
1255 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1257 NSArray *childItems = [item children];
1258 int numChildItems = childItems ? [childItems count] : 0;
1259 int numChildFrames = _private->children ? [_private->children count] : 0;
1260 if (numChildFrames != numChildItems) {
1264 for (i = 0; i < numChildItems; i++) {
1265 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1266 //Search recursive here?
1267 if (![self _immediateChildFrameNamed:itemTargetName]) {
1268 return NO; // couldn't match the i'th itemTarget
1271 return YES; // found matches for all itemTargets
1275 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1277 return !(([currentURL fragment] || [destinationURL fragment]) &&
1278 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1281 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1282 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1284 NSURL *currentURL = [[[self dataSource] request] URL];
1286 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1289 NSArray *childItems = [item children];
1290 WebHistoryItem *childItem;
1291 WebFrame *childFrame;
1292 int i, count = [childItems count];
1293 for (i = 0; i < count; i++){
1294 childItem = [childItems objectAtIndex:i];
1295 childFrame = [self _immediateChildFrameNamed:[childItem target]];
1296 if (![childFrame _URLsMatchItem: childItem])
1303 // loads content into this frame, as specified by item
1304 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1306 NSURL *itemURL = [item URL];
1307 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1308 NSURL *currentURL = [[[self dataSource] request] URL];
1309 NSArray *formData = [item formData];
1311 // Are we navigating to an anchor within the page?
1312 // Note if we have child frames we do a real reload, since the child frames might not
1313 // match our current frame structure, or they might not have the right content. We could
1314 // check for all that as an additional optimization.
1315 // We also do not do anchor-style navigation if we're posting a form.
1317 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1318 // Perhaps they should.
1319 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1322 // FIXME: We need to normalize the code paths for anchor navigation. Something
1323 // like the following line of code should be done, but also accounting for correct
1324 // updates to the back/forward list and scroll position.
1325 // rjw 4/9/03 See 3223929.
1326 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1328 // must do this maintenance here, since we don't go through a real page reload
1329 [self _saveScrollPositionToItem:[_private currentItem]];
1330 // FIXME: form state might want to be saved here too
1332 // FIXME: Perhaps we can use scrollToAnchorWithURL here instead and remove the older scrollToAnchor:?
1333 NSString *anchor = [[item URLString] _web_URLFragment];
1335 [[_private->dataSource _bridge] scrollToAnchor: anchor];
1337 // must do this maintenance here, since we don't go through a real page reload
1338 [_private setCurrentItem:item];
1339 [self _restoreScrollPosition];
1341 // Fake the URL change by updating the datasource's request. This will no longer
1342 // be necessary if we do the better fix described above.
1343 NSMutableURLRequest *hackedRequest = [[[self dataSource] request] mutableCopy];
1344 [hackedRequest setURL: itemURL];
1345 [[self dataSource] __adoptRequest:hackedRequest];
1346 [hackedRequest release];
1348 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1349 didChangeLocationWithinPageForFrame:self];
1350 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1352 // Remember this item so we can traverse any child items as child frames load
1353 [_private setProvisionalItem:item];
1355 WebDataSource *newDataSource;
1356 BOOL inPageCache = NO;
1358 // Check if we'll be using the page cache. We only use the page cache
1359 // if one exists and it is less than _backForwardCacheExpirationInterval
1360 // seconds old. If the cache is expired it gets flushed here.
1361 if ([item hasPageCache]){
1362 NSDictionary *pageCache = [item pageCache];
1363 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1364 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1366 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1367 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1368 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
1372 LOG (PageCache, "Not restoring page from back/forward cache because cache entry has expired, %@ (%3.5f > %3.5f seconds)\n", [[_private provisionalItem] URL], delta, [[[self webView] preferences] _backForwardCacheExpirationInterval]);
1373 [item setHasPageCache: NO];
1378 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1379 [self _addExtraFieldsToRequest:request alwaysFromRequest: (formData != nil)?YES:NO];
1381 // If this was a repost that failed the page cache, we might try to repost the form.
1382 NSDictionary *action;
1384 [request setHTTPMethod:@"POST"];
1385 [request setHTTPReferrer:[item formReferrer]];
1386 webSetHTTPBody(request, formData);
1387 [request setHTTPContentType:[item formContentType]];
1389 // Slight hack to test if the WF cache contains the page we're going to. We want
1390 // to know this before talking to the policy delegate, since it affects whether we
1391 // show the DoYouReallyWantToRepost nag.
1393 // This trick has a small bug (3123893) where we might find a cache hit, but then
1394 // have the item vanish when we try to use it in the ensuing nav. This should be
1395 // extremely rare, but in that case the user will get an error on the navigation.
1396 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1397 NSURLResponse *synchResponse = nil;
1398 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1399 if (synchResponse == nil) {
1401 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1402 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1404 // We can use the cache, don't use navType=resubmit
1405 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1409 case WebFrameLoadTypeReload:
1410 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1412 case WebFrameLoadTypeBack:
1413 case WebFrameLoadTypeForward:
1414 case WebFrameLoadTypeIndexedBackForward:
1415 if (![[itemURL scheme] isEqual:@"https"]) {
1416 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1419 case WebFrameLoadTypeStandard:
1420 case WebFrameLoadTypeInternal:
1421 // no-op: leave as protocol default
1422 // FIXME: I wonder if we ever hit this case
1424 case WebFrameLoadTypeSame:
1425 case WebFrameLoadTypeReloadAllowingStaleData:
1427 ASSERT_NOT_REACHED();
1430 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1433 [self _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1439 // The general idea here is to traverse the frame tree and the item tree in parallel,
1440 // tracking whether each frame already has the content the item requests. If there is
1441 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1442 // reload that frame, and all its kids.
1443 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1445 NSURL *itemURL = [item URL];
1446 NSURL *currentURL = [[[self dataSource] request] URL];
1448 // Always reload the target frame of the item we're going to. This ensures that we will
1449 // do -some- load for the transition, which means a proper notification will be posted
1451 // The exact URL has to match, including fragment. We want to go through the _load
1452 // method, even if to do a within-page navigation.
1453 // The current frame tree and the frame tree snapshot in the item have to match.
1454 if (![item isTargetItem] &&
1455 [itemURL isEqual:currentURL] &&
1456 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1457 [self _childFramesMatchItem:item])
1459 // This content is good, so leave it alone and look for children that need reloading
1461 // Save form state (works from currentItem, since prevItem is nil)
1462 ASSERT(![_private previousItem]);
1463 [_private->bridge saveDocumentState];
1464 [self _saveScrollPositionToItem:[_private currentItem]];
1466 [_private setCurrentItem:item];
1468 // Restore form state (works from currentItem)
1469 [_private->bridge restoreDocumentState];
1470 // Restore the scroll position (taken in favor of going back to the anchor)
1471 [self _restoreScrollPosition];
1473 NSArray *childItems = [item children];
1474 int numChildItems = childItems ? [childItems count] : 0;
1476 for (i = numChildItems - 1; i >= 0; i--) {
1477 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1478 NSString *childName = [childItem target];
1479 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1480 ASSERT(fromChildItem || [fromItem isTargetItem]);
1481 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1483 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1486 // We need to reload the content
1487 [self _loadItem:item withLoadType:type];
1491 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1492 // This includes recursion to handle loading into framesets properly
1493 - (void)_goToItem: (WebHistoryItem *)item withLoadType: (WebFrameLoadType)type
1495 ASSERT(!_private->parent);
1496 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1497 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1498 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1499 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1500 if ([[_private->webView _policyDelegateForwarder] webView:_private->webView shouldGoToHistoryItem:item]) {
1501 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1502 WebHistoryItem *currItem = [backForwardList currentItem];
1503 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1504 // - plus, it only makes sense for the top level of the operation through the frametree,
1505 // as opposed to happening for some/one of the page commits that might happen soon
1506 [backForwardList goToItem:item];
1507 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1511 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
1513 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
1514 [newDataSource _setTriggeringAction:action];
1516 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
1518 [self _loadDataSource:newDataSource withLoadType:loadType formState:formState];
1520 [newDataSource release];
1523 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1525 switch ([event type]) {
1526 case NSLeftMouseDown:
1527 case NSRightMouseDown:
1528 case NSOtherMouseDown:
1530 case NSRightMouseUp:
1531 case NSOtherMouseUp:
1533 NSView *topViewInEventWindow = [[event window] contentView];
1534 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1535 while (viewContainingPoint != nil) {
1536 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1539 viewContainingPoint = [viewContainingPoint superview];
1541 if (viewContainingPoint != nil) {
1542 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1543 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1545 return [NSDictionary dictionaryWithObjectsAndKeys:
1546 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1547 elementInfo, WebActionElementKey,
1548 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1549 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1550 URL, WebActionOriginalURLKey,
1558 return [NSDictionary dictionaryWithObjectsAndKeys:
1559 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1560 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1561 URL, WebActionOriginalURLKey,
1566 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1568 WebNavigationType navType;
1569 if (isFormSubmission) {
1570 navType = WebNavigationTypeFormSubmitted;
1571 } else if (event == nil) {
1572 if (loadType == WebFrameLoadTypeReload) {
1573 navType = WebNavigationTypeReload;
1574 } else if (loadType == WebFrameLoadTypeForward
1575 || loadType == WebFrameLoadTypeBack
1576 || loadType == WebFrameLoadTypeIndexedBackForward) {
1577 navType = WebNavigationTypeBackForward;
1579 navType = WebNavigationTypeOther;
1582 navType = WebNavigationTypeLinkClicked;
1584 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1587 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1589 [_private->listener _invalidate];
1590 [_private->listener release];
1591 _private->listener = nil;
1593 NSURLRequest *request = _private->policyRequest;
1594 NSString *frameName = _private->policyFrameName;
1595 id target = _private->policyTarget;
1596 SEL selector = _private->policySelector;
1597 WebFormState *formState = _private->policyFormState;
1599 _private->policyRequest = nil;
1600 _private->policyFrameName = nil;
1601 _private->policyTarget = nil;
1602 _private->policySelector = nil;
1603 _private->policyFormState = nil;
1607 [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1609 [target performSelector:selector withObject:nil withObject:nil];
1614 [frameName release];
1616 [formState release];
1619 - (void)_setPolicyDataSource:(WebDataSource *)dataSource
1621 [dataSource retain];
1622 [_private->policyDataSource release];
1623 _private->policyDataSource = dataSource;
1626 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1628 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1629 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1631 _private->policyRequest = [request retain];
1632 _private->policyTarget = [target retain];
1633 _private->policyFrameName = [frameName retain];
1634 _private->policySelector = selector;
1635 _private->listener = [listener retain];
1636 _private->policyFormState = [formState retain];
1638 WebView *wv = [self webView];
1639 [[wv _policyDelegateForwarder] webView:wv
1640 decidePolicyForNewWindowAction:action
1642 newFrameName:frameName
1643 decisionListener:listener];
1648 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1650 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1651 NSString *frameName = [[_private->policyFrameName retain] autorelease];
1652 id target = [[_private->policyTarget retain] autorelease];
1653 SEL selector = _private->policySelector;
1654 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1656 // will release _private->policy* objects, hence the above retains
1657 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1659 BOOL shouldContinue = NO;
1662 case WebPolicyIgnore:
1664 case WebPolicyDownload:
1665 // FIXME: should download full request
1666 [[self webView] _downloadURL:[request URL]];
1669 shouldContinue = YES;
1672 ASSERT_NOT_REACHED();
1675 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1678 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1679 dataSource:(WebDataSource *)dataSource
1680 formState:(WebFormState *)formState
1682 withSelector:(SEL)selector
1684 NSDictionary *action = [dataSource _triggeringAction];
1685 if (action == nil) {
1686 action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1687 [dataSource _setTriggeringAction:action];
1690 // Don't ask more than once for the same request or if we are loading an empty URL.
1691 // This avoids confusion on the part of the client.
1692 if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1693 [target performSelector:selector withObject:request withObject:nil];
1697 // We are always willing to show alternate content for unreachable URLs;
1698 // treat it like a reload so it maintains the right state for b/f list.
1699 if ([request _webDataRequestUnreachableURL] != nil) {
1700 if (_private->policyLoadType == WebFrameLoadTypeForward
1701 || _private->policyLoadType == WebFrameLoadTypeBack
1702 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1703 _private->policyLoadType = WebFrameLoadTypeReload;
1705 [target performSelector:selector withObject:request withObject:nil];
1709 [dataSource _setLastCheckedRequest:request];
1711 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1713 ASSERT(_private->policyRequest == nil);
1714 _private->policyRequest = [request retain];
1715 ASSERT(_private->policyTarget == nil);
1716 _private->policyTarget = [target retain];
1717 _private->policySelector = selector;
1718 ASSERT(_private->listener == nil);
1719 _private->listener = [listener retain];
1720 ASSERT(_private->policyFormState == nil);
1721 _private->policyFormState = [formState retain];
1723 WebView *wv = [self webView];
1724 _private->delegateIsDecidingNavigationPolicy = YES;
1725 [[wv _policyDelegateForwarder] webView:wv
1726 decidePolicyForNavigationAction:action
1729 decisionListener:listener];
1730 _private->delegateIsDecidingNavigationPolicy = NO;
1735 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1737 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1738 id target = [[_private->policyTarget retain] autorelease];
1739 SEL selector = _private->policySelector;
1740 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1742 // will release _private->policy* objects, hence the above retains
1743 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1745 BOOL shouldContinue = NO;
1748 case WebPolicyIgnore:
1750 case WebPolicyDownload:
1751 // FIXME: should download full request
1752 [[self webView] _downloadURL:[request URL]];
1755 if (![WebView _canHandleRequest:request]) {
1756 [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1758 shouldContinue = YES;
1762 ASSERT_NOT_REACHED();
1765 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1768 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1774 NSURL *URL = [request URL];
1775 WebDataSource *dataSrc = [self dataSource];
1777 BOOL isRedirect = _private->quickRedirectComing;
1778 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1779 _private->quickRedirectComing = NO;
1781 [dataSrc _setURL:URL];
1782 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1783 // NB: must happen after _setURL, since we add based on the current request.
1784 // Must also happen before we openURL and displace the scroll position, since
1785 // adding the BF item will save away scroll state.
1787 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1788 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1789 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1790 // though its load is not yet done. I think this all works out OK, for one because
1791 // we have already saved away the scroll and doc state for the long slow load,
1792 // but it's not an obvious case.
1793 [self _addBackForwardItemClippedAtTarget:NO];
1796 [_private->bridge scrollToAnchorWithURL:URL];
1799 // This will clear previousItem from the rest of the frame tree tree that didn't
1800 // doing any loading. We need to make a pass on this now, since for anchor nav
1801 // we'll not go through a real load and reach Completed state
1802 [self _checkLoadComplete];
1805 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1806 didChangeLocationWithinPageForFrame:self];
1807 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1810 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request alwaysFromRequest: (BOOL)f
1812 [request setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
1814 // Don't set the cookie policy URL if it's already been set.
1815 if ([request mainDocumentURL] == nil){
1816 if (self == [[self webView] mainFrame] || f) {
1817 [request setMainDocumentURL:[request URL]];
1819 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
1824 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1830 WebView *webView = nil;
1831 WebView *currentWebView = [self webView];
1832 id wd = [currentWebView UIDelegate];
1833 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1834 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1836 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1838 [webView _setTopLevelFrameName:frameName];
1839 [[webView _UIDelegateForwarder] webViewShow:webView];
1840 WebFrame *frame = [webView mainFrame];
1842 [frame _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1846 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1847 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1849 BOOL isFormSubmission = (values != nil);
1851 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1852 [request setHTTPReferrer:referrer];
1853 [self _addExtraFieldsToRequest:request alwaysFromRequest: (event != nil || isFormSubmission)];
1854 if (loadType == WebFrameLoadTypeReload) {
1855 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1858 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1859 // policy of LoadFromOrigin, but I didn't test that.
1860 ASSERT(loadType != WebFrameLoadTypeSame);
1862 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1863 WebFormState *formState = nil;
1864 if (form && values) {
1865 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1868 if (target != nil) {
1869 WebFrame *targetFrame = [self findFrameNamed:target];
1870 if (targetFrame != nil) {
1871 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1873 [self _checkNewWindowPolicyForRequest:request
1878 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1881 [formState release];
1885 WebDataSource *oldDataSource = [[self dataSource] retain];
1887 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1889 // Make sure to do scroll to anchor processing even if the URL is
1890 // exactly the same so pages with '#' links and DHTML side effects
1892 if (!isFormSubmission
1893 && loadType != WebFrameLoadTypeReload
1894 && loadType != WebFrameLoadTypeSame
1895 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1897 // We don't want to just scroll if a link from within a
1898 // frameset is trying to reload the frameset into _top.
1899 && ![_private->bridge isFrameSet]) {
1901 // Just do anchor navigation within the existing content.
1903 // We don't do this if we are submitting a form, explicitly reloading,
1904 // currently displaying a frameset, or if the new URL does not have a fragment.
1905 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1908 // FIXME: What about load types other than Standard and Reload?
1910 [oldDataSource _setTriggeringAction:action];
1911 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1912 [self _checkNavigationPolicyForRequest:request
1913 dataSource:oldDataSource
1916 withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1918 [self _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1919 if (_private->quickRedirectComing) {
1920 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1921 _private->quickRedirectComing = NO;
1923 // need to transfer BF items from the dataSource that we're replacing
1924 WebDataSource *newDataSource = [self provisionalDataSource];
1925 [newDataSource _setIsClientRedirect:YES];
1926 [newDataSource _addBackForwardItems:[oldDataSource _backForwardItems]];
1927 } else if (sameURL) {
1928 // Example of this case are sites that reload the same URL with a different cookie
1929 // driving the generated content, or a master frame with links that drive a target
1930 // frame, where the user has clicked on the same link repeatedly.
1931 [self _setLoadType:WebFrameLoadTypeSame];
1936 [oldDataSource release];
1937 [formState release];
1940 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1942 WebHistoryItem *parentItem = [_private currentItem];
1943 NSArray *childItems = [parentItem children];
1944 WebFrameLoadType loadType = [self _loadType];
1945 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1946 WebHistoryItem *childItem = nil;
1948 // If we're moving in the backforward list, we might want to replace the content
1949 // of this child frame with whatever was there at that point.
1950 // Reload will maintain the frame contents, LoadSame will not.
1952 (loadType == WebFrameLoadTypeForward
1953 || loadType == WebFrameLoadTypeBack
1954 || loadType == WebFrameLoadTypeIndexedBackForward
1955 || loadType == WebFrameLoadTypeReload
1956 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1958 childItem = [parentItem childItemWithName:[childFrame name]];
1960 // Use the original URL to ensure we get all the side-effects, such as
1961 // onLoad handlers, of any redirects that happened. An example of where
1962 // this is needed is Radar 3213556.
1963 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1964 // These behaviors implied by these loadTypes should apply to the child frames
1965 childLoadType = loadType;
1967 if (loadType == WebFrameLoadTypeForward
1968 || loadType == WebFrameLoadTypeBack
1969 || loadType == WebFrameLoadTypeIndexedBackForward)
1971 // For back/forward, remember this item so we can traverse any child items as child frames load
1972 [childFrame->_private setProvisionalItem:childItem];
1974 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1975 [childFrame->_private setCurrentItem:childItem];
1980 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1982 [childFrame loadArchive:archive];
1984 [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1988 - (void)_postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target data:(NSArray *)postData contentType:(NSString *)contentType triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1990 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1991 // This prevents a potential bug which may cause a page with a form that uses itself
1992 // as an action to be returned from the cache without submitting.
1994 // FIXME: Where's the code that implements what the comment above says?
1996 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1997 [self _addExtraFieldsToRequest:request alwaysFromRequest:YES];
1998 [request setHTTPReferrer:referrer];
1999 [request setHTTPMethod:@"POST"];
2000 webSetHTTPBody(request, postData);
2001 [request setHTTPContentType:contentType];
2003 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
2004 WebFormState *formState = nil;
2005 if (form && values) {
2006 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
2009 if (target != nil) {
2010 WebFrame *targetFrame = [self findFrameNamed:target];
2012 if (targetFrame != nil) {
2013 [targetFrame _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
2015 [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2018 [formState release];
2022 [self _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
2025 [formState release];
2028 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
2030 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
2032 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
2033 willPerformClientRedirectToURL:URL
2037 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2038 // load as part of the same navigation.
2040 if (![self dataSource] || isJavaScriptFormAction) {
2041 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
2042 // so we better just treat the redirect as a normal load.
2043 _private->quickRedirectComing = NO;
2044 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2046 _private->quickRedirectComing = lockHistory;
2047 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2051 - (void)_clientRedirectCancelled:(BOOL)cancelWithLoadInProgress
2053 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
2054 didCancelClientRedirectForFrame:self];
2055 if (!cancelWithLoadInProgress)
2056 _private->quickRedirectComing = NO;
2057 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2060 - (void)_saveScrollPositionToItem:(WebHistoryItem *)item
2063 NSView *clipView = [[[self frameView] documentView] superview];
2064 // we might already be detached when this is called from detachFromParent, in which
2065 // case we don't want to override real data earlier gathered with (0,0)
2067 [item setScrollPoint:[clipView bounds].origin];
2072 - (void)_restoreScrollPosition
2074 ASSERT([_private currentItem]);
2075 [[[self frameView] documentView] scrollPoint:[[_private currentItem] scrollPoint]];
2078 - (void)_scrollToTop
2080 [[[self frameView] documentView] scrollPoint: NSZeroPoint];
2083 - (void)_textSizeMultiplierChanged
2085 NSView <WebDocumentView> *view = [[self frameView] documentView];
2086 if ([view conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
2087 [(NSView <_web_WebDocumentTextSizing> *)view _web_textSizeMultiplierChanged];
2090 // It's OK to use the internal version because this method is
2091 // guaranteed not to change the set of frames.
2092 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_textSizeMultiplierChanged)];
2095 - (void)_defersCallbacksChanged
2097 [[self provisionalDataSource] _defersCallbacksChanged];
2098 [[self dataSource] _defersCallbacksChanged];
2101 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
2103 [[[self frameView] documentView] viewWillMoveToHostWindow:hostWindow];
2104 // It's OK to use the internal version because this method is
2105 // guaranteed not to change the set of frames.
2106 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewWillMoveToHostWindow:) withObject:hostWindow];
2109 - (void)_viewDidMoveToHostWindow
2111 [[[self frameView] documentView] viewDidMoveToHostWindow];
2112 // It's OK to use the internal version because this method is
2113 // guaranteed not to change the set of frames.
2114 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewDidMoveToHostWindow)];
2117 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
2119 WebDataSource *dataSource = [self dataSource];
2120 if (dataSource == nil) {
2124 NSMutableURLRequest *request = [[dataSource request] mutableCopy];
2125 NSURL *unreachableURL = [dataSource unreachableURL];
2126 if (unreachableURL != nil) {
2127 [request setURL:unreachableURL];
2129 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
2130 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
2133 [newDataSource _setOverrideEncoding:encoding];
2135 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
2137 [newDataSource release];
2140 - (void)_addChild:(WebFrame *)child
2142 if (_private->children == nil)
2143 _private->children = [[NSMutableArray alloc] init];
2144 [_private->children addObject:child];
2146 child->_private->parent = self;
2147 [[child _bridge] setParent:_private->bridge];
2148 [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
2150 unsigned currentIndex = [_private->children count] - 1;
2151 // we keep track of sibling pointers to avoid the overhead of a lookup in the children array
2153 if (currentIndex > 0) {
2154 WebFrame *previousFrame = [[self childFrames] objectAtIndex: currentIndex - 1];
2155 previousFrame->_private->nextSibling = child;
2156 child->_private->previousSibling = previousFrame;
2157 ASSERT(child->_private->nextSibling == nil);
2162 - (void)_removeChild:(WebFrame *)child
2164 // move corresponding previous and next WebFrame sibling pointers to their new positions
2165 // when we remove a child we may have to reattach the previous frame's next frame and visa versa
2166 if (child->_private->previousSibling) {
2167 child->_private->previousSibling->_private->nextSibling = child->_private->nextSibling;
2170 if (child->_private->nextSibling) {
2171 child->_private->nextSibling->_private->previousSibling = child->_private->previousSibling;
2174 [_private->children removeObject:child];
2175 child->_private->parent = nil;
2178 - (void)_addFramePathToString:(NSMutableString *)path
2180 if ([_private->name hasPrefix:@"<!--framePath "]) {
2181 // we have a generated name - take the path from our name
2182 NSRange ourPathRange = {14, [_private->name length] - 14 - 3};
2183 [path appendString:[_private->name substringWithRange:ourPathRange]];
2185 // we don't have a generated name - just add our simple name to the end
2186 if (_private->parent) {
2187 [_private->parent _addFramePathToString:path];
2189 [path appendString:@"/"];
2190 if (_private->name) {
2191 [path appendString:_private->name];
2196 // Generate a repeatable name for a child about to be added to us. The name must be
2197 // unique within the frame tree. The string we generate includes a "path" of names
2198 // from the root frame down to us. For this path to be unique, each set of siblings must
2199 // contribute a unique name to the path, which can't collide with any HTML-assigned names.
2200 // We generate this path component by index in the child list along with an unlikely frame name.
2201 - (NSString *)_generateFrameName
2203 NSMutableString *path = [NSMutableString stringWithCapacity:256];
2204 [path insertString:@"<!--framePath " atIndex:0];
2205 [self _addFramePathToString:path];
2206 // The new child's path component is all but the 1st char and the last 3 chars
2207 // FIXME: Shouldn't this number be the index of this frame in its parent rather than the child count?
2208 [path appendFormat:@"/<!--frame%d-->-->", _private->children ? [_private->children count] : 0];
2212 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
2213 // item, because we optimistically move it right away at the start of the operation. But when
2214 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
2215 // Return the item that we would reset to, so we can decide later whether to actually reset.
2216 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
2218 WebFrameLoadType loadType = [self _loadType];
2219 if ((loadType == WebFrameLoadTypeForward
2220 || loadType == WebFrameLoadTypeBack
2221 || loadType == WebFrameLoadTypeIndexedBackForward)
2222 && self == [[self webView] mainFrame]) {
2223 return [_private currentItem];
2228 - (WebHistoryItem *)_itemForSavingDocState
2230 // For a standard page load, we will have a previous item set, which will be used to
2231 // store the form state. However, in some cases we will have no previous item, and
2232 // the current item is the right place to save the state. One example is when we
2233 // detach a bunch of frames because we are navigating from a site with frames to
2234 // another site. Another is when saving the frame state of a frame that is not the
2235 // target of the current navigation (if we even decide to save with that granularity).
2237 // Because of previousItem's "masking" of currentItem for this purpose, it's important
2238 // that previousItem be cleared at the end of a page transition. We leverage the
2239 // checkLoadComplete recursion to achieve this goal.
2241 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
2245 - (WebHistoryItem *)_itemForRestoringDocState
2247 switch ([self _loadType]) {
2248 case WebFrameLoadTypeReload:
2249 case WebFrameLoadTypeReloadAllowingStaleData:
2250 case WebFrameLoadTypeSame:
2251 // Don't restore any form state on reload or loadSame
2253 case WebFrameLoadTypeBack:
2254 case WebFrameLoadTypeForward:
2255 case WebFrameLoadTypeIndexedBackForward:
2256 case WebFrameLoadTypeInternal:
2257 case WebFrameLoadTypeStandard:
2258 return [_private currentItem];
2260 ASSERT_NOT_REACHED();
2264 // Walk the frame tree, telling all frames to save their form state into their current
2266 - (void)_saveDocumentAndScrollState
2268 [_private->bridge saveDocumentState];
2269 [self _saveScrollPositionToItem:[_private currentItem]];
2271 // It's OK to use the internal version because this method is
2272 // guaranteed not to change the set of frames.
2273 NSArray *frames = [self _internalChildFrames];
2274 int count = [frames count];
2276 for (i = 0; i < count; i++) {
2277 [[frames objectAtIndex:i] _saveDocumentAndScrollState];
2281 // Called after the FormsDelegate is done processing willSubmitForm:
2282 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
2284 if (_private->listener) {
2285 [_private->listener _invalidate];
2286 [_private->listener release];
2287 _private->listener = nil;
2289 [_private->provisionalDataSource _startLoading];
2292 -(void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
2294 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2295 // nil _private->policyDataSource because loading the alternate page will have passed
2296 // through this method already, nested; otherwise, _private->policyDataSource should still be set.
2297 ASSERT(_private->policyDataSource || [[self provisionalDataSource] unreachableURL] != nil);
2300 [self _setPolicyDataSource:nil];
2304 WebFrameLoadType loadType = _private->policyLoadType;
2305 WebDataSource *dataSource = [_private->policyDataSource retain];
2308 [self _setLoadType:loadType];
2309 [self _setProvisionalDataSource:dataSource];
2310 [dataSource release];
2312 [self _setPolicyDataSource:nil];
2314 // We tell the documentView provisionalDataSourceChanged:
2315 // once it has been created by the WebView.
2317 [self _setState: WebFrameStateProvisional];
2319 if (self == [[self webView] mainFrame])
2320 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2322 WebHistoryItem *item = [_private provisionalItem];
2323 if ((loadType == WebFrameLoadTypeForward ||
2324 loadType == WebFrameLoadTypeBack ||
2325 loadType == WebFrameLoadTypeIndexedBackForward) &&
2326 [item hasPageCache]){
2327 NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2328 if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2329 LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2330 [_private->provisionalDataSource _startLoading: pageCache];
2336 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2337 // mechanism across the willSubmitForm callout.
2338 _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2339 [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2342 [self _continueAfterWillSubmitForm:WebPolicyUse];
2346 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2348 ASSERT([self webView] != nil);
2350 // Unfortunately the view must be non-nil, this is ultimately due
2351 // to KDE parser requiring a KHTMLView. Once we settle on a final
2352 // KDE drop we should fix this dependency.
2354 ASSERT([self frameView] != nil);
2356 _private->policyLoadType = loadType;
2358 WebFrame *parentFrame = [self parentFrame];
2360 [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2362 [newDataSource _setWebView:[self webView]];
2363 [newDataSource _setJustOpenedForTargetedLink:_private->justOpenedForTargetedLink];
2364 _private->justOpenedForTargetedLink = NO;
2366 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2368 [self _setPolicyDataSource:newDataSource];
2370 [self _checkNavigationPolicyForRequest:[newDataSource request]
2371 dataSource:newDataSource
2374 withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2377 - (void)_setJustOpenedForTargetedLink:(BOOL)justOpened
2379 _private->justOpenedForTargetedLink = justOpened;
2382 - (void)_setProvisionalDataSource: (WebDataSource *)d
2384 if (_private->provisionalDataSource != _private->dataSource) {
2385 [_private->provisionalDataSource _setWebFrame:nil];
2387 [_private setProvisionalDataSource: d];
2388 [d _setWebFrame:self];
2391 // used to decide to use loadType=Same
2392 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2394 WebHistoryItem *item = [_private currentItem];
2395 NSString* URLString = [URL _web_originalDataAsString];
2396 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2399 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2401 if (frameName == nil) {
2402 [self loadRequest:request];
2406 WebFrame *frame = [self findFrameNamed:frameName];
2409 [frame loadRequest:request];
2413 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2414 [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2417 // Returns the last child of us and any children, or nil
2418 - (WebFrame *)_lastChild
2420 if (_private->children && [_private->children count]) {
2421 WebFrame *ourLastKid = [_private->children lastObject];
2422 WebFrame *kidsLastKid = [ourLastKid _lastChild];
2423 return kidsLastKid ? kidsLastKid : ourLastKid;
2425 return nil; // no kids
2428 // Return next frame to be traversed, visiting children after parent
2429 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2431 if (_private->children && [_private->children count]) {
2432 return [_private->children objectAtIndex:0];
2433 } else if (_private->parent) {
2435 for (frame = self; frame->_private->parent; frame = frame->_private->parent) {
2436 WebFrame *nextSibling = frame->_private->nextSibling;
2441 return wrapFlag ? frame : nil; // made it all the way to the top
2443 return wrapFlag ? self : nil; // self is the top and we have no kids
2447 // Return previous frame to be traversed, exact reverse order of _nextFrame
2448 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2450 WebFrame *prevSibling = _private->previousSibling;
2452 WebFrame *prevSiblingLastChild = [prevSibling _lastChild];
2453 return prevSiblingLastChild ? prevSiblingLastChild : prevSibling;
2454 } else if (_private->parent) {
2455 return _private->parent;
2457 // no siblings, no parent, self==top
2459 WebFrame *selfLastChild = [self _lastChild];
2460 return selfLastChild ? selfLastChild : self;
2462 // top view is always the last one in this ordering, so prev is nil without wrap
2468 - (void)_setShouldCreateRenderers:(BOOL)f
2470 [_private->bridge setShouldCreateRenderers:f];
2473 - (BOOL)_shouldCreateRenderers
2475 return [_private->bridge shouldCreateRenderers];
2478 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2483 return [[self _bridge] numPendingOrLoadingRequests];
2485 num = [[self _bridge] numPendingOrLoadingRequests];
2486 // It's OK to use the internal version because this method is
2487 // guaranteed not to change the set of frames.
2488 NSArray *children = [self _internalChildFrames];
2489 int i, count = [children count];
2491 for (i = 0; i < count; i++){
2492 child = [children objectAtIndex: 0];
2493 num += [child _numPendingOrLoadingRequests:recurse];
2498 - (NSColor *)_bodyBackgroundColor
2500 return [_private->bridge bodyBackgroundColor];
2503 - (void)_reloadForPluginChanges
2505 NSView <WebDocumentView> *documentView = [[self frameView] documentView];
2506 if ([documentView isKindOfClass:[WebNetscapePluginDocumentView class]] ||
2507 [documentView isKindOfClass:[WebPluginDocumentView class]]) {
2509 } else if ([documentView isKindOfClass:[WebHTMLView class]]) {
2510 NSEnumerator *viewEnumerator = [[documentView subviews] objectEnumerator];
2512 // FIXME: We should ask the frame if it contains plugins, rather
2513 // than doing this check.
2514 while ((view = [viewEnumerator nextObject]) != nil) {
2515 if ([view isKindOfClass:[WebNetscapePluginEmbeddedView class]] ||
2516 [view isKindOfClass:[WebNullPluginView class]] ||
2517 [WebPluginController isPlugInView:view]) {
2523 [[self childFrames] makeObjectsPerformSelector:@selector(_reloadForPluginChanges)];
2527 - (NSArray *)_internalChildFrames
2529 return _private->children;
2534 @implementation WebFrame (WebInternal)
2536 - (void)_updateDrawsBackground
2538 BOOL drawsBackground = [[self webView] drawsBackground];
2539 if (!drawsBackground)
2540 [[[self frameView] _scrollView] setDrawsBackground:NO];
2541 id documentView = [[self frameView] documentView];
2542 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
2543 [documentView setDrawsBackground:drawsBackground];
2544 [[self _bridge] setDrawsBackground:drawsBackground];
2545 [_private->children makeObjectsPerformSelector:@selector(_updateDrawsBackground)];
2548 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2550 _private->internalLoadDelegate = internalLoadDelegate;
2553 - (id)_internalLoadDelegate
2555 return _private->internalLoadDelegate;
2558 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
2560 ASSERT(request != nil);
2562 WebView *wv = [self webView];
2563 id delegate = [wv resourceLoadDelegate];
2564 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2565 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2566 WebDataSource *dataSource = [self dataSource];
2568 if (implementations.delegateImplementsIdentifierForRequest) {
2569 *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2571 *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2574 NSURLRequest *newRequest;
2575 if (implementations.delegateImplementsWillSendRequest) {
2576 newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2578 newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2581 if (newRequest == nil) {
2582 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
2590 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
2592 WebView *wv = [self webView];
2593 id delegate = [wv resourceLoadDelegate];
2594 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2595 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2596 WebDataSource *dataSource = [self dataSource];
2598 if (response != nil) {
2599 if (implementations.delegateImplementsDidReceiveResponse) {
2600 [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2602 [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2607 if (implementations.delegateImplementsDidReceiveContentLength) {
2608 [delegate webView:wv resource:identifier didReceiveContentLength:length fromDataSource:dataSource];
2610 [sharedDelegate webView:wv resource:identifier didReceiveContentLength:length fromDataSource:dataSource];
2615 if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
2616 [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2618 [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2620 [wv _finishedLoadingResourceFromDataSource:dataSource];
2622 [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
2626 - (void)_saveResourceAndSendRemainingDelegateMessagesWithRequest:(NSURLRequest *)request
2627 identifier:(id)identifier
2628 response:(NSURLResponse *)response
2630 error:(NSError *)error
2632 unsigned length = [data length];
2633 if (length > 0 && error == nil) {
2634 ASSERT(request != nil);
2635 WebResource *resource = [[WebResource alloc] _initWithData:data URL:[request URL] response:response];
2636 ASSERT(resource != nil);
2637 [[self dataSource] addSubresource:resource];
2640 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:length error:error];
2643 - (void)_unmarkAllMisspellings
2645 [[self _bridge] unmarkAllMisspellings];
2646 [_private->children makeObjectsPerformSelector:@selector(_unmarkAllMisspellings)];
2651 @implementation WebFormState : NSObject
2653 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2656 _form = [form retain];
2657 _values = [values copy];
2658 _sourceFrame = [sourceFrame retain];
2666 [_sourceFrame release];
2670 - (DOMElement *)form
2675 - (NSDictionary *)values
2680 - (WebFrame *)sourceFrame
2682 return _sourceFrame;
2687 @implementation WebFrame
2691 return [self initWithName:nil webFrameView:nil webView:nil];
2694 - initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2698 _private = [[WebFramePrivate alloc] init];
2700 [self _setWebView:v];
2703 _private->bridge = [[WebBridge alloc] initWithWebFrame:self];
2706 [_private setWebFrameView:fv];
2717 [self _detachFromParent];
2718 [_private->webFrameView _setWebView:nil];
2719 [_private->dataSource _setWebView:nil];
2720 [_private->provisionalDataSource _setWebView:nil];
2731 // FIXME: Should not do this work at finalize time. Need to do it at a predictable time instead.
2732 [self _detachFromParent];
2733 [_private->webFrameView _setWebView:nil];
2734 [_private->dataSource _setWebView:nil];
2735 [_private->provisionalDataSource _setWebView:nil];
2744 return [_private name];
2747 - (WebFrameView *)frameView
2749 return [_private webFrameView];
2752 - (WebView *)webView
2754 return [_private webView];
2757 - (DOMDocument *)DOMDocument
2759 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2762 - (DOMHTMLElement *)frameElement
2764 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2767 - (WebDataSource *)provisionalDataSource
2769 return [_private provisionalDataSource];
2772 - (WebDataSource *)dataSource
2774 return [_private dataSource];
2777 - (void)loadRequest:(NSURLRequest *)request
2779 [self _loadRequest:request subresources:nil subframeArchives:nil];
2782 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2784 NSURLRequest *request = [self _webDataRequestForData:data
2786 textEncodingName:encodingName
2788 unreachableURL:unreachableURL];
2789 [self loadRequest:request];
2793 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2795 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2798 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2800 CFStringEncoding cfencoding = CFStringGetFastestEncoding((CFStringRef)string);
2801 NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
2802 CFStringRef cfencodingName = CFStringConvertEncodingToIANACharSetName(cfencoding);
2804 if (!cfencodingName || nsencoding == kCFStringEncodingInvalidId){
2805 NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
2806 [self _loadData:data MIMEType:nil textEncodingName:@"utf-16" baseURL:URL unreachableURL:unreachableURL];
2809 NSData *data = [string dataUsingEncoding: nsencoding];
2810 [self _loadData:data MIMEType:nil textEncodingName:(NSString *)cfencodingName baseURL:URL unreachableURL:unreachableURL];
2814 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2816 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2819 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2821 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2824 - (void)loadArchive:(WebArchive *)archive
2826 WebResource *mainResource = [archive mainResource];
2828 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2829 MIMEType:[mainResource MIMEType]
2830 textEncodingName:[mainResource textEncodingName]
2831 baseURL:[mainResource URL]
2832 unreachableURL:nil];
2833 [self _loadRequest:request subresources:[archive subresources] subframeArchives:[archive subframeArchives]];
2839 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2840 if (_private->isStoppingLoad) {
2843 _private->isStoppingLoad = YES;
2845 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2847 [_private->provisionalDataSource _stopLoading];
2848 [_private->dataSource _stopLoading];
2850 // Release the provisional data source because there's no point in keeping it around since it is unused in this case.
2851 [self _setProvisionalDataSource:nil];
2853 _private->isStoppingLoad = NO;
2859 WebDataSource *dataSource = [self dataSource];
2860 if (dataSource == nil) {
2864 NSMutableURLRequest *initialRequest = [dataSource request];
2866 // Replace error-page URL with the URL we were trying to reach.
2867 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
2868 if (unreachableURL != nil) {
2869 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
2872 // initWithRequest copies the request
2873 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:initialRequest];
2874 NSMutableURLRequest *request = [newDataSource request];
2876 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
2878 // If we're about to rePOST, set up action so the app can warn the user
2879 if ([[request HTTPMethod] _web_isCaseInsensitiveEqualToString:@"POST"]) {
2880 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
2881 [newDataSource _setTriggeringAction:action];
2884 [newDataSource _setOverrideEncoding:[dataSource _overrideEncoding]];
2886 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
2888 [newDataSource release];
2891 - (WebFrame *)findFrameNamed:(NSString *)name
2893 // First, deal with 'special' names.
2894 if ([name isEqualToString:@"_self"] || [name isEqualToString:@"_current"]){
2898 if ([name isEqualToString:@"_top"]) {
2899 return [[self webView] mainFrame];
2902 if ([name isEqualToString:@"_parent"]) {
2903 WebFrame *parent = [self parentFrame];
2904 return parent ? parent : self;
2907 if ([name isEqualToString:@"_blank"]) {
2911 // Search from this frame down.
2912 WebFrame *frame = [self _descendantFrameNamed:name sourceFrame:self];
2915 // Search in this WebView then in others.
2916 frame = [[self webView] _findFrameNamed:name sourceFrame:self];
2922 - (WebFrame *)parentFrame
2924 return [[_private->parent retain] autorelease];
2927 - (NSArray *)childFrames
2929 return [[_private->children copy] autorelease];