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/WebFrameLoadDelegate.h>
18 #import <WebKit/WebFrameViewInternal.h>
19 #import <WebKit/WebHistoryPrivate.h>
20 #import <WebKit/WebHistoryItemPrivate.h>
21 #import <WebKit/WebHTMLRepresentationPrivate.h>
22 #import <WebKit/WebHTMLViewPrivate.h>
23 #import <WebKit/WebKitErrorsPrivate.h>
24 #import <WebKit/WebKitLogging.h>
25 #import <WebKit/WebKitStatisticsPrivate.h>
26 #import <WebKit/WebNetscapePluginDocumentView.h>
27 #import <WebKit/WebNetscapePluginEmbeddedView.h>
28 #import <WebKit/WebNSObjectExtras.h>
29 #import <WebKit/WebNSURLExtras.h>
30 #import <WebKit/WebNullPluginView.h>
31 #import <WebKit/WebPreferencesPrivate.h>
32 #import <WebKit/WebPlugin.h>
33 #import <WebKit/WebPluginController.h>
34 #import <WebKit/WebPluginDocumentView.h>
35 #import <WebKit/WebResourceLoadDelegate.h>
36 #import <WebKit/WebResourcePrivate.h>
37 #import <WebKit/WebViewInternal.h>
38 #import <WebKit/WebUIDelegate.h>
40 #import <Foundation/NSDictionary_NSURLExtras.h>
41 #import <Foundation/NSString_NSURLExtras.h>
42 #import <Foundation/NSURLRequestPrivate.h>
44 #import <objc/objc-runtime.h>
47 static const char * const stateNames[] = {
48 "WebFrameStateProvisional",
49 "WebFrameStateCommittedPage",
50 "WebFrameStateLayoutAcceptable",
51 "WebFrameStateComplete"
56 Here is the current behavior matrix for four types of navigations:
60 Restore form state: YES
61 Restore scroll and focus state: YES
62 WF Cache policy: NSURLRequestUseProtocolCachePolicy
63 Add to back/forward list: YES
67 Restore form state: YES
68 Restore scroll and focus state: YES
69 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
70 Add to back/forward list: NO
72 Reload (meaning only the reload button):
74 Restore form state: NO
75 Restore scroll and focus state: YES
76 WF Cache policy: NSURLRequestReloadIgnoringCacheData
77 Add to back/forward list: NO
79 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
81 Restore form state: NO
82 Restore scroll and focus state: NO, reset to initial conditions
83 WF Cache policy: NSURLRequestReloadIgnoringCacheData
84 Add to back/forward list: NO
87 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
88 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
89 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
91 @interface NSObject (WebExtraPerformMethod)
93 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3;
97 @implementation NSObject (WebExtraPerformMethod)
99 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3
101 return objc_msgSend(self, aSelector, object1, object2, object3);
106 @interface NSArray (WebSafeMakePerform)
108 - (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector;
113 @implementation NSArray (WebSafeMakePerform)
115 - (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector
117 unsigned count = [self count];
122 [[self copy] makeObjectsPerformSelector:aSelector];
127 [self getObjects:batch range:NSMakeRange(0, count)];
129 for (i = 0; i < count; i++) {
130 objc_msgSend(batch[i], aSelector);
136 // One day we might want to expand the use of this kind of class such that we'd receive one
137 // over the bridge, and possibly hand it on through to the FormsDelegate.
138 // Today it is just used internally to keep some state as we make our way through a bunch
139 // layers while doing a load.
140 @interface WebFormState : NSObject
143 NSDictionary *_values;
144 WebFrame *_sourceFrame;
146 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame;
147 - (DOMElement *)form;
148 - (NSDictionary *)values;
149 - (WebFrame *)sourceFrame;
152 @interface WebFrame (ForwardDecls)
153 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState;
154 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
155 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
157 - (void)_saveScrollPositionToItem:(WebHistoryItem *)item;
158 - (void)_restoreScrollPosition;
159 - (void)_scrollToTop;
161 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
162 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
163 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
166 @implementation WebFramePrivate
175 state = WebFrameStateComplete;
176 loadType = WebFrameLoadTypeStandard;
184 [webFrameView release];
185 [dataSource release];
186 [provisionalDataSource release];
190 [currentItem release];
191 [provisionalItem release];
192 [previousItem release];
194 ASSERT(listener == nil);
195 ASSERT(policyRequest == nil);
196 ASSERT(policyFrameName == nil);
197 ASSERT(policyTarget == nil);
198 ASSERT(policyFormState == nil);
199 ASSERT(policyDataSource == nil);
204 - (NSString *)name { return name; }
205 - (void)setName:(NSString *)n
207 NSString *newName = [n copy];
212 - (WebFrameView *)webFrameView { return webFrameView; }
213 - (void)setWebFrameView: (WebFrameView *)v
216 [webFrameView release];
220 - (WebDataSource *)dataSource { return dataSource; }
221 - (void)setDataSource: (WebDataSource *)d
224 [dataSource release];
228 - (WebView *)webView { return webView; }
229 - (void)setWebView: (WebView *)wv
231 webView = wv; // not retained (yet)
234 - (WebDataSource *)provisionalDataSource { return provisionalDataSource; }
235 - (void)setProvisionalDataSource: (WebDataSource *)d
237 ASSERT(!d || !provisionalDataSource);
239 [provisionalDataSource release];
240 provisionalDataSource = d;
243 - (WebFrameLoadType)loadType { return loadType; }
244 - (void)setLoadType: (WebFrameLoadType)t
249 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
250 - (void)setProvisionalItem: (WebHistoryItem *)item
253 [provisionalItem release];
254 provisionalItem = item;
257 - (WebHistoryItem *)previousItem { return previousItem; }
258 - (void)setPreviousItem:(WebHistoryItem *)item
261 [previousItem release];
265 - (WebHistoryItem *)currentItem { return currentItem; }
266 - (void)setCurrentItem:(WebHistoryItem *)item
269 [currentItem release];
275 @implementation WebFrame (WebPrivate)
277 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
279 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
280 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
281 [request _webDataRequestSetData:data];
282 [request _webDataRequestSetEncoding:encodingName];
283 [request _webDataRequestSetBaseURL:URL];
284 [request _webDataRequestSetUnreachableURL:unreachableURL];
285 [request _webDataRequestSetMIMEType:MIMEType?MIMEType:@"text/html"];
289 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
291 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
292 if (unreachableURL == nil) {
296 if (_private->policyLoadType != WebFrameLoadTypeForward
297 && _private->policyLoadType != WebFrameLoadTypeBack
298 && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
302 // We only treat unreachableURLs specially during the delegate callbacks
303 // for provisional load errors and navigation policy decisions. The former
304 // case handles well-formed URLs that can't be loaded, and the latter
305 // case handles malformed URLs and unknown schemes. Loading alternate content
306 // at other times behaves like a standard load.
307 WebDataSource *compareDataSource = nil;
308 if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
309 compareDataSource = _private->policyDataSource;
310 } else if (_private->delegateIsHandlingProvisionalLoadError) {
311 compareDataSource = [self provisionalDataSource];
314 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
317 - (void)_loadRequest:(NSURLRequest *)request subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
319 WebFrameLoadType loadType;
321 // note this copies request
322 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
323 NSMutableURLRequest *r = [newDataSource request];
324 [self _addExtraFieldsToRequest:r alwaysFromRequest: NO];
325 if ([self _shouldTreatURLAsSameAsCurrent:[request URL]]) {
326 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
327 loadType = WebFrameLoadTypeSame;
329 loadType = WebFrameLoadTypeStandard;
332 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
333 [newDataSource _addSubresources:subresources];
334 [newDataSource _addSubframeArchives:subframeArchives];
336 // When we loading alternate content for an unreachable URL that we're
337 // visiting in the b/f list, we treat it as a reload so the b/f list
338 // is appropriately maintained.
339 if ([self _shouldReloadToHandleUnreachableURLFromRequest:request]) {
340 ASSERT(loadType == WebFrameLoadTypeStandard);
341 loadType = WebFrameLoadTypeReload;
344 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
345 [newDataSource release];
348 - (void)_setWebView:(WebView *)v
350 // To set to nil, we have to use _detachFromParent, not this.
352 [_private setWebView:v];
355 // helper method used in various nav cases below
356 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
358 if ([[self dataSource] _URLForHistory] != nil) {
359 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
360 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
361 [[[self webView] backForwardList] addItem:bfItem];
365 - (WebHistoryItem *)_createItem: (BOOL)useOriginal
367 WebDataSource *dataSrc = [self dataSource];
368 NSURLRequest *request;
369 NSURL *unreachableURL = [dataSrc unreachableURL];
372 WebHistoryItem *bfItem;
375 request = [dataSrc _originalRequest];
377 request = [dataSrc request];
380 if (unreachableURL != nil) {
381 URL = unreachableURL;
382 originalURL = unreachableURL;
385 originalURL = [[dataSrc _originalRequest] URL];
388 LOG (History, "creating item for %@", request);
390 // Frames that have never successfully loaded any content
391 // may have no URL at all. Currently our history code can't
392 // deal with such things, so we nip that in the bud here.
393 // Later we may want to learn to live with nil for URL.
394 // See bug 3368236 and related bugs for more information.
396 URL = [NSURL URLWithString:@"about:blank"];
398 if (originalURL == nil) {
399 originalURL = [NSURL URLWithString:@"about:blank"];
402 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
403 [dataSrc _addBackForwardItem:bfItem];
404 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
406 // save form state if this is a POST
407 [bfItem _setFormInfoFromRequest:request];
409 // Set the item for which we will save document state
410 [_private setPreviousItem:[_private currentItem]];
411 [_private setCurrentItem:bfItem];
417 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
418 The item that was the target of the user's navigation is designated as the "targetItem".
419 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
420 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
422 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
424 WebHistoryItem *bfItem = [self _createItem: [self parentFrame]?YES:NO];
426 [self _saveScrollPositionToItem:[_private previousItem]];
427 if (!(doClip && self == targetFrame)) {
428 // save frame state for items that aren't loading (khtml doesn't save those)
429 [_private->bridge saveDocumentState];
431 if (_private->children) {
433 for (i = 0; i < [_private->children count]; i++) {
434 WebFrame *child = [_private->children objectAtIndex:i];
435 WebHistoryItem *childItem = [child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip];
436 [bfItem addChildItem:childItem];
440 if (self == targetFrame) {
441 [bfItem setIsTargetItem:YES];
446 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
449 for (i = [_private->children count]-1; i >= 0; i--) {
450 WebFrame *frame = [_private->children objectAtIndex:i];
451 if ([[frame name] isEqualToString:name]) {
458 - (void)_setName:(NSString *)name
460 // It's wrong to name a frame "_blank".
461 if (![name isEqualToString:@"_blank"]) {
462 [_private setName:name];
466 - (BOOL)_isDescendantOfFrame:(WebFrame *)frame
471 NSArray *children = [frame _internalChildFrames];
473 for (i = 0; i < [children count]; i++) {
474 WebFrame *child = [children objectAtIndex:i];
475 if (self == child || [self _isDescendantOfFrame:child]) {
484 return [_private->bridge isFrameSet];
487 - (BOOL)_shouldAllowAccessFrom:(WebFrame *)source
489 // if no source frame, allow access
494 // - allow access if the two frames are in the same window
495 if ([self webView] == [source webView]) {
499 // - allow if the request is made from a local file.
500 NSString *sourceDomain = [[source _bridge] domain];
501 if ([sourceDomain length] == 0) {
505 // - allow access if this frame or one of its ancestors
506 // has the same origin as source
507 WebFrame *ancestor = self;
508 while (ancestor != nil) {
509 NSString *ancestorDomain = [[ancestor _bridge] domain];
510 if (ancestorDomain != nil && [sourceDomain _web_isCaseInsensitiveEqualToString:ancestorDomain]) {
513 ancestor = [ancestor parentFrame];
516 // - allow access if this frame is a toplevel window and the source
517 // can access its opener. Note that we only allow one level of
519 if ([self parentFrame] == nil) {
520 NSString *openerDomain = [[[self _bridge] opener] domain];
521 if (openerDomain != nil && [sourceDomain _web_isCaseInsensitiveEqualToString:openerDomain]) {
526 // otherwise deny access
531 - (WebFrame *)_descendantFrameNamed:(NSString *)name sourceFrame:(WebFrame *)source
533 // for security reasons, we do not want to even make frames visible to frames that
535 if ([[self name] isEqualToString: name] && [self _shouldAllowAccessFrom:source]) {
539 // It's OK to use the internal version of getting the child
540 // frames, since we know this method won't change the set of
542 NSArray *children = [self _internalChildFrames];
546 for (i = 0; i < [children count]; i++){
547 frame = [children objectAtIndex: i];
548 frame = [frame _descendantFrameNamed:name sourceFrame:source];
557 - (void)_detachChildren
559 // Note we have to be careful to remove the kids as we detach each one,
560 // since detaching stops loading, which checks loadComplete, which runs the whole
561 // frame tree, at which point we don't want to trip on already detached kids.
562 if (_private->children) {
564 for (i = [_private->children count]-1; i >=0; i--) {
565 [[_private->children objectAtIndex:i] _detachFromParent];
566 [_private->children removeObjectAtIndex:i];
568 [_private->children release];
569 _private->children = nil;
573 - (void)_closeOldDataSources
575 if (_private->children) {
577 for (i = [_private->children count]-1; i >=0; i--) {
578 [[_private->children objectAtIndex:i] _closeOldDataSources];
581 if (_private->dataSource) {
582 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView willCloseFrame:self];
586 - (void)_detachFromParent
588 WebBridge *bridge = _private->bridge;
589 _private->bridge = nil;
592 [self _saveScrollPositionToItem:[_private currentItem]];
596 [self _detachChildren];
598 [_private setWebView:nil];
599 [_private->webFrameView _setWebView:nil];
600 [_private->dataSource _setWebView:nil];
601 [_private->provisionalDataSource _setWebView:nil];
603 [self _setDataSource:nil];
604 [_private setWebFrameView:nil];
611 - (void)_setDataSource:(WebDataSource *)ds
613 if (ds == nil && _private->dataSource == nil) {
617 ASSERT(ds != _private->dataSource);
619 if (_private->dataSource) {
620 // Make sure that any work that is triggered by resigning first reponder can get done.
621 // The main example where this came up is the textDidEndEditing that is sent to the
622 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
623 // remove the views as a side-effect of freeing the bridge, at which point we can't
624 // post the FormDelegate messages.
626 // Note that this can also take FirstResponder away from a child of our frameView that
627 // is not in a child frame's view. This is OK because we are in the process
628 // of loading new content, which will blow away all editors in this top frame, and if
629 // a non-editor is firstReponder it will not be affected by endEditingFor:.
630 // Potentially one day someone could write a DocView whose editors were not all
631 // replaced by loading new content, but that does not apply currently.
632 NSView *frameView = [self frameView];
633 NSWindow *window = [frameView window];
634 NSResponder *firstResp = [window firstResponder];
635 if ([firstResp isKindOfClass:[NSView class]]
636 && [(NSView *)firstResp isDescendantOf:frameView])
638 [window endEditingFor:firstResp];
641 [self _detachChildren];
643 [_private->dataSource _setWebFrame:nil];
645 ASSERT(!_private->children);
648 [_private setDataSource:ds];
649 [ds _setWebView:[self webView]];
650 [ds _setWebFrame:self];
653 - (void)_setLoadType: (WebFrameLoadType)t
655 [_private setLoadType: t];
658 - (WebFrameLoadType)_loadType
660 return [_private loadType];
663 - (void)_transitionToLayoutAcceptable
665 switch ([self _state]) {
666 case WebFrameStateCommittedPage:
668 [self _setState: WebFrameStateLayoutAcceptable];
669 if (!([[self dataSource] _isDocumentHTML])) {
670 // Go ahead and lay out/display non-HTML the minute we have some data. This makes
671 // more sense for text files (which can always be immediately displayed).
672 WebFrameView *thisView = [self frameView];
673 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
674 ASSERT(thisDocumentView != nil);
675 [thisDocumentView setNeedsLayout:YES];
676 [thisDocumentView layout];
677 [thisDocumentView setNeedsDisplay:YES];
682 case WebFrameStateProvisional:
683 case WebFrameStateComplete:
684 case WebFrameStateLayoutAcceptable:
687 ASSERT_NOT_REACHED();
690 - (void)_makeDocumentView
692 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:_private->dataSource];
697 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
698 WebFrameView *v = _private->webFrameView;
699 [_private->bridge createKHTMLViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
700 [self _updateDrawsBackground];
701 [_private->bridge installInFrame:[v _scrollView]];
703 // Call setDataSource on the document view after it has been placed in the view hierarchy.
704 // This what we for the top-level view, so should do this for views in subframes as well.
705 [documentView setDataSource:_private->dataSource];
708 - (void)_receivedMainResourceError:(NSError *)error
710 if ([self _state] == WebFrameStateProvisional) {
711 NSURL *failedURL = [[_private->provisionalDataSource _originalRequest] URL];
712 // When we are pre-commit, the currentItem is where the pageCache data resides
713 NSDictionary *pageCache = [[_private currentItem] pageCache];
714 [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
715 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
716 [[_private currentItem] setHasPageCache:NO];
720 - (void)_transitionToCommitted: (NSDictionary *)pageCache
722 ASSERT([self webView] != nil);
724 switch ([self _state]) {
725 case WebFrameStateProvisional:
727 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
729 WebFrameLoadType loadType = [self _loadType];
730 if (loadType == WebFrameLoadTypeForward ||
731 loadType == WebFrameLoadTypeBack ||
732 loadType == WebFrameLoadTypeIndexedBackForward ||
733 (loadType == WebFrameLoadTypeReload && [_private->provisionalDataSource unreachableURL] != nil))
735 // Once committed, we want to use current item for saving DocState, and
736 // the provisional item for restoring state.
737 // Note previousItem must be set before we close the URL, which will
738 // happen when the data source is made non-provisional below
739 [_private setPreviousItem:[_private currentItem]];
740 ASSERT([_private provisionalItem]);
741 [_private setCurrentItem:[_private provisionalItem]];
742 [_private setProvisionalItem:nil];
745 // Set the committed data source on the frame.
746 [self _setDataSource:_private->provisionalDataSource];
748 [self _setProvisionalDataSource: nil];
750 [self _setState: WebFrameStateCommittedPage];
752 // Handle adding the URL to the back/forward list.
753 WebDataSource *ds = [self dataSource];
754 WebHistoryItem *entry = nil;
755 NSString *ptitle = [ds pageTitle];
758 case WebFrameLoadTypeForward:
759 case WebFrameLoadTypeBack:
760 case WebFrameLoadTypeIndexedBackForward:
761 if ([[self webView] backForwardList]) {
762 // Must grab the current scroll position before disturbing it
763 [self _saveScrollPositionToItem:[_private previousItem]];
765 // Create a document view for this document, or used the cached view.
767 NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
768 ASSERT(cachedView != nil);
769 [[self frameView] _setDocumentView: cachedView];
772 [self _makeDocumentView];
774 // FIXME - I'm not sure this call does anything. Should be dealt with as
776 [self _restoreScrollPosition];
780 case WebFrameLoadTypeReload:
781 case WebFrameLoadTypeSame:
783 WebHistoryItem *currItem = [_private currentItem];
784 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
785 // FIXME: rjw sez this cache clearing is no longer needed
786 [currItem setHasPageCache:NO];
787 if (loadType == WebFrameLoadTypeReload) {
788 [self _saveScrollPositionToItem:currItem];
790 // Update the last visited time. Mostly interesting for URL autocompletion
792 NSURL *URL = [[[ds _originalRequest] URL] _webkit_canonicalize];
793 WebHistoryItem *oldItem = [[WebHistory optionalSharedHistory] itemForURL:URL];
795 [oldItem _setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate]];
797 [self _makeDocumentView];
801 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
802 case WebFrameLoadTypeReloadAllowingStaleData:
803 [self _makeDocumentView];
806 case WebFrameLoadTypeStandard:
807 if (![ds _isClientRedirect]) {
808 // Add item to history and BF list
809 NSURL *URL = [ds _URLForHistory];
810 if (URL && ![URL _web_isEmpty]){
811 ASSERT([self webView]);
812 if (![[[self webView] preferences] privateBrowsingEnabled]) {
813 entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
815 [entry setTitle: ptitle];
817 [self _addBackForwardItemClippedAtTarget:YES];
821 NSURLRequest *request = [ds request];
823 // update the URL in the BF list that we made before the redirect, unless
824 // this is alternate content for an unreachable URL (we want the BF list
825 // item to remember the unreachable URL in case it becomes reachable later)
826 if ([request _webDataRequestUnreachableURL] == nil) {
827 [[_private currentItem] setURL:[request URL]];
829 // clear out the form data so we don't repost it to the wrong place if we
830 // ever go back/forward to this item
831 [[_private currentItem] _setFormInfoFromRequest:request];
833 // We must also clear out form data so we don't try to restore it into the incoming page,
837 [self _makeDocumentView];
840 case WebFrameLoadTypeInternal:
841 // Add an item to the item tree for this frame
842 ASSERT(![ds _isClientRedirect]);
843 WebFrame *parentFrame = [self parentFrame];
845 WebHistoryItem *parentItem = [parentFrame->_private currentItem];
846 // The only case where parentItem==nil should be when a parent frame loaded an
847 // empty URL, which doesn't set up a current item in that parent.
849 [parentItem addChildItem:[self _createItem: YES]];
852 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
853 // for a top-level frame, but that was a likely explanation for those crashes,
854 // so let's guard against it.
855 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
856 ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
858 [self _makeDocumentView];
861 // FIXME Remove this check when dummy ds is removed. An exception should be thrown
862 // if we're in the WebFrameLoadTypeUninitialized state.
864 ASSERT_NOT_REACHED();
868 // Tell the client we've committed this URL.
869 ASSERT([[self frameView] documentView] != nil);
870 [[self webView] _didCommitLoadForFrame: self];
871 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView didCommitLoadForFrame:self];
873 // If we have a title let the WebView know about it.
875 [entry setTitle:ptitle];
876 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
877 didReceiveTitle:ptitle
883 case WebFrameStateCommittedPage:
884 case WebFrameStateLayoutAcceptable:
885 case WebFrameStateComplete:
888 ASSERT_NOT_REACHED();
893 - (BOOL)_canCachePage
895 return [[[self webView] backForwardList] _usesPageCache];
898 - (void)_purgePageCache
900 // This method implements the rule for purging the page cache.
901 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
902 unsigned pagesCached = 0;
903 WebBackForwardList *backForwardList = [[self webView] backForwardList];
904 NSArray *backList = [backForwardList backListWithLimit: 999999];
905 WebHistoryItem *oldestItem = nil;
908 for (i = 0; i < [backList count]; i++){
909 WebHistoryItem *item = [backList objectAtIndex: i];
910 if ([item hasPageCache]){
911 if (oldestItem == nil)
917 // Snapback items are never directly purged here.
918 if (pagesCached >= sizeLimit && ![oldestItem alwaysAttemptToUsePageCache]){
919 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestItem URL]);
920 [oldestItem setHasPageCache: NO];
924 - (WebFrameState)_state
926 return _private->state;
929 static CFAbsoluteTime _timeOfLastCompletedLoad;
930 + (CFAbsoluteTime)_timeOfLastCompletedLoad
932 return _timeOfLastCompletedLoad;
935 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
937 NSMutableDictionary *pageCache;
939 [item setHasPageCache: YES];
941 if (![_private->bridge saveDocumentToPageCache]){
942 [item setHasPageCache: NO];
946 pageCache = [item pageCache];
947 [[self dataSource] _setStoredInPageCache: YES];
948 [pageCache setObject: [NSDate date] forKey: WebPageCacheEntryDateKey];
949 [pageCache setObject: [self dataSource] forKey: WebPageCacheDataSourceKey];
950 [pageCache setObject: [[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
955 - (void)_setState: (WebFrameState)newState
957 LOG(Loading, "%@: transition from %s to %s", [self name], stateNames[_private->state], stateNames[newState]);
959 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]);
961 if (newState == WebFrameStateComplete && self == [[self webView] mainFrame]){
962 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[self dataSource] _loadingStartedTime]);
965 _private->state = newState;
967 if (_private->state == WebFrameStateProvisional) {
968 [_private->bridge provisionalLoadStarted];
970 // FIXME: This is OK as long as no one resizes the window,
971 // but in the case where someone does, it means garbage outside
972 // the occupied part of the scroll view.
973 [[[self frameView] _scrollView] setDrawsBackground:NO];
975 // Cache the page, if possible.
976 // Don't write to the cache if in the middle of a redirect, since we will want to
977 // store the final page we end up on.
978 // No point writing to the cache on a reload or loadSame, since we will just write
979 // over it again when we leave that page.
980 WebHistoryItem *item = [_private currentItem];
981 WebFrameLoadType loadType = [self _loadType];
982 if ([self _canCachePage]
983 && [_private->bridge canCachePage]
985 && !_private->quickRedirectComing
986 && loadType != WebFrameLoadTypeReload
987 && loadType != WebFrameLoadTypeReloadAllowingStaleData
988 && loadType != WebFrameLoadTypeSame
989 && ![[self dataSource] isLoading]
990 && ![[self dataSource] _isStopping])
992 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
993 if (![item pageCache]){
995 // Add the items to this page's cache.
996 if ([self _createPageCacheForItem:item]) {
997 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
999 // See if any page caches need to be purged after the addition of this
1001 [self _purgePageCache];
1004 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
1009 // Put the document into a null state, so it can be restored correctly.
1010 [_private->bridge clear];
1014 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
1018 if (_private->state == WebFrameStateComplete) {
1019 NSScrollView *sv = [[self frameView] _scrollView];
1020 if ([[self webView] drawsBackground])
1021 [sv setDrawsBackground:YES];
1022 [_private setPreviousItem:nil];
1023 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
1027 // Called after we send an openURL:... down to WebCore.
1030 if ([self _loadType] == WebFrameLoadTypeStandard && [[self dataSource] _isClientRedirect]) {
1031 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
1032 // khtml has closed the URL and saved away the form state.
1033 WebHistoryItem *item = [_private currentItem];
1034 [item setDocumentState:nil];
1035 [item setScrollPoint:NSZeroPoint];
1038 if ([[self dataSource] _loadingFromPageCache]){
1039 // Force a layout to update view size and thereby update scrollbars.
1040 NSView <WebDocumentView> *view = [[self frameView] documentView];
1041 if ([view isKindOfClass:[WebHTMLView class]]) {
1042 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
1044 [view setNeedsLayout: YES];
1046 [self _restoreScrollPosition];
1048 NSArray *responses = [[self dataSource] _responses];
1049 NSURLResponse *response;
1050 int i, count = [responses count];
1051 for (i = 0; i < count; i++){
1052 response = [responses objectAtIndex: i];
1053 [self _sendResourceLoadDelegateMessagesForURL:[response URL]
1055 length:[response expectedContentLength]];
1058 // Release the resources kept in the page cache. They will be
1059 // reset when we leave this page. The core side of the page cache
1060 // will have already been invalidated by the bridge to prevent
1061 // premature release.
1062 [[_private currentItem] setHasPageCache: NO];
1064 [[self dataSource] _setPrimaryLoadComplete: YES];
1065 [self _checkLoadCompleteForThisFrame];
1069 - (void)_checkLoadCompleteForThisFrame
1071 ASSERT([self webView] != nil);
1073 switch ([self _state]) {
1074 case WebFrameStateProvisional:
1076 WebDataSource *pd = [self provisionalDataSource];
1078 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
1079 // If we've received any errors we may be stuck in the provisional state and actually
1081 NSError *error = [pd _mainDocumentError];
1083 // Check all children first.
1084 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
1085 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
1086 BOOL shouldReset = YES;
1087 if (![pd isLoading]) {
1088 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
1089 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
1090 _private->delegateIsHandlingProvisionalLoadError = YES;
1091 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1092 didFailProvisionalLoadWithError:error
1094 _private->delegateIsHandlingProvisionalLoadError = NO;
1095 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1098 // Finish resetting the load state, but only if another load hasn't been started by the
1099 // delegate callback.
1100 if (pd == _private->provisionalDataSource) {
1101 [self _setProvisionalDataSource:nil];
1103 [[self webView] _progressCompleted: self];
1105 [self _setState:WebFrameStateComplete];
1107 NSURL *unreachableURL = [_private->provisionalDataSource unreachableURL];
1108 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
1113 if (shouldReset && resetItem != nil) {
1114 [[[self webView] backForwardList] goToItem:resetItem];
1120 case WebFrameStateCommittedPage:
1121 case WebFrameStateLayoutAcceptable:
1123 WebDataSource *ds = [self dataSource];
1125 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
1126 if (![ds isLoading]) {
1127 WebFrameView *thisView = [self frameView];
1128 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1129 ASSERT(thisDocumentView != nil);
1131 // FIXME: need to avoid doing this in the non-HTML case or the bridge may assert.
1132 // Should instead make sure the bridge/part is in the proper state even for
1133 // non-HTML content, or make a call to the document and let it deal with the bridge.
1135 [self _setState:WebFrameStateComplete];
1137 // FIXME: Is this subsequent work important if we already navigated away?
1138 // Maybe there are bugs because of that, or extra work we can skip because
1139 // the new page is ready.
1141 // Tell the just loaded document to layout. This may be necessary
1142 // for non-html content that needs a layout message.
1143 if (!([[self dataSource] _isDocumentHTML])) {
1144 [thisDocumentView setNeedsLayout:YES];
1145 [thisDocumentView layout];
1146 [thisDocumentView setNeedsDisplay:YES];
1149 // If the user had a scroll point scroll to it. This will override
1150 // the anchor point. After much discussion it was decided by folks
1151 // that the user scroll point should override the anchor point.
1152 if ([[self webView] backForwardList]) {
1153 switch ([self _loadType]) {
1154 case WebFrameLoadTypeForward:
1155 case WebFrameLoadTypeBack:
1156 case WebFrameLoadTypeIndexedBackForward:
1157 case WebFrameLoadTypeReload:
1158 [self _restoreScrollPosition];
1161 case WebFrameLoadTypeStandard:
1162 case WebFrameLoadTypeInternal:
1163 case WebFrameLoadTypeReloadAllowingStaleData:
1164 case WebFrameLoadTypeSame:
1169 ASSERT_NOT_REACHED();
1174 NSError *error = [ds _mainDocumentError];
1176 [[self webView] _didFailLoadWithError:error forFrame:self];
1177 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1178 didFailLoadWithError:error
1180 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1182 [[self webView] _didFinishLoadForFrame:self];
1183 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1184 didFinishLoadForFrame:self];
1185 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1188 [[self webView] _progressCompleted: self];
1195 case WebFrameStateComplete:
1197 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
1198 // Even if already complete, we might have set a previous item on a frame that
1199 // didn't do any data loading on the past transaction. Make sure to clear these out.
1200 [_private setPreviousItem:nil];
1205 // Yikes! Serious horkage.
1206 ASSERT_NOT_REACHED();
1209 - (void)_recursiveCheckLoadComplete
1211 // Checking for load complete may indeed alter the set of child
1212 // frames. However, _web_safeMakeObjectsPerformSelector: makes
1213 // sure to copy the array so it is safe against changes.
1214 [[self _internalChildFrames] _web_safeMakeObjectsPerformSelector:@selector(_recursiveCheckLoadComplete)];
1215 [self _checkLoadCompleteForThisFrame];
1218 // Called every time a resource is completely loaded, or an error is received.
1219 - (void)_checkLoadComplete
1221 ASSERT([self webView] != nil);
1223 // Now walk the frame tree to see if any frame that may have initiated a load is done.
1224 [[[self webView] mainFrame] _recursiveCheckLoadComplete];
1227 - (WebBridge *)_bridge
1229 return _private->bridge;
1232 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1234 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1235 WebView *wv = [self webView];
1236 _private->delegateIsHandlingUnimplementablePolicy = YES;
1237 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];
1238 _private->delegateIsHandlingUnimplementablePolicy = NO;
1241 - (void)_clearProvisionalDataSource
1243 [self _setProvisionalDataSource:nil];
1246 // helper method that determines whether the subframes described by the item's subitems
1247 // match our own current frameset
1248 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1250 NSArray *childItems = [item children];
1251 int numChildItems = childItems ? [childItems count] : 0;
1252 int numChildFrames = _private->children ? [_private->children count] : 0;
1253 if (numChildFrames != numChildItems) {
1257 for (i = 0; i < numChildItems; i++) {
1258 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1259 //Search recursive here?
1260 if (![self _immediateChildFrameNamed:itemTargetName]) {
1261 return NO; // couldn't match the i'th itemTarget
1264 return YES; // found matches for all itemTargets
1268 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1270 return !(([currentURL fragment] || [destinationURL fragment]) &&
1271 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1274 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1275 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1277 NSURL *currentURL = [[[self dataSource] request] URL];
1279 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1282 NSArray *childItems = [item children];
1283 WebHistoryItem *childItem;
1284 WebFrame *childFrame;
1285 int i, count = [childItems count];
1286 for (i = 0; i < count; i++){
1287 childItem = [childItems objectAtIndex:i];
1288 childFrame = [self _immediateChildFrameNamed:[childItem target]];
1289 if (![childFrame _URLsMatchItem: childItem])
1296 // loads content into this frame, as specified by item
1297 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1299 NSURL *itemURL = [item URL];
1300 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1301 NSURL *currentURL = [[[self dataSource] request] URL];
1302 NSArray *formData = [item formData];
1304 // Are we navigating to an anchor within the page?
1305 // Note if we have child frames we do a real reload, since the child frames might not
1306 // match our current frame structure, or they might not have the right content. We could
1307 // check for all that as an additional optimization.
1308 // We also do not do anchor-style navigation if we're posting a form.
1310 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1311 // Perhaps they should.
1312 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1315 // FIXME: We need to normalize the code paths for anchor navigation. Something
1316 // like the following line of code should be done, but also accounting for correct
1317 // updates to the back/forward list and scroll position.
1318 // rjw 4/9/03 See 3223929.
1319 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1321 // must do this maintenance here, since we don't go through a real page reload
1322 [self _saveScrollPositionToItem:[_private currentItem]];
1323 // FIXME: form state might want to be saved here too
1325 // FIXME: Perhaps we can use scrollToAnchorWithURL here instead and remove the older scrollToAnchor:?
1326 NSString *anchor = [[item URLString] _web_URLFragment];
1328 [[_private->dataSource _bridge] scrollToAnchor: anchor];
1330 // must do this maintenance here, since we don't go through a real page reload
1331 [_private setCurrentItem:item];
1332 [self _restoreScrollPosition];
1334 // Fake the URL change by updating the datasource's request. This will no longer
1335 // be necessary if we do the better fix described above.
1336 NSMutableURLRequest *hackedRequest = [[[self dataSource] request] mutableCopy];
1337 [hackedRequest setURL: itemURL];
1338 [[self dataSource] __adoptRequest:hackedRequest];
1339 [hackedRequest release];
1341 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1342 didChangeLocationWithinPageForFrame:self];
1343 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1345 // Remember this item so we can traverse any child items as child frames load
1346 [_private setProvisionalItem:item];
1348 WebDataSource *newDataSource;
1349 BOOL inPageCache = NO;
1351 // Check if we'll be using the page cache. We only use the page cache
1352 // if one exists and it is less than _backForwardCacheExpirationInterval
1353 // seconds old. If the cache is expired it gets flushed here.
1354 if ([item hasPageCache]){
1355 NSDictionary *pageCache = [item pageCache];
1356 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1357 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1359 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1360 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1361 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
1365 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]);
1366 [item setHasPageCache: NO];
1371 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1372 [self _addExtraFieldsToRequest:request alwaysFromRequest: (formData != nil)?YES:NO];
1374 // If this was a repost that failed the page cache, we might try to repost the form.
1375 NSDictionary *action;
1377 [request setHTTPMethod:@"POST"];
1378 [request setHTTPReferrer:[item formReferrer]];
1380 // FIXME: This will have to be expanded to handle filenames and arrays with more than one element to fix file uploading.
1381 if ([formData count] == 1 && [[formData objectAtIndex:0] isKindOfClass:[NSData class]]) {
1382 [request setHTTPBody:(NSData *)[formData objectAtIndex:0]];
1383 [request setHTTPContentType:[item formContentType]];
1386 // Slight hack to test if the WF cache contains the page we're going to. We want
1387 // to know this before talking to the policy delegate, since it affects whether we
1388 // show the DoYouReallyWantToRepost nag.
1390 // This trick has a small bug (3123893) where we might find a cache hit, but then
1391 // have the item vanish when we try to use it in the ensuing nav. This should be
1392 // extremely rare, but in that case the user will get an error on the navigation.
1393 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1394 NSURLResponse *synchResponse = nil;
1395 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1396 if (synchResponse == nil) {
1398 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1399 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1401 // We can use the cache, don't use navType=resubmit
1402 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1406 case WebFrameLoadTypeReload:
1407 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1409 case WebFrameLoadTypeBack:
1410 case WebFrameLoadTypeForward:
1411 case WebFrameLoadTypeIndexedBackForward:
1412 if (![[itemURL scheme] isEqual:@"https"]) {
1413 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1416 case WebFrameLoadTypeStandard:
1417 case WebFrameLoadTypeInternal:
1418 // no-op: leave as protocol default
1419 // FIXME: I wonder if we ever hit this case
1421 case WebFrameLoadTypeSame:
1422 case WebFrameLoadTypeReloadAllowingStaleData:
1424 ASSERT_NOT_REACHED();
1427 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1430 [self _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1436 // The general idea here is to traverse the frame tree and the item tree in parallel,
1437 // tracking whether each frame already has the content the item requests. If there is
1438 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1439 // reload that frame, and all its kids.
1440 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1442 NSURL *itemURL = [item URL];
1443 NSURL *currentURL = [[[self dataSource] request] URL];
1445 // Always reload the target frame of the item we're going to. This ensures that we will
1446 // do -some- load for the transition, which means a proper notification will be posted
1448 // The exact URL has to match, including fragment. We want to go through the _load
1449 // method, even if to do a within-page navigation.
1450 // The current frame tree and the frame tree snapshot in the item have to match.
1451 if (![item isTargetItem] &&
1452 [itemURL isEqual:currentURL] &&
1453 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1454 [self _childFramesMatchItem:item])
1456 // This content is good, so leave it alone and look for children that need reloading
1458 // Save form state (works from currentItem, since prevItem is nil)
1459 ASSERT(![_private previousItem]);
1460 [_private->bridge saveDocumentState];
1461 [self _saveScrollPositionToItem:[_private currentItem]];
1463 [_private setCurrentItem:item];
1465 // Restore form state (works from currentItem)
1466 [_private->bridge restoreDocumentState];
1467 // Restore the scroll position (taken in favor of going back to the anchor)
1468 [self _restoreScrollPosition];
1470 NSArray *childItems = [item children];
1471 int numChildItems = childItems ? [childItems count] : 0;
1473 for (i = numChildItems - 1; i >= 0; i--) {
1474 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1475 NSString *childName = [childItem target];
1476 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1477 ASSERT(fromChildItem || [fromItem isTargetItem]);
1478 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1480 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1483 // We need to reload the content
1484 [self _loadItem:item withLoadType:type];
1488 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1489 // This includes recursion to handle loading into framesets properly
1490 - (void)_goToItem: (WebHistoryItem *)item withLoadType: (WebFrameLoadType)type
1492 ASSERT(!_private->parent);
1493 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1494 WebHistoryItem *currItem = [backForwardList currentItem];
1495 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1496 // - plus, it only makes sense for the top level of the operation through the frametree,
1497 // as opposed to happening for some/one of the page commits that might happen soon
1498 [backForwardList goToItem:item];
1499 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1502 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
1504 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
1505 [newDataSource _setTriggeringAction:action];
1507 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
1509 [self _loadDataSource:newDataSource withLoadType:loadType formState:formState];
1511 [newDataSource release];
1514 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1516 switch ([event type]) {
1517 case NSLeftMouseDown:
1518 case NSRightMouseDown:
1519 case NSOtherMouseDown:
1521 case NSRightMouseUp:
1522 case NSOtherMouseUp:
1524 NSView *topViewInEventWindow = [[event window] contentView];
1525 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1526 while (viewContainingPoint != nil) {
1527 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1530 viewContainingPoint = [viewContainingPoint superview];
1532 if (viewContainingPoint != nil) {
1533 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1534 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1536 return [NSDictionary dictionaryWithObjectsAndKeys:
1537 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1538 elementInfo, WebActionElementKey,
1539 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1540 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1541 URL, WebActionOriginalURLKey,
1549 return [NSDictionary dictionaryWithObjectsAndKeys:
1550 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1551 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1552 URL, WebActionOriginalURLKey,
1557 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1559 WebNavigationType navType;
1560 if (isFormSubmission) {
1561 navType = WebNavigationTypeFormSubmitted;
1562 } else if (event == nil) {
1563 if (loadType == WebFrameLoadTypeReload) {
1564 navType = WebNavigationTypeReload;
1565 } else if (loadType == WebFrameLoadTypeForward
1566 || loadType == WebFrameLoadTypeBack
1567 || loadType == WebFrameLoadTypeIndexedBackForward) {
1568 navType = WebNavigationTypeBackForward;
1570 navType = WebNavigationTypeOther;
1573 navType = WebNavigationTypeLinkClicked;
1575 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1578 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1580 [_private->listener _invalidate];
1581 [_private->listener release];
1582 _private->listener = nil;
1584 NSURLRequest *request = _private->policyRequest;
1585 NSString *frameName = _private->policyFrameName;
1586 id target = _private->policyTarget;
1587 SEL selector = _private->policySelector;
1588 WebFormState *formState = _private->policyFormState;
1590 _private->policyRequest = nil;
1591 _private->policyFrameName = nil;
1592 _private->policyTarget = nil;
1593 _private->policySelector = nil;
1594 _private->policyFormState = nil;
1598 [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1600 [target performSelector:selector withObject:nil withObject:nil];
1605 [frameName release];
1607 [formState release];
1610 - (void)_setPolicyDataSource:(WebDataSource *)dataSource
1612 [dataSource retain];
1613 [_private->policyDataSource release];
1614 _private->policyDataSource = dataSource;
1617 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1619 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1620 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1622 _private->policyRequest = [request retain];
1623 _private->policyTarget = [target retain];
1624 _private->policyFrameName = [frameName retain];
1625 _private->policySelector = selector;
1626 _private->listener = [listener retain];
1627 _private->policyFormState = [formState retain];
1629 WebView *wv = [self webView];
1630 [[wv _policyDelegateForwarder] webView:wv
1631 decidePolicyForNewWindowAction:action
1633 newFrameName:frameName
1634 decisionListener:listener];
1639 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1641 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1642 NSString *frameName = [[_private->policyFrameName retain] autorelease];
1643 id target = [[_private->policyTarget retain] autorelease];
1644 SEL selector = _private->policySelector;
1645 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1647 // will release _private->policy* objects, hence the above retains
1648 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1650 BOOL shouldContinue = NO;
1653 case WebPolicyIgnore:
1655 case WebPolicyDownload:
1656 // FIXME: should download full request
1657 [[self webView] _downloadURL:[request URL]];
1660 shouldContinue = YES;
1663 ASSERT_NOT_REACHED();
1666 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1669 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1670 dataSource:(WebDataSource *)dataSource
1671 formState:(WebFormState *)formState
1673 withSelector:(SEL)selector
1675 NSDictionary *action = [dataSource _triggeringAction];
1676 if (action == nil) {
1677 action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1678 [dataSource _setTriggeringAction:action];
1681 // Don't ask more than once for the same request or if we are loading an empty URL.
1682 // This avoids confusion on the part of the client.
1683 if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1684 [target performSelector:selector withObject:request withObject:nil];
1688 // We are always willing to show alternate content for unreachable URLs;
1689 // treat it like a reload so it maintains the right state for b/f list.
1690 if ([request _webDataRequestUnreachableURL] != nil) {
1691 if (_private->policyLoadType == WebFrameLoadTypeForward
1692 || _private->policyLoadType == WebFrameLoadTypeBack
1693 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1694 _private->policyLoadType = WebFrameLoadTypeReload;
1696 [target performSelector:selector withObject:request withObject:nil];
1700 [dataSource _setLastCheckedRequest:request];
1702 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1704 ASSERT(_private->policyRequest == nil);
1705 _private->policyRequest = [request retain];
1706 ASSERT(_private->policyTarget == nil);
1707 _private->policyTarget = [target retain];
1708 _private->policySelector = selector;
1709 ASSERT(_private->listener == nil);
1710 _private->listener = [listener retain];
1711 ASSERT(_private->policyFormState == nil);
1712 _private->policyFormState = [formState retain];
1714 WebView *wv = [self webView];
1715 _private->delegateIsDecidingNavigationPolicy = YES;
1716 [[wv _policyDelegateForwarder] webView:wv
1717 decidePolicyForNavigationAction:action
1720 decisionListener:listener];
1721 _private->delegateIsDecidingNavigationPolicy = NO;
1726 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1728 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1729 id target = [[_private->policyTarget retain] autorelease];
1730 SEL selector = _private->policySelector;
1731 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1733 // will release _private->policy* objects, hence the above retains
1734 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1736 BOOL shouldContinue = NO;
1739 case WebPolicyIgnore:
1741 case WebPolicyDownload:
1742 // FIXME: should download full request
1743 [[self webView] _downloadURL:[request URL]];
1746 if (![WebView _canHandleRequest:request]) {
1747 [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1749 shouldContinue = YES;
1753 ASSERT_NOT_REACHED();
1756 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1759 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1765 NSURL *URL = [request URL];
1766 WebDataSource *dataSrc = [self dataSource];
1768 BOOL isRedirect = _private->quickRedirectComing;
1769 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1770 _private->quickRedirectComing = NO;
1772 [dataSrc _setURL:URL];
1773 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1774 // NB: must happen after _setURL, since we add based on the current request.
1775 // Must also happen before we openURL and displace the scroll position, since
1776 // adding the BF item will save away scroll state.
1778 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1779 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1780 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1781 // though its load is not yet done. I think this all works out OK, for one because
1782 // we have already saved away the scroll and doc state for the long slow load,
1783 // but it's not an obvious case.
1784 [self _addBackForwardItemClippedAtTarget:NO];
1787 [_private->bridge scrollToAnchorWithURL:URL];
1790 // This will clear previousItem from the rest of the frame tree tree that didn't
1791 // doing any loading. We need to make a pass on this now, since for anchor nav
1792 // we'll not go through a real load and reach Completed state
1793 [self _checkLoadComplete];
1796 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
1797 didChangeLocationWithinPageForFrame:self];
1798 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1801 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request alwaysFromRequest: (BOOL)f
1803 [request setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
1805 // Don't set the cookie policy URL if it's already been set.
1806 if ([request mainDocumentURL] == nil){
1807 if (self == [[self webView] mainFrame] || f) {
1808 [request setMainDocumentURL:[request URL]];
1810 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
1815 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1821 WebView *webView = nil;
1822 WebView *currentWebView = [self webView];
1823 id wd = [currentWebView UIDelegate];
1824 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1825 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1827 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1829 [webView _setTopLevelFrameName:frameName];
1830 [[webView _UIDelegateForwarder] webViewShow:webView];
1831 WebFrame *frame = [webView mainFrame];
1833 [frame _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1837 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1838 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1840 BOOL isFormSubmission = (values != nil);
1842 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1843 [request setHTTPReferrer:referrer];
1844 [self _addExtraFieldsToRequest:request alwaysFromRequest: (event != nil || isFormSubmission)];
1845 if (loadType == WebFrameLoadTypeReload) {
1846 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1849 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1850 // policy of LoadFromOrigin, but I didn't test that.
1851 ASSERT(loadType != WebFrameLoadTypeSame);
1853 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1854 WebFormState *formState = nil;
1855 if (form && values) {
1856 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1859 if (target != nil) {
1860 WebFrame *targetFrame = [self findFrameNamed:target];
1861 if (targetFrame != nil) {
1862 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1864 [self _checkNewWindowPolicyForRequest:request
1869 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1872 [formState release];
1876 WebDataSource *oldDataSource = [[self dataSource] retain];
1878 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1880 // Make sure to do scroll to anchor processing even if the URL is
1881 // exactly the same so pages with '#' links and DHTML side effects
1883 if (!isFormSubmission
1884 && loadType != WebFrameLoadTypeReload
1885 && loadType != WebFrameLoadTypeSame
1886 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1888 // We don't want to just scroll if a link from within a
1889 // frameset is trying to reload the frameset into _top.
1890 && ![_private->bridge isFrameSet]) {
1892 // Just do anchor navigation within the existing content.
1894 // We don't do this if we are submitting a form, explicitly reloading,
1895 // currently displaying a frameset, or if the new URL does not have a fragment.
1896 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1899 // FIXME: What about load types other than Standard and Reload?
1901 [oldDataSource _setTriggeringAction:action];
1902 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1903 [self _checkNavigationPolicyForRequest:request
1904 dataSource:oldDataSource
1907 withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1909 [self _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1910 if (_private->quickRedirectComing) {
1911 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1912 _private->quickRedirectComing = NO;
1914 // need to transfer BF items from the dataSource that we're replacing
1915 WebDataSource *newDataSource = [self provisionalDataSource];
1916 [newDataSource _setIsClientRedirect:YES];
1917 [newDataSource _addBackForwardItems:[oldDataSource _backForwardItems]];
1918 } else if (sameURL) {
1919 // Example of this case are sites that reload the same URL with a different cookie
1920 // driving the generated content, or a master frame with links that drive a target
1921 // frame, where the user has clicked on the same link repeatedly.
1922 [self _setLoadType:WebFrameLoadTypeSame];
1927 [oldDataSource release];
1928 [formState release];
1931 - (void)_loadURL:(NSURL *)URL intoChild:(WebFrame *)childFrame
1933 WebHistoryItem *parentItem = [_private currentItem];
1934 NSArray *childItems = [parentItem children];
1935 WebFrameLoadType loadType = [self _loadType];
1936 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1937 WebHistoryItem *childItem = nil;
1939 // If we're moving in the backforward list, we might want to replace the content
1940 // of this child frame with whatever was there at that point.
1941 // Reload will maintain the frame contents, LoadSame will not.
1943 (loadType == WebFrameLoadTypeForward
1944 || loadType == WebFrameLoadTypeBack
1945 || loadType == WebFrameLoadTypeIndexedBackForward
1946 || loadType == WebFrameLoadTypeReload
1947 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1949 childItem = [parentItem childItemWithName:[childFrame name]];
1951 // Use the original URL to ensure we get all the side-effects, such as
1952 // onLoad handlers, of any redirects that happened. An example of where
1953 // this is needed is Radar 3213556.
1954 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1955 // These behaviors implied by these loadTypes should apply to the child frames
1956 childLoadType = loadType;
1958 if (loadType == WebFrameLoadTypeForward
1959 || loadType == WebFrameLoadTypeBack
1960 || loadType == WebFrameLoadTypeIndexedBackForward)
1962 // For back/forward, remember this item so we can traverse any child items as child frames load
1963 [childFrame->_private setProvisionalItem:childItem];
1965 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1966 [childFrame->_private setCurrentItem:childItem];
1971 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1973 [childFrame loadArchive:archive];
1975 // FIXME: is this the right referrer?
1976 [childFrame _loadURL:URL referrer:[[self _bridge] referrer] loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1980 - (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
1982 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1983 // This prevents a potential bug which may cause a page with a form that uses itself
1984 // as an action to be returned from the cache without submitting.
1986 // FIXME: Where's the code that implements what the comment above says?
1988 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1989 [self _addExtraFieldsToRequest:request alwaysFromRequest:YES];
1990 [request setHTTPReferrer:referrer];
1991 [request setHTTPMethod:@"POST"];
1993 // FIXME: This will have to be expanded to handle filenames and arrays with more than one element to fix file uploading.
1994 if ([postData count] == 1 && [[postData objectAtIndex:0] isKindOfClass:[NSData class]]) {
1995 [request setHTTPBody:(NSData *)[postData objectAtIndex:0]];
1996 [request setHTTPContentType:contentType];
1999 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
2000 WebFormState *formState = nil;
2001 if (form && values) {
2002 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
2005 if (target != nil) {
2006 WebFrame *targetFrame = [self findFrameNamed:target];
2008 if (targetFrame != nil) {
2009 [targetFrame _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
2011 [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2014 [formState release];
2018 [self _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
2021 [formState release];
2024 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
2026 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
2028 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
2029 willPerformClientRedirectToURL:URL
2033 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2034 // load as part of the same navigation.
2036 if (![self dataSource] || isJavaScriptFormAction) {
2037 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
2038 // so we better just treat the redirect as a normal load.
2039 _private->quickRedirectComing = NO;
2040 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2042 _private->quickRedirectComing = lockHistory;
2043 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2047 - (void)_clientRedirectCancelled:(BOOL)cancelWithLoadInProgress
2049 [[[self webView] _frameLoadDelegateForwarder] webView:_private->webView
2050 didCancelClientRedirectForFrame:self];
2051 if (!cancelWithLoadInProgress)
2052 _private->quickRedirectComing = NO;
2053 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2056 - (void)_saveScrollPositionToItem:(WebHistoryItem *)item
2059 NSView *clipView = [[[self frameView] documentView] superview];
2060 // we might already be detached when this is called from detachFromParent, in which
2061 // case we don't want to override real data earlier gathered with (0,0)
2063 [item setScrollPoint:[clipView bounds].origin];
2068 - (void)_restoreScrollPosition
2070 ASSERT([_private currentItem]);
2071 [[[self frameView] documentView] scrollPoint:[[_private currentItem] scrollPoint]];
2074 - (void)_scrollToTop
2076 [[[self frameView] documentView] scrollPoint: NSZeroPoint];
2079 - (void)_textSizeMultiplierChanged
2081 NSView <WebDocumentView> *view = [[self frameView] documentView];
2082 if ([view conformsToProtocol:@protocol(_web_WebDocumentTextSizing)]) {
2083 [(NSView <_web_WebDocumentTextSizing> *)view _web_textSizeMultiplierChanged];
2086 // It's OK to use the internal version because this method is
2087 // guaranteed not to change the set of frames.
2088 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_textSizeMultiplierChanged)];
2091 - (void)_defersCallbacksChanged
2093 [[self provisionalDataSource] _defersCallbacksChanged];
2094 [[self dataSource] _defersCallbacksChanged];
2097 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
2099 [[[self frameView] documentView] viewWillMoveToHostWindow:hostWindow];
2100 // It's OK to use the internal version because this method is
2101 // guaranteed not to change the set of frames.
2102 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewWillMoveToHostWindow:) withObject:hostWindow];
2105 - (void)_viewDidMoveToHostWindow
2107 [[[self frameView] documentView] viewDidMoveToHostWindow];
2108 // It's OK to use the internal version because this method is
2109 // guaranteed not to change the set of frames.
2110 [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewDidMoveToHostWindow)];
2113 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
2115 WebDataSource *dataSource = [self dataSource];
2116 if (dataSource == nil) {
2120 NSMutableURLRequest *request = [[dataSource request] mutableCopy];
2121 NSURL *unreachableURL = [dataSource unreachableURL];
2122 if (unreachableURL != nil) {
2123 [request setURL:unreachableURL];
2125 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
2126 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
2129 [newDataSource _setOverrideEncoding:encoding];
2131 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
2133 [newDataSource release];
2136 - (void)_addChild:(WebFrame *)child
2138 if (_private->children == nil)
2139 _private->children = [[NSMutableArray alloc] init];
2140 [_private->children addObject:child];
2142 child->_private->parent = self;
2143 [[child _bridge] setParent:_private->bridge];
2144 [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
2146 unsigned currentIndex = [_private->children count] - 1;
2147 // we keep track of sibling pointers to avoid the overhead of a lookup in the children array
2149 if (currentIndex > 0) {
2150 WebFrame *previousFrame = [[self childFrames] objectAtIndex: currentIndex - 1];
2151 previousFrame->_private->nextSibling = child;
2152 child->_private->previousSibling = previousFrame;
2153 ASSERT(child->_private->nextSibling == nil);
2158 - (void)_removeChild:(WebFrame *)child
2160 // move corresponding previous and next WebFrame sibling pointers to their new positions
2161 // when we remove a child we may have to reattach the previous frame's next frame and visa versa
2162 if (child->_private->previousSibling) {
2163 child->_private->previousSibling->_private->nextSibling = child->_private->nextSibling;
2166 if (child->_private->nextSibling) {
2167 child->_private->nextSibling->_private->previousSibling = child->_private->previousSibling;
2170 [_private->children removeObject:child];
2171 child->_private->parent = nil;
2174 - (void)_addFramePathToString:(NSMutableString *)path
2176 if ([_private->name hasPrefix:@"<!--framePath "]) {
2177 // we have a generated name - take the path from our name
2178 NSRange ourPathRange = {14, [_private->name length] - 14 - 3};
2179 [path appendString:[_private->name substringWithRange:ourPathRange]];
2181 // we don't have a generated name - just add our simple name to the end
2182 if (_private->parent) {
2183 [_private->parent _addFramePathToString:path];
2185 [path appendString:@"/"];
2186 if (_private->name) {
2187 [path appendString:_private->name];
2192 // Generate a repeatable name for a child about to be added to us. The name must be
2193 // unique within the frame tree. The string we generate includes a "path" of names
2194 // from the root frame down to us. For this path to be unique, each set of siblings must
2195 // contribute a unique name to the path, which can't collide with any HTML-assigned names.
2196 // We generate this path component by index in the child list along with an unlikely frame name.
2197 - (NSString *)_generateFrameName
2199 NSMutableString *path = [NSMutableString stringWithCapacity:256];
2200 [path insertString:@"<!--framePath " atIndex:0];
2201 [self _addFramePathToString:path];
2202 // The new child's path component is all but the 1st char and the last 3 chars
2203 // FIXME: Shouldn't this number be the index of this frame in its parent rather than the child count?
2204 [path appendFormat:@"/<!--frame%d-->-->", _private->children ? [_private->children count] : 0];
2208 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
2209 // item, because we optimistically move it right away at the start of the operation. But when
2210 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
2211 // Return the item that we would reset to, so we can decide later whether to actually reset.
2212 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
2214 WebFrameLoadType loadType = [self _loadType];
2215 if ((loadType == WebFrameLoadTypeForward
2216 || loadType == WebFrameLoadTypeBack
2217 || loadType == WebFrameLoadTypeIndexedBackForward)
2218 && self == [[self webView] mainFrame]) {
2219 return [_private currentItem];
2224 - (WebHistoryItem *)_itemForSavingDocState
2226 // For a standard page load, we will have a previous item set, which will be used to
2227 // store the form state. However, in some cases we will have no previous item, and
2228 // the current item is the right place to save the state. One example is when we
2229 // detach a bunch of frames because we are navigating from a site with frames to
2230 // another site. Another is when saving the frame state of a frame that is not the
2231 // target of the current navigation (if we even decide to save with that granularity).
2233 // Because of previousItem's "masking" of currentItem for this purpose, it's important
2234 // that previousItem be cleared at the end of a page transition. We leverage the
2235 // checkLoadComplete recursion to achieve this goal.
2237 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
2241 - (WebHistoryItem *)_itemForRestoringDocState
2243 switch ([self _loadType]) {
2244 case WebFrameLoadTypeReload:
2245 case WebFrameLoadTypeReloadAllowingStaleData:
2246 case WebFrameLoadTypeSame:
2247 // Don't restore any form state on reload or loadSame
2249 case WebFrameLoadTypeBack:
2250 case WebFrameLoadTypeForward:
2251 case WebFrameLoadTypeIndexedBackForward:
2252 case WebFrameLoadTypeInternal:
2253 case WebFrameLoadTypeStandard:
2254 return [_private currentItem];
2256 ASSERT_NOT_REACHED();
2260 // Walk the frame tree, telling all frames to save their form state into their current
2262 - (void)_saveDocumentAndScrollState
2264 [_private->bridge saveDocumentState];
2265 [self _saveScrollPositionToItem:[_private currentItem]];
2267 // It's OK to use the internal version because this method is
2268 // guaranteed not to change the set of frames.
2269 NSArray *frames = [self _internalChildFrames];
2270 int count = [frames count];
2272 for (i = 0; i < count; i++) {
2273 [[frames objectAtIndex:i] _saveDocumentAndScrollState];
2277 // Called after the FormsDelegate is done processing willSubmitForm:
2278 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
2280 if (_private->listener) {
2281 [_private->listener _invalidate];
2282 [_private->listener release];
2283 _private->listener = nil;
2285 [_private->provisionalDataSource _startLoading];
2288 -(void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
2290 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2291 // nil _private->policyDataSource because loading the alternate page will have passed
2292 // through this method already, nested; otherwise, _private->policyDataSource should still be set.
2293 ASSERT(_private->policyDataSource || [[self provisionalDataSource] unreachableURL] != nil);
2296 [self _setPolicyDataSource:nil];
2300 WebFrameLoadType loadType = _private->policyLoadType;
2301 WebDataSource *dataSource = [_private->policyDataSource retain];
2304 [self _setLoadType:loadType];
2305 [self _setProvisionalDataSource:dataSource];
2306 [dataSource release];
2308 [self _setPolicyDataSource:nil];
2310 // We tell the documentView provisionalDataSourceChanged:
2311 // once it has been created by the WebView.
2313 [self _setState: WebFrameStateProvisional];
2315 if (self == [[self webView] mainFrame])
2316 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2318 WebHistoryItem *item = [_private provisionalItem];
2319 if ((loadType == WebFrameLoadTypeForward ||
2320 loadType == WebFrameLoadTypeBack ||
2321 loadType == WebFrameLoadTypeIndexedBackForward) &&
2322 [item hasPageCache]){
2323 NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2324 if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2325 LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2326 [_private->provisionalDataSource _startLoading: pageCache];
2332 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2333 // mechanism across the willSubmitForm callout.
2334 _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2335 [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2338 [self _continueAfterWillSubmitForm:WebPolicyUse];
2342 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2344 ASSERT([self webView] != nil);
2346 // Unfortunately the view must be non-nil, this is ultimately due
2347 // to KDE parser requiring a KHTMLView. Once we settle on a final
2348 // KDE drop we should fix this dependency.
2350 ASSERT([self frameView] != nil);
2352 _private->policyLoadType = loadType;
2354 WebFrame *parentFrame = [self parentFrame];
2356 [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2358 [newDataSource _setWebView:[self webView]];
2359 [newDataSource _setJustOpenedForTargetedLink:_private->justOpenedForTargetedLink];
2360 _private->justOpenedForTargetedLink = NO;
2362 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2364 [self _setPolicyDataSource:newDataSource];
2366 [self _checkNavigationPolicyForRequest:[newDataSource request]
2367 dataSource:newDataSource
2370 withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2373 - (void)_setJustOpenedForTargetedLink:(BOOL)justOpened
2375 _private->justOpenedForTargetedLink = justOpened;
2378 - (void)_setProvisionalDataSource: (WebDataSource *)d
2380 if (_private->provisionalDataSource != _private->dataSource) {
2381 [_private->provisionalDataSource _setWebFrame:nil];
2383 [_private setProvisionalDataSource: d];
2384 [d _setWebFrame:self];
2387 // used to decide to use loadType=Same
2388 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2390 WebHistoryItem *item = [_private currentItem];
2391 NSString* URLString = [URL _web_originalDataAsString];
2392 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2395 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2397 if (frameName == nil) {
2398 [self loadRequest:request];
2402 WebFrame *frame = [self findFrameNamed:frameName];
2405 [frame loadRequest:request];
2409 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2410 [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2413 // Returns the last child of us and any children, or nil
2414 - (WebFrame *)_lastChild
2416 if (_private->children && [_private->children count]) {
2417 WebFrame *ourLastKid = [_private->children lastObject];
2418 WebFrame *kidsLastKid = [ourLastKid _lastChild];
2419 return kidsLastKid ? kidsLastKid : ourLastKid;
2421 return nil; // no kids
2424 // Return next frame to be traversed, visiting children after parent
2425 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2427 if (_private->children && [_private->children count]) {
2428 return [_private->children objectAtIndex:0];
2429 } else if (_private->parent) {
2431 for (frame = self; frame->_private->parent; frame = frame->_private->parent) {
2432 WebFrame *nextSibling = frame->_private->nextSibling;
2437 return wrapFlag ? frame : nil; // made it all the way to the top
2439 return wrapFlag ? self : nil; // self is the top and we have no kids
2443 // Return previous frame to be traversed, exact reverse order of _nextFrame
2444 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2446 WebFrame *prevSibling = _private->previousSibling;
2448 WebFrame *prevSiblingLastChild = [prevSibling _lastChild];
2449 return prevSiblingLastChild ? prevSiblingLastChild : prevSibling;
2450 } else if (_private->parent) {
2451 return _private->parent;
2453 // no siblings, no parent, self==top
2455 WebFrame *selfLastChild = [self _lastChild];
2456 return selfLastChild ? selfLastChild : self;
2458 // top view is always the last one in this ordering, so prev is nil without wrap
2464 - (void)_setShouldCreateRenderers:(BOOL)f
2466 [_private->bridge setShouldCreateRenderers:f];
2469 - (BOOL)_shouldCreateRenderers
2471 return [_private->bridge shouldCreateRenderers];
2474 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2479 return [[self _bridge] numPendingOrLoadingRequests];
2481 num = [[self _bridge] numPendingOrLoadingRequests];
2482 // It's OK to use the internal version because this method is
2483 // guaranteed not to change the set of frames.
2484 NSArray *children = [self _internalChildFrames];
2485 int i, count = [children count];
2487 for (i = 0; i < count; i++){
2488 child = [children objectAtIndex: 0];
2489 num += [child _numPendingOrLoadingRequests:recurse];
2494 - (NSColor *)_bodyBackgroundColor
2496 return [_private->bridge bodyBackgroundColor];
2499 - (void)_reloadForPluginChanges
2501 NSView <WebDocumentView> *documentView = [[self frameView] documentView];
2502 if ([documentView isKindOfClass:[WebNetscapePluginDocumentView class]] ||
2503 [documentView isKindOfClass:[WebPluginDocumentView class]]) {
2505 } else if ([documentView isKindOfClass:[WebHTMLView class]]) {
2506 NSEnumerator *viewEnumerator = [[documentView subviews] objectEnumerator];
2508 // FIXME: We should ask the frame if it contains plugins, rather
2509 // than doing this check.
2510 while ((view = [viewEnumerator nextObject]) != nil) {
2511 if ([view isKindOfClass:[WebNetscapePluginEmbeddedView class]] ||
2512 [view isKindOfClass:[WebNullPluginView class]] ||
2513 [WebPluginController isPlugInView:view]) {
2519 [[self childFrames] makeObjectsPerformSelector:@selector(_reloadForPluginChanges)];
2523 - (NSArray *)_internalChildFrames
2525 return _private->children;
2530 @implementation WebFrame (WebInternal)
2532 - (void)_updateDrawsBackground
2534 [[self _bridge] setDrawsBackground:[[self webView] drawsBackground]];
2535 [_private->children makeObjectsPerformSelector:@selector(_updateDrawsBackground)];
2538 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2540 _private->internalLoadDelegate = internalLoadDelegate;
2543 - (id)_internalLoadDelegate
2545 return _private->internalLoadDelegate;
2548 - (void)_sendResourceLoadDelegateMessagesForURL:(NSURL *)URL response:(NSURLResponse *)response length:(unsigned)length
2550 ASSERT(response != nil);
2552 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL];
2553 WebView *wv = [self webView];
2554 id delegate = [wv resourceLoadDelegate];
2555 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2557 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2558 WebDataSource *dataSource = [self dataSource];
2560 // No chance for delegate to modify request, so we don't send a willSendRequest:redirectResponse: message.
2561 if (implementations.delegateImplementsIdentifierForRequest)
2562 identifier = [delegate webView:wv identifierForInitialRequest: request fromDataSource:dataSource];
2564 identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2566 if (implementations.delegateImplementsDidReceiveResponse)
2567 [delegate webView:wv resource: identifier didReceiveResponse: response fromDataSource:dataSource];
2569 [sharedDelegate webView:wv resource: identifier didReceiveResponse: response fromDataSource:dataSource];
2571 if (implementations.delegateImplementsDidReceiveContentLength)
2572 [delegate webView:wv resource: identifier didReceiveContentLength:length fromDataSource:dataSource];
2574 [sharedDelegate webView:wv resource: identifier didReceiveContentLength:length fromDataSource:dataSource];
2576 if (implementations.delegateImplementsDidFinishLoadingFromDataSource)
2577 [delegate webView:wv resource: identifier didFinishLoadingFromDataSource:dataSource];
2579 [sharedDelegate webView:wv resource: identifier didFinishLoadingFromDataSource:dataSource];
2581 [wv _finishedLoadingResourceFromDataSource:dataSource];
2588 @implementation WebFormState : NSObject
2590 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2593 _form = [form retain];
2594 _values = [values copy];
2595 _sourceFrame = [sourceFrame retain];
2603 [_sourceFrame release];
2607 - (DOMElement *)form
2612 - (NSDictionary *)values
2617 - (WebFrame *)sourceFrame
2619 return _sourceFrame;
2624 @implementation WebFrame
2628 return [self initWithName:nil webFrameView:nil webView:nil];
2631 - initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2635 _private = [[WebFramePrivate alloc] init];
2637 [self _setWebView:v];
2640 _private->bridge = [[WebBridge alloc] initWithWebFrame:self];
2643 [_private setWebFrameView:fv];
2654 [self _detachFromParent];
2655 [_private->webFrameView _setWebView:nil];
2656 [_private->dataSource _setWebView:nil];
2657 [_private->provisionalDataSource _setWebView:nil];
2668 // FIXME: Should not do this work at finalize time. Need to do it at a predictable time instead.
2669 [self _detachFromParent];
2670 [_private->webFrameView _setWebView:nil];
2671 [_private->dataSource _setWebView:nil];
2672 [_private->provisionalDataSource _setWebView:nil];
2681 return [_private name];
2684 - (WebFrameView *)frameView
2686 return [_private webFrameView];
2689 - (WebView *)webView
2691 return [_private webView];
2694 - (DOMDocument *)DOMDocument
2696 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2699 - (DOMHTMLElement *)frameElement
2701 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2704 - (WebDataSource *)provisionalDataSource
2706 return [_private provisionalDataSource];
2709 - (WebDataSource *)dataSource
2711 return [_private dataSource];
2714 - (void)loadRequest:(NSURLRequest *)request
2716 [self _loadRequest:request subresources:nil subframeArchives:nil];
2719 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2721 NSURLRequest *request = [self _webDataRequestForData:data
2723 textEncodingName:encodingName
2725 unreachableURL:unreachableURL];
2726 [self loadRequest:request];
2730 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2732 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2735 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2737 CFStringEncoding cfencoding = CFStringGetFastestEncoding((CFStringRef)string);
2738 NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
2739 CFStringRef cfencodingName = CFStringConvertEncodingToIANACharSetName(cfencoding);
2741 if (!cfencodingName || nsencoding == kCFStringEncodingInvalidId){
2742 NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
2743 [self _loadData:data MIMEType:nil textEncodingName:@"utf-16" baseURL:URL unreachableURL:unreachableURL];
2746 NSData *data = [string dataUsingEncoding: nsencoding];
2747 [self _loadData:data MIMEType:nil textEncodingName:(NSString *)cfencodingName baseURL:URL unreachableURL:unreachableURL];
2751 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2753 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2756 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2758 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2761 - (void)loadArchive:(WebArchive *)archive
2763 WebResource *mainResource = [archive mainResource];
2765 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2766 MIMEType:[mainResource MIMEType]
2767 textEncodingName:[mainResource textEncodingName]
2768 baseURL:[mainResource URL]
2769 unreachableURL:nil];
2770 [self _loadRequest:request subresources:[archive subresources] subframeArchives:[archive subframeArchives]];
2776 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2777 if (_private->isStoppingLoad) {
2780 _private->isStoppingLoad = YES;
2782 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2784 [_private->provisionalDataSource _stopLoading];
2785 [_private->dataSource _stopLoading];
2787 // Release the provisional data source because there's no point in keeping it around since it is unused in this case.
2788 [self _setProvisionalDataSource:nil];
2790 _private->isStoppingLoad = NO;
2796 WebDataSource *dataSource = [self dataSource];
2797 if (dataSource == nil) {
2801 NSMutableURLRequest *initialRequest = [dataSource request];
2803 // Replace error-page URL with the URL we were trying to reach.
2804 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
2805 if (unreachableURL != nil) {
2806 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
2809 // initWithRequest copies the request
2810 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:initialRequest];
2811 NSMutableURLRequest *request = [newDataSource request];
2813 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
2815 // If we're about to rePOST, set up action so the app can warn the user
2816 if ([[request HTTPMethod] _web_isCaseInsensitiveEqualToString:@"POST"]) {
2817 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
2818 [newDataSource _setTriggeringAction:action];
2821 [newDataSource _setOverrideEncoding:[dataSource _overrideEncoding]];
2823 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
2825 [newDataSource release];
2828 - (WebFrame *)findFrameNamed:(NSString *)name
2830 // First, deal with 'special' names.
2831 if ([name isEqualToString:@"_self"] || [name isEqualToString:@"_current"]){
2835 if ([name isEqualToString:@"_top"]) {
2836 return [[self webView] mainFrame];
2839 if ([name isEqualToString:@"_parent"]) {
2840 WebFrame *parent = [self parentFrame];
2841 return parent ? parent : self;
2844 if ([name isEqualToString:@"_blank"]) {
2848 // Search from this frame down.
2849 WebFrame *frame = [self _descendantFrameNamed:name sourceFrame:self];
2852 // Search in this WebView then in others.
2853 frame = [[self webView] _findFrameNamed:name sourceFrame:self];
2859 - (WebFrame *)parentFrame
2861 return [[_private->parent retain] autorelease];
2864 - (NSArray *)childFrames
2866 return [[_private->children copy] autorelease];