+2006-10-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin.
+
+ - move remaining movable data fields from WebFrameLoader to WebFrame
+
+ * Loader/WebDocumentLoadState.m:
+ (-[WebDocumentLoadState commitIfReady]):
+ * Loader/WebFrameLoader.h:
+ * Loader/WebFrameLoader.m:
+ (-[WebFrameLoader provisionalLoadStarted]):
+ (-[WebFrameLoader _setState:]):
+ (-[WebFrameLoader stopLoadingSubframes]):
+ (-[WebFrameLoader stopLoading]):
+ (-[WebFrameLoader startLoading]):
+ (-[WebFrameLoader _receivedMainResourceError:complete:]):
+ (-[WebFrameLoader clientRedirectCancelledOrFinished:]):
+ (-[WebFrameLoader clientRedirectedTo:delay:fireDate:lockHistory:isJavaScriptFormAction:]):
+ (-[WebFrameLoader shouldReloadForCurrent:andDestination:]):
+ (-[WebFrameLoader loadURL:referrer:loadType:target:triggeringEvent:form:formValues:]):
+ (-[WebFrameLoader continueFragmentScrollAfterNavigationPolicy:formState:]):
+ (-[WebFrameLoader closeOldDataSources]):
+ (-[WebFrameLoader commitProvisionalLoad:]):
+ (-[WebFrameLoader continueLoadRequestAfterNavigationPolicy:formState:]):
+ (-[WebFrameLoader isQuickRedirectComing]):
+ * Loader/WebFrameLoaderClient.h:
+ * WebCoreSupport/WebFrameBridge.h:
+ * WebCoreSupport/WebFrameBridge.m:
+ (-[WebFrameBridge frameLoader]):
+ (-[WebFrameBridge setTitle:]):
+ (-[WebFrameBridge reportClientRedirectToURL:delay:fireDate:lockHistory:isJavaScriptFormAction:]):
+ (-[WebFrameBridge reportClientRedirectCancelled:]):
+ (-[WebFrameBridge loadURL:referrer:reload:userGesture:target:triggeringEvent:form:formValues:]):
+ * WebView/WebDataSource.m:
+ (-[WebDataSource _loadFromPageCache:]):
+ * WebView/WebFrame.m:
+ (-[NSView setWebFrame::]):
+ (-[WebFrame _addHistoryItemForFragmentScroll]):
+ (-[WebFrame _didFinishLoad]):
+ (-[WebFrame _provisionalLoadStarted]):
+ (-[WebFrame _checkLoadCompleteForThisFrame]):
+ (-[WebFrame _loadItem:withLoadType:]):
+ (-[WebFrame _loadURL:referrer:intoChild:]):
+ (-[WebFrame _frameLoadCompleted]):
+ (-[WebFrame stopLoading]):
+ (-[WebFrame _invalidateCurrentItemPageCache]):
+ * WebView/WebFrameInternal.h:
+
2006-10-08 Darin Adler <darin@apple.com>
Rubber stamped by Maciej.
{
if (gotFirstByte && !committed) {
committed = YES;
- [frameLoader commitProvisitionalLoad];
+ [frameLoader commitProvisionalLoad:nil];
}
}
@class WebResource;
@class WebFrame;
@class WebPolicyDecisionListener;
+@class DOMElement;
typedef enum {
WebFrameStateProvisional,
BOOL delegateIsHandlingUnimplementablePolicy;
BOOL firstLayoutDone;
+ BOOL quickRedirectComing;
+ BOOL sentRedirectNotification;
+ BOOL isStoppingLoad;
}
- (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)wf;
- (void)stopLoadingWithError:(NSError *)error;
- (void)clearProvisionalLoad;
- (void)stopLoading;
+- (void)stopLoadingSubframes;
- (void)markLoadComplete;
- (void)commitProvisionalLoad;
- (void)startLoading;
- (void)didReceiveServerRedirectForProvisionalLoadForFrame;
- (WebFrameBridge *)bridge;
- (void)finishedLoadingDocument:(WebDocumentLoader *)loader;
-- (void)commitProvisitionalLoad;
- (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data;
- (BOOL)isReplacing;
- (void)setReplacing;
- (void)didFirstLayout;
- (BOOL)firstLayoutDone;
+- (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress;
+- (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction;
+- (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values;
+- (void)commitProvisionalLoad:(NSDictionary *)pageCache;
+- (BOOL)isQuickRedirectComing;
+- (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL;
+
@end
return _timeOfLastCompletedLoad;
}
+- (void)provisionalLoadStarted
+{
+ firstLayoutDone = NO;
+ [[client _bridge] provisionalLoadStarted];
+
+ [client _provisionalLoadStarted];
+}
+
- (void)_setState:(WebFrameState)newState
{
LOG(Loading, "%@: transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
state = newState;
if (state == WebFrameStateProvisional)
- [client _provisionalLoadStarted];
+ [self provisionalLoadStarted];
else if (state == WebFrameStateComplete) {
[client _frameLoadCompleted];
+ [self frameLoadCompleted];
_timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
[[self documentLoader] stopRecordingResponses];
}
[self _setState:WebFrameStateCommittedPage];
}
+- (void)stopLoadingSubframes
+{
+ for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
+ [[(WebFrameBridge *)child frameLoader] stopLoading];
+}
+
- (void)stopLoading
{
- [[self provisionalDocumentLoader] stopLoading];
- [[self documentLoader] stopLoading];
+ // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
+ if (isStoppingLoad)
+ return;
+
+ isStoppingLoad = YES;
+
+ [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
+
+ [self stopLoadingSubframes];
+ [provisionalDocumentLoader stopLoading];
+ [documentLoader stopLoading];
[self _clearProvisionalDataSource];
[self clearArchivedResources];
+
+ isStoppingLoad = NO;
}
// FIXME: poor method name; also why is this not part of startProvisionalLoad:?
else
identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDataSource:[self provisionalDataSource]];
- if (![[provisionalDocumentLoader frameLoader] startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
+ if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
[provisionalDocumentLoader updateLoading];
}
[bridge handleFallbackContent];
}
- [bridge release];
+ if ([self state] == WebFrameStateProvisional) {
+ NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
+ [bridge didNotOpenURL:failedURL];
+ [client _invalidateCurrentItemPageCache];
+
+ // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
+ // status has changed, if there was a redirect. The frame load delegate may have saved some state about
+ // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
+ // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
+ // has ended.
+ if (sentRedirectNotification)
+ [self clientRedirectCancelledOrFinished:NO];
+ }
+
- [cli _receivedMainResourceError:error];
[loader mainReceivedError:error complete:isComplete];
+ [bridge release];
[cli release];
-
[loader release];
}
+- (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
+{
+ // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
+ // the redirect succeeded. We should either rename this API, or add a new method, like
+ // -webView:didFinishClientRedirectForFrame:
+ [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
+ didCancelClientRedirectForFrame:client];
+ if (!cancelWithLoadInProgress)
+ quickRedirectComing = NO;
+
+ sentRedirectNotification = NO;
+
+ LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
+}
+
+- (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
+{
+ LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
+
+ [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
+ willPerformClientRedirectToURL:URL
+ delay:seconds
+ fireDate:date
+ forFrame:client];
+
+ // Remember that we sent a redirect notification to the frame load delegate so that when we commit
+ // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
+ sentRedirectNotification = YES;
+
+ // If a "quick" redirect comes in an, we set a special mode so we treat the next
+ // load as part of the same navigation.
+
+ if (!documentLoader || isJavaScriptFormAction) {
+ // If we don't have a dataSource, we have no "original" load on which to base a redirect,
+ // so we better just treat the redirect as a normal load.
+ quickRedirectComing = NO;
+ LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
+ } else {
+ quickRedirectComing = lockHistory;
+ LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
+ }
+}
+
+- (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
+{
+ return !(([currentURL fragment] || [destinationURL fragment]) &&
+ [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
+}
+
+// main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
+- (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
+{
+ BOOL isFormSubmission = (values != nil);
+
+ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
+ [request setValue:[[client webView] userAgentForURL:[request URL]] forHTTPHeaderField:@"Referer"];
+ [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
+ if (_loadType == WebFrameLoadTypeReload) {
+ [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+ }
+
+ // I believe this is never called with LoadSame. If it is, we probably want to set the cache
+ // policy of LoadFromOrigin, but I didn't test that.
+ ASSERT(_loadType != WebFrameLoadTypeSame);
+
+ NSDictionary *action = [client _actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
+ WebFormState *formState = nil;
+ if (form && values)
+ formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
+
+ if (target != nil) {
+ WebFrame *targetFrame = [client findFrameNamed:target];
+ if (targetFrame != nil) {
+ [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
+ } else {
+ [self checkNewWindowPolicyForRequest:request
+ action:action
+ frameName:target
+ formState:formState
+ andCall:self
+ withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
+ }
+ [request release];
+ [formState release];
+ return;
+ }
+
+ WebDataSource *oldDataSource = [[self dataSource] retain];
+
+ BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
+
+ // Make sure to do scroll to anchor processing even if the URL is
+ // exactly the same so pages with '#' links and DHTML side effects
+ // work properly.
+ if (!isFormSubmission
+ && _loadType != WebFrameLoadTypeReload
+ && _loadType != WebFrameLoadTypeSame
+ && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
+
+ // We don't want to just scroll if a link from within a
+ // frameset is trying to reload the frameset into _top.
+ && ![[client _bridge] isFrameSet]) {
+
+ // Just do anchor navigation within the existing content.
+
+ // We don't do this if we are submitting a form, explicitly reloading,
+ // currently displaying a frameset, or if the new URL does not have a fragment.
+ // These rules are based on what KHTML was doing in KHTMLPart::openURL.
+
+ // FIXME: What about load types other than Standard and Reload?
+
+ [[oldDataSource _documentLoader] setTriggeringAction:action];
+ [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
+ [self checkNavigationPolicyForRequest:request
+ dataSource:oldDataSource formState:formState
+ andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
+ } else {
+ // must grab this now, since this load may stop the previous load and clear this flag
+ BOOL isRedirect = quickRedirectComing;
+ [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
+ if (isRedirect) {
+ LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [client name], self, (int)isRedirect);
+ quickRedirectComing = NO;
+ [provisionalDocumentLoader setIsClientRedirect:YES];
+ } else if (sameURL) {
+ // Example of this case are sites that reload the same URL with a different cookie
+ // driving the generated content, or a master frame with links that drive a target
+ // frame, where the user has clicked on the same link repeatedly.
+ [self setLoadType:WebFrameLoadTypeSame];
+ }
+ }
+
+ [request release];
+ [oldDataSource release];
+ [formState release];
+}
+
+-(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
+{
+ if (!request)
+ return;
+
+ NSURL *URL = [request URL];
+
+ BOOL isRedirect = quickRedirectComing;
+ LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
+ quickRedirectComing = NO;
+
+ [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
+ if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
+ // NB: must happen after _setURL, since we add based on the current request.
+ // Must also happen before we openURL and displace the scroll position, since
+ // adding the BF item will save away scroll state.
+
+ // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
+ // it was done, currItem is now set the that slow doc, and prevItem is whatever was
+ // before it. Adding the b/f item will bump the slow doc down to prevItem, even
+ // though its load is not yet done. I think this all works out OK, for one because
+ // we have already saved away the scroll and doc state for the long slow load,
+ // but it's not an obvious case.
+
+ [client _addHistoryItemForFragmentScroll];
+ }
+
+ [[client _bridge] scrollToAnchorWithURL:URL];
+
+ if (!isRedirect) {
+ // This will clear previousItem from the rest of the frame tree tree that didn't
+ // doing any loading. We need to make a pass on this now, since for anchor nav
+ // we'll not go through a real load and reach Completed state
+ [client _checkLoadComplete];
+ }
+
+ [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
+ didChangeLocationWithinPageForFrame:client];
+
+ [client _didFinishLoad];
+}
+
+- (void)closeOldDataSources
+{
+ // FIXME: is it important for this traversal to be postorder instead of preorder?
+ // FIXME: add helpers for postorder traversal?
+ for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
+ [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
+
+ if (documentLoader)
+ [[[client webView] _frameLoadDelegateForwarder] webView:[client webView] willCloseFrame:client];
+ [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
+}
+
+- (void)commitProvisionalLoad:(NSDictionary *)pageCache
+{
+ bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
+
+ WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
+ NSURLResponse *response = [provisionalDataSource response];
+
+ NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
+ ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
+
+ if (loadType != WebFrameLoadTypeReplace)
+ [self closeOldDataSources];
+
+ if (!pageCache)
+ [provisionalDataSource _makeRepresentation];
+
+ [client _transitionToCommitted:pageCache];
+
+ // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
+ // status has changed, if there was a redirect. The frame load delegate may have saved some state about
+ // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
+ // just about to commit a new page, there cannot possibly be a pending redirect at this point.
+ if (sentRedirectNotification)
+ [self clientRedirectCancelledOrFinished:NO];
+
+ NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
+ NSURL *URL = baseURL ? baseURL : [response URL];
+
+ if (!URL || [URL _web_isEmpty])
+ URL = [NSURL URLWithString:@"about:blank"];
+
+ [[client _bridge] openURL:URL
+ reload:reload
+ contentType:[response MIMEType]
+ refresh:[headers objectForKey:@"Refresh"]
+ lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
+ pageCache:pageCache];
+
+ [client _opened];
+
+ [provisionalDataSource release];
+}
+
- (NSURLRequest *)initialRequest
{
return [[self activeDataSource] initialRequest];
[[client _dataSourceForDocumentLoader:loader] _finishedLoading];
}
-- (void)commitProvisitionalLoad
-{
- [client _commitProvisionalLoad:nil];
-}
-
- (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
{
[[client _dataSourceForDocumentLoader:loader] _receivedData:data];
if (!canContinue) {
// If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
// need to report that the client redirect was cancelled.
- if ([client _quickRedirectComing])
- [client _clientRedirectCancelledOrFinished:NO];
+ if (quickRedirectComing)
+ [self clientRedirectCancelledOrFinished:NO];
[self setPolicyDocumentLoader:nil];
[[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:client];
}
-- (void)provisionalLoadStarted
-{
- firstLayoutDone = NO;
-}
-
- (void)frameLoadCompleted
{
// After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
return firstLayoutDone;
}
+- (BOOL)isQuickRedirectComing
+{
+ return quickRedirectComing;
+}
+
@end
@protocol WebFrameLoaderClient
- (void)_resetBackForwardList;
-- (BOOL)_quickRedirectComing;
- (BOOL)_provisionalItemIsTarget;
- (BOOL)_loadProvisionalItemFromPageCache;
+- (void)_invalidateCurrentItemPageCache;
@end
@class WebCoreRenderPart;
@class WebFrame;
@class WebFrameView;
+@class WebFrameLoader;
@protocol WebOpenPanelResultListener;
- (BOOL)inNextKeyViewOutsideWebFrameViews;
- (WebFrame *)webFrame;
+- (WebFrameLoader *)frameLoader;
@end
return dataSource;
}
+- (WebFrameLoader *)frameLoader
+{
+ return [_frame _frameLoader];
+}
+
- (void)setTitle:(NSString *)title
{
- [[[_frame _frameLoader] documentLoader] setTitle:[title _webkit_stringByCollapsingNonPrintingCharacters]];
+ [[[self frameLoader] documentLoader] setTitle:[title _webkit_stringByCollapsingNonPrintingCharacters]];
}
- (void)setStatusText:(NSString *)status
- (void)reportClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
{
- [_frame _clientRedirectedTo:URL delay:seconds fireDate:date lockHistory:lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction];
+ [[self frameLoader] clientRedirectedTo:URL delay:seconds fireDate:date lockHistory:lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction];
}
- (void)reportClientRedirectCancelled:(BOOL)cancelWithLoadInProgress
{
- [_frame _clientRedirectCancelledOrFinished:cancelWithLoadInProgress];
+ [[self frameLoader] clientRedirectCancelledOrFinished:cancelWithLoadInProgress];
}
- (void)close
loadType = WebFrameLoadTypeInternal;
else
loadType = WebFrameLoadTypeStandard;
- [_frame _loadURL:URL referrer:(hideReferrer ? nil : referrer) loadType:loadType target:target triggeringEvent:event form:form formValues:values];
+ [[self frameLoader] loadURL:URL referrer:(hideReferrer ? nil : referrer) loadType:loadType target:target triggeringEvent:event form:form formValues:values];
if (targetFrame != nil && _frame != targetFrame) {
[[targetFrame _bridge] activateWindow];
[_private->loader prepareForLoadStart];
_private->loadingFromPageCache = YES;
[_private->loader setCommitted:YES];
- [[self webFrame] _commitProvisionalLoad:pageCache];
+ [[_private->loader frameLoader] commitProvisionalLoad:pageCache];
}
- (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
- (WebHistoryItem *)_createItem: (BOOL)useOriginal;
- (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
- (WebHistoryItem *)_currentBackForwardListItemToResetTo;
-- (void)_stopLoadingSubframes;
@end
@interface WebFrame (FrameTraversal)
NSMutableSet *plugInViews;
NSMutableSet *inspectors;
-
- // things below here should be moved
-
- BOOL quickRedirectComing;
- BOOL sentRedirectNotification;
- BOOL isStoppingLoad;
}
- (void)setWebFrameView:(WebFrameView *)v;
}
}
+- (void)_addHistoryItemForFragmentScroll
+{
+ [self _addBackForwardItemClippedAtTarget:NO];
+}
+
+- (void)_didFinishLoad
+{
+ [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
+}
+
- (WebHistoryItem *)_createItem:(BOOL)useOriginal
{
WebDataSource *dataSrc = [self dataSource];
[child _detachFromParent];
}
-- (void)_closeOldDataSources
-{
- // FIXME: is it important for this traversal to be postorder instead of preorder?
- // FIXME: add helpers for postorder traversal?
- for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
- [child _closeOldDataSources];
-
- if ([_private->frameLoader dataSource])
- [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] willCloseFrame:self];
- [[self webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
-}
-
- (void)_detachFromParent
{
WebFrameBridge *bridge = [_private->bridge retain];
[documentView setDataSource:[_private->frameLoader dataSource]];
}
-- (void)_receivedMainResourceError:(NSError *)error
-{
- if ([_private->frameLoader state] == WebFrameStateProvisional) {
- NSURL *failedURL = [[[_private->frameLoader provisionalDocumentLoader] originalRequestCopy] URL];
- // When we are pre-commit, the currentItem is where the pageCache data resides
- NSDictionary *pageCache = [[_private currentItem] pageCache];
- [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
- // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
- [[_private currentItem] setHasPageCache:NO];
-
- // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
- // status has changed, if there was a redirect. The frame load delegate may have saved some state about
- // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
- // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
- // has ended.
- if (_private->sentRedirectNotification)
- [self _clientRedirectCancelledOrFinished:NO];
- }
-}
-
- (void)_transitionToCommitted:(NSDictionary *)pageCache
{
ASSERT([self webView] != nil);
}
}
-- (void)_commitProvisionalLoad:(NSDictionary *)pageCache
-{
- WebFrameLoadType loadType = [_private->frameLoader loadType];
- bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
-
- WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
- NSURLResponse *response = [provisionalDataSource response];
-
- NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
- ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
-
- if (loadType != WebFrameLoadTypeReplace)
- [self _closeOldDataSources];
-
- if (!pageCache)
- [provisionalDataSource _makeRepresentation];
-
- [self _transitionToCommitted:pageCache];
-
- // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
- // status has changed, if there was a redirect. The frame load delegate may have saved some state about
- // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
- // just about to commit a new page, there cannot possibly be a pending redirect at this point.
- if (_private->sentRedirectNotification)
- [self _clientRedirectCancelledOrFinished:NO];
-
- NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
- NSURL *URL = baseURL ? baseURL : [response URL];
-
- if (!URL || [URL _web_isEmpty])
- URL = [NSURL URLWithString:@"about:blank"];
-
- [[self _bridge] openURL:URL
- reload:reload
- contentType:[response MIMEType]
- refresh:[headers objectForKey:@"Refresh"]
- lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
- pageCache:pageCache];
-
- [self _opened];
-
- [provisionalDataSource release];
-}
-
- (BOOL)_canCachePage
{
return [[[self webView] backForwardList] _usesPageCache];
return YES;
}
+- (void)_provisionalLoadStarted
+{
+ WebFrameLoadType loadType = [_private->frameLoader loadType];
+
+ // FIXME: This is OK as long as no one resizes the window,
+ // but in the case where someone does, it means garbage outside
+ // the occupied part of the scroll view.
+ [[[self frameView] _scrollView] setDrawsBackground:NO];
+
+ // Cache the page, if possible.
+ // Don't write to the cache if in the middle of a redirect, since we will want to
+ // store the final page we end up on.
+ // No point writing to the cache on a reload or loadSame, since we will just write
+ // over it again when we leave that page.
+ WebHistoryItem *item = [_private currentItem];
+ if ([self _canCachePage]
+ && [_private->bridge canCachePage]
+ && item
+ && ![_private->frameLoader isQuickRedirectComing]
+ && loadType != WebFrameLoadTypeReload
+ && loadType != WebFrameLoadTypeReloadAllowingStaleData
+ && loadType != WebFrameLoadTypeSame
+ && ![[self dataSource] isLoading]
+ && ![[_private->frameLoader documentLoader] isStopping]) {
+ if ([[[self dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]) {
+ if (![item pageCache]){
+ // Add the items to this page's cache.
+ if ([self _createPageCacheForItem:item]) {
+ LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
+
+ // See if any page caches need to be purged after the addition of this
+ // new page cache.
+ [self _purgePageCache];
+ }
+ else
+ LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
+ }
+ } else
+ // Put the document into a null state, so it can be restored correctly.
+ [_private->bridge clear];
+ } else
+ LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
+}
+
// Called after we send an openURL:... down to WebCore.
- (void)_opened
{
// any effect, if isLoading is false, which it
// must be, to be in this branch of the if? And is it ok to just do
// a full-on stopLoading?
- [self _stopLoadingSubframes];
+ [_private->frameLoader stopLoadingSubframes];
[[pd _documentLoader] stopLoading];
// Finish resetting the load state, but only if another load hasn't been started by the
return YES; // found matches for all itemTargets
}
-- (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
-{
- return !(([currentURL fragment] || [destinationURL fragment]) &&
- [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
-}
-
// Walk the frame tree and ensure that the URLs match the URLs in the item.
- (BOOL)_URLsMatchItem:(WebHistoryItem *)item
{
// FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
// Perhaps they should.
- if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
+ if (!formData && ![_private->frameLoader shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
{
#if 0
// FIXME: We need to normalize the code paths for anchor navigation. Something
return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
}
--(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
-{
- if (!request) {
- return;
- }
-
- NSURL *URL = [request URL];
-
- BOOL isRedirect = _private->quickRedirectComing;
- LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
- _private->quickRedirectComing = NO;
-
- [[_private->frameLoader documentLoader] replaceRequestURLForAnchorScrollWithURL:URL];
- if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
- // NB: must happen after _setURL, since we add based on the current request.
- // Must also happen before we openURL and displace the scroll position, since
- // adding the BF item will save away scroll state.
-
- // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
- // it was done, currItem is now set the that slow doc, and prevItem is whatever was
- // before it. Adding the b/f item will bump the slow doc down to prevItem, even
- // though its load is not yet done. I think this all works out OK, for one because
- // we have already saved away the scroll and doc state for the long slow load,
- // but it's not an obvious case.
- [self _addBackForwardItemClippedAtTarget:NO];
- }
-
- [_private->bridge scrollToAnchorWithURL:URL];
-
- if (!isRedirect) {
- // This will clear previousItem from the rest of the frame tree tree that didn't
- // doing any loading. We need to make a pass on this now, since for anchor nav
- // we'll not go through a real load and reach Completed state
- [self _checkLoadComplete];
- }
-
- [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
- didChangeLocationWithinPageForFrame:self];
- [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
-}
-
- (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
{
if (!request)
[self release];
}
-// main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
-- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
-{
- BOOL isFormSubmission = (values != nil);
-
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
- [request _web_setHTTPReferrer:referrer];
- [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
- if (loadType == WebFrameLoadTypeReload) {
- [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
- }
-
- // I believe this is never called with LoadSame. If it is, we probably want to set the cache
- // policy of LoadFromOrigin, but I didn't test that.
- ASSERT(loadType != WebFrameLoadTypeSame);
-
- NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
- WebFormState *formState = nil;
- if (form && values) {
- formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
- }
-
- if (target != nil) {
- WebFrame *targetFrame = [self findFrameNamed:target];
- if (targetFrame != nil) {
- [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
- } else {
- [_private->frameLoader checkNewWindowPolicyForRequest:request
- action:action
- frameName:target
- formState:formState
- andCall:self
- withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
- }
- [request release];
- [formState release];
- return;
- }
-
- WebDataSource *oldDataSource = [[self dataSource] retain];
-
- BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
-
- // Make sure to do scroll to anchor processing even if the URL is
- // exactly the same so pages with '#' links and DHTML side effects
- // work properly.
- if (!isFormSubmission
- && loadType != WebFrameLoadTypeReload
- && loadType != WebFrameLoadTypeSame
- && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
-
- // We don't want to just scroll if a link from within a
- // frameset is trying to reload the frameset into _top.
- && ![_private->bridge isFrameSet]) {
-
- // Just do anchor navigation within the existing content.
-
- // We don't do this if we are submitting a form, explicitly reloading,
- // currently displaying a frameset, or if the new URL does not have a fragment.
- // These rules are based on what KHTML was doing in KHTMLPart::openURL.
-
- // FIXME: What about load types other than Standard and Reload?
-
- [[oldDataSource _documentLoader] setTriggeringAction:action];
- [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
- [_private->frameLoader checkNavigationPolicyForRequest:request
- dataSource:oldDataSource formState:formState
- andCall:self withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
- } else {
- // must grab this now, since this load may stop the previous load and clear this flag
- BOOL isRedirect = _private->quickRedirectComing;
- [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
- if (isRedirect) {
- LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
- _private->quickRedirectComing = NO;
- [[[self provisionalDataSource] _documentLoader] setIsClientRedirect:YES];
- } else if (sameURL) {
- // Example of this case are sites that reload the same URL with a different cookie
- // driving the generated content, or a master frame with links that drive a target
- // frame, where the user has clicked on the same link repeatedly.
- [_private->frameLoader setLoadType:WebFrameLoadTypeSame];
- }
- }
-
- [request release];
- [oldDataSource release];
- [formState release];
-}
-
- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
{
WebHistoryItem *parentItem = [_private currentItem];
if (archive) {
[childFrame loadArchive:archive];
} else {
- [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
+ [[childFrame _frameLoader] loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
}
}
[formState release];
}
-- (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
-{
- LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
-
- [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
- willPerformClientRedirectToURL:URL
- delay:seconds
- fireDate:date
- forFrame:self];
-
- // Remember that we sent a redirect notification to the frame load delegate so that when we commit
- // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
- _private->sentRedirectNotification = YES;
-
- // If a "quick" redirect comes in an, we set a special mode so we treat the next
- // load as part of the same navigation.
-
- if (![self dataSource] || isJavaScriptFormAction) {
- // If we don't have a dataSource, we have no "original" load on which to base a redirect,
- // so we better just treat the redirect as a normal load.
- _private->quickRedirectComing = NO;
- LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
- } else {
- _private->quickRedirectComing = lockHistory;
- LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
- }
-}
-
-- (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
-{
- // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
- // the redirect succeeded. We should either rename this API, or add a new method, like
- // -webView:didFinishClientRedirectForFrame:
- [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
- didCancelClientRedirectForFrame:self];
- if (!cancelWithLoadInProgress)
- _private->quickRedirectComing = NO;
-
- _private->sentRedirectNotification = NO;
-
- LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
-}
-
- (void)_setTitle:(NSString *)title
{
[[_private currentItem] setTitle:title];
ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
}
-- (void)_stopLoadingSubframes
-{
- for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
- [child stopLoading];
-}
-
- (BOOL)_subframeIsLoading
{
// It's most likely that the last added frame is the last to load so we walk backwards.
return _private->frameLoader;
}
-- (void)_provisionalLoadStarted
-{
- [_private->frameLoader provisionalLoadStarted];
- [_private->bridge provisionalLoadStarted];
-
- // FIXME: This is OK as long as no one resizes the window,
- // but in the case where someone does, it means garbage outside
- // the occupied part of the scroll view.
- [[[self frameView] _scrollView] setDrawsBackground:NO];
-
- // Cache the page, if possible.
- // Don't write to the cache if in the middle of a redirect, since we will want to
- // store the final page we end up on.
- // No point writing to the cache on a reload or loadSame, since we will just write
- // over it again when we leave that page.
- WebHistoryItem *item = [_private currentItem];
- WebFrameLoadType loadType = [_private->frameLoader loadType];
- if ([self _canCachePage]
- && [_private->bridge canCachePage]
- && item
- && !_private->quickRedirectComing
- && loadType != WebFrameLoadTypeReload
- && loadType != WebFrameLoadTypeReloadAllowingStaleData
- && loadType != WebFrameLoadTypeSame
- && ![[self dataSource] isLoading]
- && ![[_private->frameLoader documentLoader] isStopping]) {
- if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
- if (![item pageCache]){
- // Add the items to this page's cache.
- if ([self _createPageCacheForItem:item]) {
- LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
-
- // See if any page caches need to be purged after the addition of this
- // new page cache.
- [self _purgePageCache];
- }
- else
- LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
- }
- } else
- // Put the document into a null state, so it can be restored correctly.
- [_private->bridge clear];
- } else
- LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
-}
-
- (void)_prepareForDataSourceReplacement
{
if (![_private->frameLoader dataSource]) {
if ([[self webView] drawsBackground])
[sv setDrawsBackground:YES];
[_private setPreviousItem:nil];
- [_private->frameLoader frameLoadCompleted];
}
- (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader
- (void)stopLoading
{
- // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
- if (_private->isStoppingLoad)
- return;
-
- _private->isStoppingLoad = YES;
-
- [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
-
- [self _stopLoadingSubframes];
[_private->frameLoader stopLoading];
-
- _private->isStoppingLoad = NO;
}
- (void)reload
[[[self webView] backForwardList] goToItem:resetItem];
}
-- (BOOL)_quickRedirectComing
+- (void)_invalidateCurrentItemPageCache
{
- return _private->quickRedirectComing;
+ // When we are pre-commit, the currentItem is where the pageCache data resides
+ NSDictionary *pageCache = [[_private currentItem] pageCache];
+
+ [[self _bridge] invalidatePageCache:pageCache];
+
+ // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
+ [[_private currentItem] setHasPageCache:NO];
}
- (BOOL)_provisionalItemIsTarget
- (void)_removeInspector:(WebInspector *)inspector;
- (WebFrameLoader *)_frameLoader;
-- (void)_provisionalLoadStarted;
- (void)_prepareForDataSourceReplacement;
- (void)_frameLoadCompleted;
- (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader;
- (void)_detachFromParent;
- (void)_detachChildren;
-- (void)_closeOldDataSources;
-- (void)_commitProvisionalLoad:(NSDictionary *)pageCache;
- (void)_checkLoadCompleteForThisFrame;
- (void)_handledOnloadEvents;
- (void)_checkLoadComplete;
- (WebFrameBridge *)_bridge;
- (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type;
-- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values;
- (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame;
- (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;
- (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName;
-- (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction;
-- (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress;
- (void)_defersCallbacksChanged;
- (void)_setTitle:(NSString *)title;
-- (void)_receivedMainResourceError:(NSError *)error;
-
+ (CFAbsoluteTime)_timeOfLastCompletedLoad;
- (BOOL)_canCachePage;
- (void)_purgePageCache;
- (void)_recursive_resumeNullEventsForAllNetscapePlugins;
- (void)_restoreScrollPositionAndViewState;
+- (void)_transitionToCommitted:(NSDictionary *)pageCache;
+
+- (void)_provisionalLoadStarted;
+-(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
+- (void)_addHistoryItemForFragmentScroll;
+- (void)_didFinishLoad;
@end