2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import "WebFrameInternal.h"
31 #import "WebArchive.h"
32 #import "WebBackForwardList.h"
33 #import "WebDataProtocol.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultResourceLoadDelegate.h"
36 #import "WebDefaultUIDelegate.h"
37 #import "WebDocumentInternal.h"
38 #import "WebDocumentLoadStateMac.h"
39 #import "WebFormDataStream.h"
40 #import "WebFrameBridge.h"
41 #import "WebFrameLoadDelegate.h"
42 #import "WebFrameLoader.h"
43 #import "WebFrameLoaderClient.h"
44 #import "WebFrameViewInternal.h"
45 #import "WebHTMLRepresentationPrivate.h"
46 #import "WebHTMLViewInternal.h"
47 #import "WebHTMLViewPrivate.h"
48 #import "WebHistoryItemPrivate.h"
49 #import "WebHistoryPrivate.h"
50 #import "WebKitErrorsPrivate.h"
51 #import "WebKitLogging.h"
52 #import "WebKitNSStringExtras.h"
53 #import "WebKitStatisticsPrivate.h"
54 #import "WebNSObjectExtras.h"
55 #import "WebNSURLExtras.h"
56 #import "WebNSURLRequestExtras.h"
57 #import "WebNetscapePluginEmbeddedView.h"
58 #import "WebNullPluginView.h"
60 #import "WebPluginController.h"
61 #import "WebPreferencesPrivate.h"
62 #import "WebResourceLoadDelegate.h"
63 #import "WebResourcePrivate.h"
64 #import "WebScriptDebugDelegatePrivate.h"
65 #import "WebUIDelegate.h"
66 #import "WebViewInternal.h"
67 #import <WebKit/DOM.h>
68 #import <WebKitSystemInterface.h>
69 #import <objc/objc-runtime.h>
72 Here is the current behavior matrix for four types of navigations:
76 Restore form state: YES
77 Restore scroll and focus state: YES
78 WF Cache policy: NSURLRequestUseProtocolCachePolicy
79 Add to back/forward list: YES
83 Restore form state: YES
84 Restore scroll and focus state: YES
85 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
86 Add to back/forward list: NO
88 Reload (meaning only the reload button):
90 Restore form state: NO
91 Restore scroll and focus state: YES
92 WF Cache policy: NSURLRequestReloadIgnoringCacheData
93 Add to back/forward list: NO
95 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
97 Restore form state: NO
98 Restore scroll and focus state: NO, reset to initial conditions
99 WF Cache policy: NSURLRequestReloadIgnoringCacheData
100 Add to back/forward list: NO
103 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
104 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
105 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
107 @interface WebFrame (ForwardDecls)
108 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
109 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
111 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
113 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
114 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
115 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
116 - (void)_stopLoadingSubframes;
119 @interface WebFrame (FrameTraversal)
120 - (WebFrame *)_firstChildFrame;
121 - (WebFrame *)_lastChildFrame;
122 - (unsigned)_childFrameCount;
123 - (WebFrame *)_previousSiblingFrame;
124 - (WebFrame *)_nextSiblingFrame;
125 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
128 @interface WebFrame (WebFrameLoaderClient) <WebFrameLoaderClient>
131 @interface NSView (WebFramePluginHosting)
132 - (void)setWebFrame:(WebFrame *)webFrame;
135 @interface WebFramePrivate : NSObject
138 WebFrameView *webFrameView;
139 WebFrameLoader *frameLoader;
141 WebFrameBridge *bridge;
142 WebHistoryItem *currentItem; // BF item for our current content
143 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
144 // (only known when navigating to a pre-existing BF item)
145 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
147 WebScriptDebugger *scriptDebugger;
148 id internalLoadDelegate;
150 NSMutableSet *plugInViews;
151 NSMutableSet *inspectors;
153 // things below here should be moved
155 BOOL quickRedirectComing;
156 BOOL sentRedirectNotification;
160 - (void)setWebFrameView:(WebFrameView *)v;
161 - (WebFrameView *)webFrameView;
163 - (void)setProvisionalItem:(WebHistoryItem *)item;
164 - (WebHistoryItem *)provisionalItem;
165 - (void)setPreviousItem:(WebHistoryItem *)item;
166 - (WebHistoryItem *)previousItem;
167 - (void)setCurrentItem:(WebHistoryItem *)item;
168 - (WebHistoryItem *)currentItem;
172 @implementation WebFramePrivate
176 [webFrameView release];
177 [frameLoader release];
179 [currentItem release];
180 [provisionalItem release];
181 [previousItem release];
183 [scriptDebugger release];
185 [inspectors release];
187 ASSERT(plugInViews == nil);
192 - (WebFrameView *)webFrameView { return webFrameView; }
193 - (void)setWebFrameView: (WebFrameView *)v
196 [webFrameView release];
200 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
201 - (void)setProvisionalItem: (WebHistoryItem *)item
204 [provisionalItem release];
205 provisionalItem = item;
208 - (WebHistoryItem *)previousItem { return previousItem; }
209 - (void)setPreviousItem:(WebHistoryItem *)item
212 [previousItem release];
216 - (WebHistoryItem *)currentItem { return currentItem; }
217 - (void)setCurrentItem:(WebHistoryItem *)item
220 [currentItem release];
226 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
228 return [(WebFrameBridge *)bridge webFrame];
231 @implementation WebFrame (FrameTraversal)
232 - (WebFrame *)_firstChildFrame
234 return Frame([[self _bridge] firstChild]);
237 - (WebFrame *)_lastChildFrame
239 return Frame([[self _bridge] lastChild]);
242 - (unsigned)_childFrameCount
244 return [[self _bridge] childCount];
247 - (WebFrame *)_previousSiblingFrame;
249 return Frame([[self _bridge] previousSibling]);
252 - (WebFrame *)_nextSiblingFrame;
254 return Frame([[self _bridge] nextSibling]);
257 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
259 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
264 @implementation WebFrame (WebPrivate)
266 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
268 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
269 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
270 [request _webDataRequestSetData:data];
271 [request _webDataRequestSetEncoding:encodingName];
272 [request _webDataRequestSetBaseURL:URL];
273 [request _webDataRequestSetUnreachableURL:unreachableURL];
274 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
278 // helper method used in various nav cases below
279 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
281 if ([[self dataSource] _URLForHistory] != nil) {
282 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
283 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
284 [[[self webView] backForwardList] addItem:bfItem];
288 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
290 WebDataSource *dataSrc = [self dataSource];
291 NSURLRequest *request;
292 NSURL *unreachableURL = [dataSrc unreachableURL];
295 WebHistoryItem *bfItem;
298 request = [[dataSrc _documentLoadState] originalRequestCopy];
300 request = [dataSrc request];
302 if (unreachableURL != nil) {
303 URL = unreachableURL;
304 originalURL = unreachableURL;
307 originalURL = [[[dataSrc _documentLoadState] originalRequestCopy] URL];
310 LOG (History, "creating item for %@", request);
312 // Frames that have never successfully loaded any content
313 // may have no URL at all. Currently our history code can't
314 // deal with such things, so we nip that in the bud here.
315 // Later we may want to learn to live with nil for URL.
316 // See bug 3368236 and related bugs for more information.
318 URL = [NSURL URLWithString:@"about:blank"];
320 if (originalURL == nil) {
321 originalURL = [NSURL URLWithString:@"about:blank"];
324 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
325 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
327 // save form state if this is a POST
328 [bfItem _setFormInfoFromRequest:request];
330 // Set the item for which we will save document state
331 [_private setPreviousItem:[_private currentItem]];
332 [_private setCurrentItem:bfItem];
338 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
339 The item that was the target of the user's navigation is designated as the "targetItem".
340 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
341 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
343 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
345 WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
347 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
348 if (!(doClip && self == targetFrame)) {
349 // save frame state for items that aren't loading (khtml doesn't save those)
350 [_private->bridge saveDocumentState];
352 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
353 [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
355 if (self == targetFrame)
356 [bfItem setIsTargetItem:YES];
361 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
363 return Frame([[self _bridge] childFrameNamed:name]);
366 // FIXME: this exists only as a convenience for Safari, consider moving there
367 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
369 return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
374 return [_private->bridge isFrameSet];
377 - (void)_detachChildren
379 // FIXME: is it really necessary to do this in reverse order any more?
380 WebFrame *child = [self _lastChildFrame];
381 WebFrame *prev = [child _previousSiblingFrame];
382 for (; child; child = prev, prev = [child _previousSiblingFrame])
383 [child _detachFromParent];
386 - (void)_closeOldDataSources
388 // FIXME: is it important for this traversal to be postorder instead of preorder?
389 // FIXME: add helpers for postorder traversal?
390 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
391 [child _closeOldDataSources];
393 if ([_private->frameLoader dataSource])
394 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] willCloseFrame:self];
395 [[self webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
398 - (void)_detachFromParent
400 WebFrameBridge *bridge = [_private->bridge retain];
405 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
406 [self _detachChildren];
407 [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
409 [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
411 [_private->frameLoader clearDataSource];
412 [_private setWebFrameView:nil];
414 [self retain]; // retain self temporarily because dealloc can re-enter this method
416 [[[self parentFrame] _bridge] removeChild:bridge];
422 _private->bridge = nil;
427 - (WebFrameLoadType)_loadType
429 return [_private->frameLoader loadType];
432 - (void)_makeDocumentView
434 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[_private->frameLoader dataSource]];
438 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
439 WebFrameView *v = _private->webFrameView;
440 [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
441 [self _updateBackground];
442 [_private->bridge installInFrame:[v _scrollView]];
444 // Call setDataSource on the document view after it has been placed in the view hierarchy.
445 // This what we for the top-level view, so should do this for views in subframes as well.
446 [documentView setDataSource:[_private->frameLoader dataSource]];
449 - (void)_receivedMainResourceError:(NSError *)error
451 if ([_private->frameLoader state] == WebFrameStateProvisional) {
452 NSURL *failedURL = [[[_private->frameLoader provisionalDocumentLoadState] originalRequestCopy] URL];
453 // When we are pre-commit, the currentItem is where the pageCache data resides
454 NSDictionary *pageCache = [[_private currentItem] pageCache];
455 [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
456 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
457 [[_private currentItem] setHasPageCache:NO];
459 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
460 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
461 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
462 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
464 if (_private->sentRedirectNotification)
465 [self _clientRedirectCancelledOrFinished:NO];
469 - (void)_transitionToCommitted:(NSDictionary *)pageCache
471 ASSERT([self webView] != nil);
473 switch ([_private->frameLoader state]) {
474 case WebFrameStateProvisional:
476 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
478 WebFrameLoadType loadType = [_private->frameLoader loadType];
479 if (loadType == WebFrameLoadTypeForward ||
480 loadType == WebFrameLoadTypeBack ||
481 loadType == WebFrameLoadTypeIndexedBackForward ||
482 (loadType == WebFrameLoadTypeReload && [[_private->frameLoader provisionalDataSource] unreachableURL] != nil))
484 // Once committed, we want to use current item for saving DocState, and
485 // the provisional item for restoring state.
486 // Note previousItem must be set before we close the URL, which will
487 // happen when the data source is made non-provisional below
488 [_private setPreviousItem:[_private currentItem]];
489 ASSERT([_private provisionalItem]);
490 [_private setCurrentItem:[_private provisionalItem]];
491 [_private setProvisionalItem:nil];
494 // The call to closeURL invokes the unload event handler, which can execute arbitrary
495 // JavaScript. If the script initiates a new load, we need to abandon the current load,
496 // or the two will stomp each other.
497 WebDataSource *pd = [_private->frameLoader provisionalDataSource];
498 [[self _bridge] closeURL];
499 if (pd != [_private->frameLoader provisionalDataSource])
502 [_private->frameLoader commitProvisionalLoad];
504 // Handle adding the URL to the back/forward list.
505 WebDataSource *ds = [self dataSource];
506 NSString *ptitle = [ds pageTitle];
509 case WebFrameLoadTypeForward:
510 case WebFrameLoadTypeBack:
511 case WebFrameLoadTypeIndexedBackForward:
512 if ([[self webView] backForwardList]) {
513 // Must grab the current scroll position before disturbing it
514 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
516 // Create a document view for this document, or used the cached view.
518 NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
519 ASSERT(cachedView != nil);
520 [[self frameView] _setDocumentView: cachedView];
523 [self _makeDocumentView];
527 case WebFrameLoadTypeReload:
528 case WebFrameLoadTypeSame:
529 case WebFrameLoadTypeReplace:
531 WebHistoryItem *currItem = [_private currentItem];
532 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
533 [currItem setHasPageCache:NO];
534 if (loadType == WebFrameLoadTypeReload) {
535 [self _saveScrollPositionAndViewStateToItem:currItem];
537 NSURLRequest *request = [ds request];
538 if ([request _webDataRequestUnreachableURL] == nil) {
539 // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
540 [currItem setURL:[request URL]];
542 // Update the last visited time. Mostly interesting for URL autocompletion
544 NSURL *URL = [[[[ds _documentLoadState] originalRequestCopy] URL] _webkit_canonicalize];
545 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
546 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
548 [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
550 [self _makeDocumentView];
554 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
555 case WebFrameLoadTypeReloadAllowingStaleData:
556 [self _makeDocumentView];
559 case WebFrameLoadTypeStandard:
560 if (![[ds _documentLoadState] isClientRedirect]) {
561 // Add item to history and BF list
562 NSURL *URL = [ds _URLForHistory];
563 if (URL && ![URL _web_isEmpty]){
564 ASSERT([self webView]);
565 if (![[[self webView] preferences] privateBrowsingEnabled]) {
566 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
568 [entry setTitle: ptitle];
570 [self _addBackForwardItemClippedAtTarget:YES];
574 NSURLRequest *request = [ds request];
576 // update the URL in the BF list that we made before the redirect, unless
577 // this is alternate content for an unreachable URL (we want the BF list
578 // item to remember the unreachable URL in case it becomes reachable later)
579 if ([request _webDataRequestUnreachableURL] == nil) {
580 [[_private currentItem] setURL:[request URL]];
582 // clear out the form data so we don't repost it to the wrong place if we
583 // ever go back/forward to this item
584 [[_private currentItem] _setFormInfoFromRequest:request];
586 // We must also clear out form data so we don't try to restore it into the incoming page,
590 [self _makeDocumentView];
593 case WebFrameLoadTypeInternal:
594 // Add an item to the item tree for this frame
595 ASSERT(![[ds _documentLoadState] isClientRedirect]);
596 WebFrame *parentFrame = [self parentFrame];
598 WebHistoryItem *parentItem = [parentFrame->_private currentItem];
599 // The only case where parentItem==nil should be when a parent frame loaded an
600 // empty URL, which doesn't set up a current item in that parent.
602 [parentItem addChildItem:[self _createItem: YES]];
604 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
605 // for a top-level frame, but that was a likely explanation for those crashes,
606 // so let's guard against it.
607 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
608 LOG_ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
610 [self _makeDocumentView];
613 // FIXME Remove this check when dummy ds is removed. An exception should be thrown
614 // if we're in the WebFrameLoadTypeUninitialized state.
616 ASSERT_NOT_REACHED();
620 // Tell the client we've committed this URL.
621 ASSERT([[self frameView] documentView] != nil);
622 [[self webView] _didCommitLoadForFrame: self];
623 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didCommitLoadForFrame:self];
625 // If we have a title let the WebView know about it.
627 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
628 didReceiveTitle:ptitle
634 case WebFrameStateCommittedPage:
635 case WebFrameStateComplete:
638 ASSERT_NOT_REACHED();
643 - (void)_commitProvisionalLoad:(NSDictionary *)pageCache
645 WebFrameLoadType loadType = [_private->frameLoader loadType];
646 bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
648 WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
649 NSURLResponse *response = [provisionalDataSource response];
651 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
652 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
654 if (loadType != WebFrameLoadTypeReplace)
655 [self _closeOldDataSources];
658 [provisionalDataSource _makeRepresentation];
660 [self _transitionToCommitted:pageCache];
662 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
663 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
664 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
665 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
666 if (_private->sentRedirectNotification)
667 [self _clientRedirectCancelledOrFinished:NO];
669 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
670 NSURL *URL = baseURL ? baseURL : [response URL];
672 if (!URL || [URL _web_isEmpty])
673 URL = [NSURL URLWithString:@"about:blank"];
675 [[self _bridge] openURL:URL
677 contentType:[response MIMEType]
678 refresh:[headers objectForKey:@"Refresh"]
679 lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
680 pageCache:pageCache];
684 [provisionalDataSource release];
687 - (BOOL)_canCachePage
689 return [[[self webView] backForwardList] _usesPageCache];
692 - (void)_purgePageCache
694 // This method implements the rule for purging the page cache.
695 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
696 unsigned pagesCached = 0;
697 WebBackForwardList *backForwardList = [[self webView] backForwardList];
698 NSArray *backList = [backForwardList backListWithLimit: 999999];
699 WebHistoryItem *oldestNonSnapbackItem = nil;
702 for (i = 0; i < [backList count]; i++){
703 WebHistoryItem *item = [backList objectAtIndex: i];
704 if ([item hasPageCache]){
705 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
706 oldestNonSnapbackItem = item;
711 // Snapback items are never directly purged here.
712 if (pagesCached >= sizeLimit) {
713 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
714 [oldestNonSnapbackItem setHasPageCache:NO];
718 + (CFAbsoluteTime)_timeOfLastCompletedLoad
720 return [WebFrameLoader timeOfLastCompletedLoad];
723 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
725 NSMutableDictionary *pageCache;
727 [item setHasPageCache: YES];
729 if (![_private->bridge saveDocumentToPageCache]){
730 [item setHasPageCache: NO];
734 pageCache = [item pageCache];
735 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
736 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
737 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
742 // Called after we send an openURL:... down to WebCore.
745 if ([_private->frameLoader loadType] == WebFrameLoadTypeStandard && [[[self dataSource] _documentLoadState] isClientRedirect]) {
746 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
747 // khtml has closed the URL and saved away the form state.
748 WebHistoryItem *item = [_private currentItem];
749 [item setDocumentState:nil];
750 [item setScrollPoint:NSZeroPoint];
753 if ([[self dataSource] _loadingFromPageCache]){
754 // Force a layout to update view size and thereby update scrollbars.
755 NSView <WebDocumentView> *view = [[self frameView] documentView];
756 if ([view isKindOfClass:[WebHTMLView class]]) {
757 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
759 [view setNeedsLayout: YES];
762 NSArray *responses = [[_private->frameLoader documentLoadState] responses];
763 NSURLResponse *response;
764 int i, count = [responses count];
765 for (i = 0; i < count; i++){
766 response = [responses objectAtIndex: i];
767 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
770 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
771 [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
772 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
776 // Release the resources kept in the page cache. They will be
777 // reset when we leave this page. The core side of the page cache
778 // will have already been invalidated by the bridge to prevent
779 // premature release.
780 [[_private currentItem] setHasPageCache:NO];
782 [[_private->frameLoader documentLoadState] setPrimaryLoadComplete:YES];
783 // why only this frame and not parent frames?
784 [self _checkLoadCompleteForThisFrame];
788 - (void)_checkLoadCompleteForThisFrame
790 ASSERT([self webView] != nil);
792 switch ([_private->frameLoader state]) {
793 case WebFrameStateProvisional:
795 if ([_private->frameLoader delegateIsHandlingProvisionalLoadError])
798 WebDataSource *pd = [self provisionalDataSource];
800 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
801 // If we've received any errors we may be stuck in the provisional state and actually
803 NSError *error = [pd _mainDocumentError];
805 // Check all children first.
806 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
807 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
808 BOOL shouldReset = YES;
809 if (![pd isLoading]) {
810 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
811 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
812 [_private->frameLoader setDelegateIsHandlingProvisionalLoadError:YES];
813 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
814 didFailProvisionalLoadWithError:error
816 [_private->frameLoader setDelegateIsHandlingProvisionalLoadError:NO];
817 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
819 // FIXME: can stopping loading here possibly have
820 // any effect, if isLoading is false, which it
821 // must be, to be in this branch of the if? And is it ok to just do
822 // a full-on stopLoading?
823 [self _stopLoadingSubframes];
824 [[pd _documentLoadState] stopLoading];
826 // Finish resetting the load state, but only if another load hasn't been started by the
827 // delegate callback.
828 if (pd == [_private->frameLoader provisionalDataSource])
829 [_private->frameLoader clearProvisionalLoad];
831 NSURL *unreachableURL = [[_private->frameLoader provisionalDataSource] unreachableURL];
832 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
837 if (shouldReset && resetItem != nil) {
838 [[[self webView] backForwardList] goToItem:resetItem];
844 case WebFrameStateCommittedPage:
846 WebDataSource *ds = [self dataSource];
848 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
849 if (![ds isLoading]) {
850 WebFrameView *thisView = [self frameView];
851 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
852 ASSERT(thisDocumentView != nil);
854 [_private->frameLoader markLoadComplete];
856 // FIXME: Is this subsequent work important if we already navigated away?
857 // Maybe there are bugs because of that, or extra work we can skip because
858 // the new page is ready.
860 // Tell the just loaded document to layout. This may be necessary
861 // for non-html content that needs a layout message.
862 if (!([[self dataSource] _isDocumentHTML])) {
863 [thisDocumentView setNeedsLayout:YES];
864 [thisDocumentView layout];
865 [thisDocumentView setNeedsDisplay:YES];
868 // If the user had a scroll point scroll to it. This will override
869 // the anchor point. After much discussion it was decided by folks
870 // that the user scroll point should override the anchor point.
871 if ([[self webView] backForwardList]) {
872 switch ([_private->frameLoader loadType]) {
873 case WebFrameLoadTypeForward:
874 case WebFrameLoadTypeBack:
875 case WebFrameLoadTypeIndexedBackForward:
876 case WebFrameLoadTypeReload:
877 [self _restoreScrollPositionAndViewState];
880 case WebFrameLoadTypeStandard:
881 case WebFrameLoadTypeInternal:
882 case WebFrameLoadTypeReloadAllowingStaleData:
883 case WebFrameLoadTypeSame:
884 case WebFrameLoadTypeReplace:
889 ASSERT_NOT_REACHED();
894 NSError *error = [ds _mainDocumentError];
896 [[self webView] _didFailLoadWithError:error forFrame:self];
897 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
898 didFailLoadWithError:error
900 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
902 [[self webView] _didFinishLoadForFrame:self];
903 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
904 didFinishLoadForFrame:self];
905 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
908 [[self webView] _progressCompleted: self];
915 case WebFrameStateComplete:
917 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
918 // Even if already complete, we might have set a previous item on a frame that
919 // didn't do any data loading on the past transaction. Make sure to clear these out.
920 [_private setPreviousItem:nil];
925 // Yikes! Serious horkage.
926 ASSERT_NOT_REACHED();
929 - (void)_handledOnloadEvents
931 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
934 // Called every time a resource is completely loaded, or an error is received.
935 - (void)_checkLoadComplete
937 ASSERT([self webView] != nil);
940 for (WebFrame *frame = self; frame; frame = parent) {
942 [frame _checkLoadCompleteForThisFrame];
943 parent = [frame parentFrame];
948 - (WebFrameBridge *)_bridge
950 return _private->bridge;
953 // helper method that determines whether the subframes described by the item's subitems
954 // match our own current frameset
955 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
957 NSArray *childItems = [item children];
958 int numChildItems = [childItems count];
959 int numChildFrames = [self _childFrameCount];
960 if (numChildFrames != numChildItems)
964 for (i = 0; i < numChildItems; i++) {
965 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
966 //Search recursive here?
967 if (![self _immediateChildFrameNamed:itemTargetName])
968 return NO; // couldn't match the i'th itemTarget
971 return YES; // found matches for all itemTargets
974 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
976 return !(([currentURL fragment] || [destinationURL fragment]) &&
977 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
980 // Walk the frame tree and ensure that the URLs match the URLs in the item.
981 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
983 NSURL *currentURL = [[[self dataSource] request] URL];
985 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
988 NSArray *childItems = [item children];
989 WebHistoryItem *childItem;
990 WebFrame *childFrame;
991 int i, count = [childItems count];
992 for (i = 0; i < count; i++){
993 childItem = [childItems objectAtIndex:i];
994 childFrame = [self _immediateChildFrameNamed:[childItem target]];
995 if (![childFrame _URLsMatchItem: childItem])
1002 // loads content into this frame, as specified by item
1003 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1005 NSURL *itemURL = [item URL];
1006 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1007 NSURL *currentURL = [[[self dataSource] request] URL];
1008 NSArray *formData = [item formData];
1010 // Are we navigating to an anchor within the page?
1011 // Note if we have child frames we do a real reload, since the child frames might not
1012 // match our current frame structure, or they might not have the right content. We could
1013 // check for all that as an additional optimization.
1014 // We also do not do anchor-style navigation if we're posting a form.
1016 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1017 // Perhaps they should.
1018 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1021 // FIXME: We need to normalize the code paths for anchor navigation. Something
1022 // like the following line of code should be done, but also accounting for correct
1023 // updates to the back/forward list and scroll position.
1024 // rjw 4/9/03 See 3223929.
1025 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1027 // must do this maintenance here, since we don't go through a real page reload
1028 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1029 // FIXME: form state might want to be saved here too
1031 // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
1032 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
1033 [_private->bridge scrollToAnchorWithURL:[item URL]];
1035 // must do this maintenance here, since we don't go through a real page reload
1036 [_private setCurrentItem:item];
1037 [self _restoreScrollPositionAndViewState];
1039 // Fake the URL change by updating the data source's request. This will no longer
1040 // be necessary if we do the better fix described above.
1041 [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:itemURL];
1043 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1044 didChangeLocationWithinPageForFrame:self];
1045 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1047 // Remember this item so we can traverse any child items as child frames load
1048 [_private setProvisionalItem:item];
1050 WebDataSource *newDataSource;
1051 BOOL inPageCache = NO;
1053 // Check if we'll be using the page cache. We only use the page cache
1054 // if one exists and it is less than _backForwardCacheExpirationInterval
1055 // seconds old. If the cache is expired it gets flushed here.
1056 if ([item hasPageCache]){
1057 NSDictionary *pageCache = [item pageCache];
1058 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1059 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1061 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1062 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1063 [_private->frameLoader loadDataSource:newDataSource withLoadType:loadType formState:nil];
1067 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]);
1068 [item setHasPageCache: NO];
1073 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1074 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1076 // If this was a repost that failed the page cache, we might try to repost the form.
1077 NSDictionary *action;
1079 [request setHTTPMethod:@"POST"];
1080 [request _web_setHTTPReferrer:[item formReferrer]];
1081 webSetHTTPBody(request, formData);
1082 [request _web_setHTTPContentType:[item formContentType]];
1084 // Slight hack to test if the WF cache contains the page we're going to. We want
1085 // to know this before talking to the policy delegate, since it affects whether we
1086 // show the DoYouReallyWantToRepost nag.
1088 // This trick has a small bug (3123893) where we might find a cache hit, but then
1089 // have the item vanish when we try to use it in the ensuing nav. This should be
1090 // extremely rare, but in that case the user will get an error on the navigation.
1091 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1092 NSURLResponse *synchResponse = nil;
1093 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1094 if (synchResponse == nil) {
1096 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1097 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1099 // We can use the cache, don't use navType=resubmit
1100 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1104 case WebFrameLoadTypeReload:
1105 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1107 case WebFrameLoadTypeBack:
1108 case WebFrameLoadTypeForward:
1109 case WebFrameLoadTypeIndexedBackForward:
1110 if (![[itemURL scheme] isEqual:@"https"]) {
1111 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1114 case WebFrameLoadTypeStandard:
1115 case WebFrameLoadTypeInternal:
1116 // no-op: leave as protocol default
1117 // FIXME: I wonder if we ever hit this case
1119 case WebFrameLoadTypeSame:
1120 case WebFrameLoadTypeReloadAllowingStaleData:
1122 ASSERT_NOT_REACHED();
1125 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1128 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1134 // The general idea here is to traverse the frame tree and the item tree in parallel,
1135 // tracking whether each frame already has the content the item requests. If there is
1136 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1137 // reload that frame, and all its kids.
1138 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1140 NSURL *itemURL = [item URL];
1141 NSURL *currentURL = [[[self dataSource] request] URL];
1143 // Always reload the target frame of the item we're going to. This ensures that we will
1144 // do -some- load for the transition, which means a proper notification will be posted
1146 // The exact URL has to match, including fragment. We want to go through the _load
1147 // method, even if to do a within-page navigation.
1148 // The current frame tree and the frame tree snapshot in the item have to match.
1149 if (![item isTargetItem] &&
1150 [itemURL isEqual:currentURL] &&
1151 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1152 [self _childFramesMatchItem:item])
1154 // This content is good, so leave it alone and look for children that need reloading
1156 // Save form state (works from currentItem, since prevItem is nil)
1157 ASSERT(![_private previousItem]);
1158 [_private->bridge saveDocumentState];
1159 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1161 [_private setCurrentItem:item];
1163 // Restore form state (works from currentItem)
1164 [_private->bridge restoreDocumentState];
1165 // Restore the scroll position (taken in favor of going back to the anchor)
1166 [self _restoreScrollPositionAndViewState];
1168 NSArray *childItems = [item children];
1169 int numChildItems = childItems ? [childItems count] : 0;
1171 for (i = numChildItems - 1; i >= 0; i--) {
1172 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1173 NSString *childName = [childItem target];
1174 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1175 ASSERT(fromChildItem || [fromItem isTargetItem]);
1176 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1178 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1181 // We need to reload the content
1182 [self _loadItem:item withLoadType:type];
1186 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1187 // This includes recursion to handle loading into framesets properly
1188 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1190 ASSERT(![self parentFrame]);
1191 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1192 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1193 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1194 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1195 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
1196 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1197 WebHistoryItem *currItem = [backForwardList currentItem];
1198 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1199 // - plus, it only makes sense for the top level of the operation through the frametree,
1200 // as opposed to happening for some/one of the page commits that might happen soon
1201 [backForwardList goToItem:item];
1202 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1206 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1208 switch ([event type]) {
1209 case NSLeftMouseDown:
1210 case NSRightMouseDown:
1211 case NSOtherMouseDown:
1213 case NSRightMouseUp:
1214 case NSOtherMouseUp:
1216 NSView *topViewInEventWindow = [[event window] contentView];
1217 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1218 while (viewContainingPoint != nil) {
1219 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1222 viewContainingPoint = [viewContainingPoint superview];
1224 if (viewContainingPoint != nil) {
1225 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1226 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1228 return [NSDictionary dictionaryWithObjectsAndKeys:
1229 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1230 elementInfo, WebActionElementKey,
1231 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1232 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1233 URL, WebActionOriginalURLKey,
1241 return [NSDictionary dictionaryWithObjectsAndKeys:
1242 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1243 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1244 URL, WebActionOriginalURLKey,
1249 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1251 WebNavigationType navType;
1252 if (isFormSubmission) {
1253 navType = WebNavigationTypeFormSubmitted;
1254 } else if (event == nil) {
1255 if (loadType == WebFrameLoadTypeReload) {
1256 navType = WebNavigationTypeReload;
1257 } else if (loadType == WebFrameLoadTypeForward
1258 || loadType == WebFrameLoadTypeBack
1259 || loadType == WebFrameLoadTypeIndexedBackForward) {
1260 navType = WebNavigationTypeBackForward;
1262 navType = WebNavigationTypeOther;
1265 navType = WebNavigationTypeLinkClicked;
1267 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1270 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1276 NSURL *URL = [request URL];
1278 BOOL isRedirect = _private->quickRedirectComing;
1279 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1280 _private->quickRedirectComing = NO;
1282 [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:URL];
1283 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1284 // NB: must happen after _setURL, since we add based on the current request.
1285 // Must also happen before we openURL and displace the scroll position, since
1286 // adding the BF item will save away scroll state.
1288 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1289 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1290 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1291 // though its load is not yet done. I think this all works out OK, for one because
1292 // we have already saved away the scroll and doc state for the long slow load,
1293 // but it's not an obvious case.
1294 [self _addBackForwardItemClippedAtTarget:NO];
1297 [_private->bridge scrollToAnchorWithURL:URL];
1300 // This will clear previousItem from the rest of the frame tree tree that didn't
1301 // doing any loading. We need to make a pass on this now, since for anchor nav
1302 // we'll not go through a real load and reach Completed state
1303 [self _checkLoadComplete];
1306 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1307 didChangeLocationWithinPageForFrame:self];
1308 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1311 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1318 WebView *webView = nil;
1319 WebView *currentWebView = [self webView];
1320 id wd = [currentWebView UIDelegate];
1321 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1322 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1324 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1328 WebFrame *frame = [webView mainFrame];
1334 [[frame _bridge] setName:frameName];
1336 [[webView _UIDelegateForwarder] webViewShow:webView];
1338 [[frame _bridge] setOpener:[self _bridge]];
1339 [frame->_private->frameLoader _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1347 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1348 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1350 BOOL isFormSubmission = (values != nil);
1352 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1353 [request _web_setHTTPReferrer:referrer];
1354 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
1355 if (loadType == WebFrameLoadTypeReload) {
1356 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1359 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1360 // policy of LoadFromOrigin, but I didn't test that.
1361 ASSERT(loadType != WebFrameLoadTypeSame);
1363 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1364 WebFormState *formState = nil;
1365 if (form && values) {
1366 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1369 if (target != nil) {
1370 WebFrame *targetFrame = [self findFrameNamed:target];
1371 if (targetFrame != nil) {
1372 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1374 [_private->frameLoader checkNewWindowPolicyForRequest:request
1379 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1382 [formState release];
1386 WebDataSource *oldDataSource = [[self dataSource] retain];
1388 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1390 // Make sure to do scroll to anchor processing even if the URL is
1391 // exactly the same so pages with '#' links and DHTML side effects
1393 if (!isFormSubmission
1394 && loadType != WebFrameLoadTypeReload
1395 && loadType != WebFrameLoadTypeSame
1396 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1398 // We don't want to just scroll if a link from within a
1399 // frameset is trying to reload the frameset into _top.
1400 && ![_private->bridge isFrameSet]) {
1402 // Just do anchor navigation within the existing content.
1404 // We don't do this if we are submitting a form, explicitly reloading,
1405 // currently displaying a frameset, or if the new URL does not have a fragment.
1406 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1408 // FIXME: What about load types other than Standard and Reload?
1410 [[oldDataSource _documentLoadState] setTriggeringAction:action];
1411 [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1412 [_private->frameLoader checkNavigationPolicyForRequest:request
1413 dataSource:oldDataSource formState:formState
1414 andCall:self withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1416 // must grab this now, since this load may stop the previous load and clear this flag
1417 BOOL isRedirect = _private->quickRedirectComing;
1418 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1420 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1421 _private->quickRedirectComing = NO;
1422 [[[self provisionalDataSource] _documentLoadState] setIsClientRedirect:YES];
1423 } else if (sameURL) {
1424 // Example of this case are sites that reload the same URL with a different cookie
1425 // driving the generated content, or a master frame with links that drive a target
1426 // frame, where the user has clicked on the same link repeatedly.
1427 [_private->frameLoader setLoadType:WebFrameLoadTypeSame];
1432 [oldDataSource release];
1433 [formState release];
1436 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1438 WebHistoryItem *parentItem = [_private currentItem];
1439 NSArray *childItems = [parentItem children];
1440 WebFrameLoadType loadType = [_private->frameLoader loadType];
1441 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1442 WebHistoryItem *childItem = nil;
1444 // If we're moving in the backforward list, we might want to replace the content
1445 // of this child frame with whatever was there at that point.
1446 // Reload will maintain the frame contents, LoadSame will not.
1448 (loadType == WebFrameLoadTypeForward
1449 || loadType == WebFrameLoadTypeBack
1450 || loadType == WebFrameLoadTypeIndexedBackForward
1451 || loadType == WebFrameLoadTypeReload
1452 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1454 childItem = [parentItem childItemWithName:[childFrame name]];
1456 // Use the original URL to ensure we get all the side-effects, such as
1457 // onLoad handlers, of any redirects that happened. An example of where
1458 // this is needed is Radar 3213556.
1459 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1460 // These behaviors implied by these loadTypes should apply to the child frames
1461 childLoadType = loadType;
1463 if (loadType == WebFrameLoadTypeForward
1464 || loadType == WebFrameLoadTypeBack
1465 || loadType == WebFrameLoadTypeIndexedBackForward)
1467 // For back/forward, remember this item so we can traverse any child items as child frames load
1468 [childFrame->_private setProvisionalItem:childItem];
1470 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1471 [childFrame->_private setCurrentItem:childItem];
1476 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1478 [childFrame loadArchive:archive];
1480 [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1484 - (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
1486 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1487 // This prevents a potential bug which may cause a page with a form that uses itself
1488 // as an action to be returned from the cache without submitting.
1490 // FIXME: Where's the code that implements what the comment above says?
1492 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1493 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1494 [request _web_setHTTPReferrer:referrer];
1495 [request setHTTPMethod:@"POST"];
1496 webSetHTTPBody(request, postData);
1497 [request _web_setHTTPContentType:contentType];
1499 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1500 WebFormState *formState = nil;
1501 if (form && values) {
1502 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1505 if (target != nil) {
1506 WebFrame *targetFrame = [self findFrameNamed:target];
1508 if (targetFrame != nil) {
1509 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1511 [_private->frameLoader checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self
1512 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1515 [formState release];
1519 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1522 [formState release];
1525 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
1527 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
1529 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1530 willPerformClientRedirectToURL:URL
1535 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1536 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1537 _private->sentRedirectNotification = YES;
1539 // If a "quick" redirect comes in an, we set a special mode so we treat the next
1540 // load as part of the same navigation.
1542 if (![self dataSource] || isJavaScriptFormAction) {
1543 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
1544 // so we better just treat the redirect as a normal load.
1545 _private->quickRedirectComing = NO;
1546 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1548 _private->quickRedirectComing = lockHistory;
1549 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1553 - (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
1555 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1556 // the redirect succeeded. We should either rename this API, or add a new method, like
1557 // -webView:didFinishClientRedirectForFrame:
1558 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1559 didCancelClientRedirectForFrame:self];
1560 if (!cancelWithLoadInProgress)
1561 _private->quickRedirectComing = NO;
1563 _private->sentRedirectNotification = NO;
1565 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1568 - (void)_setTitle:(NSString *)title
1570 [[_private currentItem] setTitle:title];
1573 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1576 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1577 NSView *parent = [docView superview];
1578 // we might already be detached when this is called from detachFromParent, in which
1579 // case we don't want to override real data earlier gathered with (0,0)
1582 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1583 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1584 // ScrollView instead of using the one provided by the WebFrame
1585 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1586 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1588 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1589 ASSERT([parent isKindOfClass:[NSClipView class]]);
1590 point = [parent bounds].origin;
1592 [item setScrollPoint:point];
1597 - (void)_defersCallbacksChanged
1599 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1600 [frame->_private->frameLoader defersCallbacksChanged];
1603 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1605 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1606 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1609 - (void)_viewDidMoveToHostWindow
1611 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1612 [[[frame frameView] documentView] viewDidMoveToHostWindow];
1615 - (void)_addChild:(WebFrame *)child
1617 [[self _bridge] appendChild:[child _bridge]];
1618 [[[child dataSource] _documentLoadState] setOverrideEncoding:[[[self dataSource] _documentLoadState] overrideEncoding]];
1621 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1622 // item, because we optimistically move it right away at the start of the operation. But when
1623 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1624 // Return the item that we would reset to, so we can decide later whether to actually reset.
1625 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1627 WebFrameLoadType loadType = [_private->frameLoader loadType];
1628 if ((loadType == WebFrameLoadTypeForward
1629 || loadType == WebFrameLoadTypeBack
1630 || loadType == WebFrameLoadTypeIndexedBackForward)
1631 && self == [[self webView] mainFrame]) {
1632 return [_private currentItem];
1637 - (WebHistoryItem *)_itemForSavingDocState
1639 // For a standard page load, we will have a previous item set, which will be used to
1640 // store the form state. However, in some cases we will have no previous item, and
1641 // the current item is the right place to save the state. One example is when we
1642 // detach a bunch of frames because we are navigating from a site with frames to
1643 // another site. Another is when saving the frame state of a frame that is not the
1644 // target of the current navigation (if we even decide to save with that granularity).
1646 // Because of previousItem's "masking" of currentItem for this purpose, it's important
1647 // that previousItem be cleared at the end of a page transition. We leverage the
1648 // checkLoadComplete recursion to achieve this goal.
1650 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
1654 - (WebHistoryItem *)_itemForRestoringDocState
1656 switch ([_private->frameLoader loadType]) {
1657 case WebFrameLoadTypeReload:
1658 case WebFrameLoadTypeReloadAllowingStaleData:
1659 case WebFrameLoadTypeSame:
1660 case WebFrameLoadTypeReplace:
1661 // Don't restore any form state on reload or loadSame
1663 case WebFrameLoadTypeBack:
1664 case WebFrameLoadTypeForward:
1665 case WebFrameLoadTypeIndexedBackForward:
1666 case WebFrameLoadTypeInternal:
1667 case WebFrameLoadTypeStandard:
1668 return [_private currentItem];
1670 ASSERT_NOT_REACHED();
1674 // Walk the frame tree, telling all frames to save their form state into their current
1676 - (void)_saveDocumentAndScrollState
1678 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1679 [[frame _bridge] saveDocumentState];
1680 [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
1684 // used to decide to use loadType=Same
1685 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
1687 WebHistoryItem *item = [_private currentItem];
1688 NSString* URLString = [URL _web_originalDataAsString];
1689 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
1692 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1694 if (frameName == nil) {
1695 [self loadRequest:request];
1699 WebFrame *frame = [self findFrameNamed:frameName];
1702 [frame loadRequest:request];
1706 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1707 [_private->frameLoader checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1710 // Return next frame to be traversed, visiting children after parent
1711 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
1713 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
1716 // Return previous frame to be traversed, exact reverse order of _nextFrame
1717 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
1719 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
1722 - (void)_setShouldCreateRenderers:(BOOL)f
1724 [_private->bridge setShouldCreateRenderers:f];
1727 - (BOOL)_shouldCreateRenderers
1729 return [_private->bridge shouldCreateRenderers];
1732 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
1735 return [[self _bridge] numPendingOrLoadingRequests];
1738 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1739 num += [[frame _bridge] numPendingOrLoadingRequests];
1744 - (NSColor *)_bodyBackgroundColor
1746 return [_private->bridge bodyBackgroundColor];
1749 - (void)_reloadForPluginChanges
1751 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1752 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1753 if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
1758 - (void)_attachScriptDebugger
1760 if (!_private->scriptDebugger)
1761 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
1764 - (void)_detachScriptDebugger
1766 if (_private->scriptDebugger) {
1767 id old = _private->scriptDebugger;
1768 _private->scriptDebugger = nil;
1773 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
1775 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1776 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1777 if ([documentView isKindOfClass:[WebHTMLView class]])
1778 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1782 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
1784 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1785 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1786 if ([documentView isKindOfClass:[WebHTMLView class]])
1787 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1791 - (BOOL)_firstLayoutDone
1793 return [_private->frameLoader firstLayoutDone];
1798 @implementation WebFrame (WebInternal)
1800 - (void)_didReceiveServerRedirectForProvisionalLoadForFrame
1802 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1803 didReceiveServerRedirectForProvisionalLoadForFrame:self];
1806 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
1808 self = [super init];
1812 _private = [[WebFramePrivate alloc] init];
1814 _private->bridge = bridge;
1817 [_private setWebFrameView:fv];
1818 [fv _setWebFrame:self];
1821 _private->frameLoader = [[WebFrameLoader alloc] initWithClient:self];
1828 - (NSArray *)_documentViews
1830 NSMutableArray *result = [NSMutableArray array];
1831 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1832 id docView = [[frame frameView] documentView];
1834 [result addObject:docView];
1840 - (void)_updateBackground
1842 BOOL drawsBackground = [[self webView] drawsBackground];
1843 NSColor *backgroundColor = [[self webView] backgroundColor];
1845 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1846 // Never call setDrawsBackground:YES here on the scroll view or the background color will
1847 // flash between pages loads. setDrawsBackground:YES will be called in WebFrame's _frameLoadCompleted.
1848 if (!drawsBackground)
1849 [[[frame frameView] _scrollView] setDrawsBackground:NO];
1850 [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
1851 id documentView = [[frame frameView] documentView];
1852 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
1853 [documentView setDrawsBackground:drawsBackground];
1854 if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
1855 [documentView setBackgroundColor:backgroundColor];
1856 [[frame _bridge] setDrawsBackground:drawsBackground];
1857 [[frame _bridge] setBaseBackgroundColor:backgroundColor];
1861 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
1863 _private->internalLoadDelegate = internalLoadDelegate;
1866 - (id)_internalLoadDelegate
1868 return _private->internalLoadDelegate;
1871 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1873 ASSERT(request != nil);
1875 WebView *wv = [self webView];
1876 id delegate = [wv resourceLoadDelegate];
1877 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1878 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1879 WebDataSource *dataSource = [self dataSource];
1881 if (implementations.delegateImplementsIdentifierForRequest) {
1882 *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1884 *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1887 NSURLRequest *newRequest;
1888 if (implementations.delegateImplementsWillSendRequest) {
1889 newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1891 newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1894 if (newRequest == nil) {
1895 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1903 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1905 WebView *wv = [self webView];
1906 id delegate = [wv resourceLoadDelegate];
1907 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1908 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1909 WebDataSource *dataSource = [self dataSource];
1911 if (response != nil) {
1912 if (implementations.delegateImplementsDidReceiveResponse) {
1913 [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1915 [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1920 if (implementations.delegateImplementsDidReceiveContentLength) {
1921 [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1923 [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1928 if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
1929 [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1931 [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1933 [self _checkLoadComplete];
1935 [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
1939 - (void)_safeLoadURL:(NSURL *)URL
1941 // Call the bridge because this is where our security checks are made.
1942 [[self _bridge] loadURL:URL
1943 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
1947 triggeringEvent:[NSApp currentEvent]
1952 - (void)_unmarkAllMisspellings
1954 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1955 [[frame _bridge] unmarkAllMisspellings];
1958 - (BOOL)_hasSelection
1960 id documentView = [[self frameView] documentView];
1962 // optimization for common case to avoid creating potentially large selection string
1963 if ([documentView isKindOfClass:[WebHTMLView class]]) {
1964 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
1965 return selectedDOMRange && ![selectedDOMRange collapsed];
1968 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1969 return [[documentView selectedString] length] > 0;
1974 - (void)_clearSelection
1976 id documentView = [[self frameView] documentView];
1977 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1978 [documentView deselectAll];
1983 - (BOOL)_atMostOneFrameHasSelection;
1985 // FIXME: 4186050 is one known case that makes this debug check fail
1987 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1988 if ([frame _hasSelection]) {
1999 - (WebFrame *)_findFrameWithSelection
2001 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2002 if ([frame _hasSelection])
2008 - (void)_clearSelectionInOtherFrames
2010 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
2011 // responder. It would be nicer to just notice first responder changes here instead, but there's no
2012 // notification sent when the first responder changes in general (Radar 2573089).
2013 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
2014 if (frameWithSelection != self)
2015 [frameWithSelection _clearSelection];
2017 // While we're in the general area of selection and frames, check that there is only one now.
2018 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
2021 - (void)_stopLoadingSubframes
2023 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2024 [child stopLoading];
2027 - (BOOL)_subframeIsLoading
2029 // It's most likely that the last added frame is the last to load so we walk backwards.
2030 for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
2031 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
2036 - (void)_addPlugInView:(NSView *)plugInView
2038 ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
2039 ASSERT(![_private->plugInViews containsObject:plugInView]);
2041 if (!_private->plugInViews)
2042 _private->plugInViews = [[NSMutableSet alloc] init];
2044 [plugInView setWebFrame:self];
2045 [_private->plugInViews addObject:plugInView];
2048 - (void)_removeAllPlugInViews
2050 if (!_private->plugInViews)
2053 [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
2054 [_private->plugInViews release];
2055 _private->plugInViews = nil;
2058 // This is called when leaving a page or closing the WebView
2059 - (void)_willCloseURL
2061 [self _removeAllPlugInViews];
2064 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2066 [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
2068 if ([_private->frameLoader loadType] == WebFrameLoadTypeReload)
2069 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2071 // Don't set the cookie policy URL if it's already been set.
2072 if ([request mainDocumentURL] == nil) {
2073 if (mainResource && (self == [[self webView] mainFrame] || f))
2074 [request setMainDocumentURL:[request URL]];
2076 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
2080 [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
2083 - (BOOL)_isMainFrame
2085 return self == [[self webView] mainFrame];
2088 - (void)_addInspector:(WebInspector *)inspector
2090 if (!_private->inspectors)
2091 _private->inspectors = [[NSMutableSet alloc] init];
2092 ASSERT(![_private->inspectors containsObject:inspector]);
2093 [_private->inspectors addObject:inspector];
2096 - (void)_removeInspector:(WebInspector *)inspector
2098 ASSERT([_private->inspectors containsObject:inspector]);
2099 [_private->inspectors removeObject:inspector];
2102 - (WebFrameLoader *)_frameLoader
2104 return _private->frameLoader;
2107 - (void)_provisionalLoadStarted
2109 [_private->frameLoader provisionalLoadStarted];
2110 [_private->bridge provisionalLoadStarted];
2112 // FIXME: This is OK as long as no one resizes the window,
2113 // but in the case where someone does, it means garbage outside
2114 // the occupied part of the scroll view.
2115 [[[self frameView] _scrollView] setDrawsBackground:NO];
2117 // Cache the page, if possible.
2118 // Don't write to the cache if in the middle of a redirect, since we will want to
2119 // store the final page we end up on.
2120 // No point writing to the cache on a reload or loadSame, since we will just write
2121 // over it again when we leave that page.
2122 WebHistoryItem *item = [_private currentItem];
2123 WebFrameLoadType loadType = [_private->frameLoader loadType];
2124 if ([self _canCachePage]
2125 && [_private->bridge canCachePage]
2127 && !_private->quickRedirectComing
2128 && loadType != WebFrameLoadTypeReload
2129 && loadType != WebFrameLoadTypeReloadAllowingStaleData
2130 && loadType != WebFrameLoadTypeSame
2131 && ![[self dataSource] isLoading]
2132 && ![[_private->frameLoader documentLoadState] isStopping]) {
2133 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
2134 if (![item pageCache]){
2135 // Add the items to this page's cache.
2136 if ([self _createPageCacheForItem:item]) {
2137 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2139 // See if any page caches need to be purged after the addition of this
2141 [self _purgePageCache];
2144 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
2147 // Put the document into a null state, so it can be restored correctly.
2148 [_private->bridge clear];
2150 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2153 - (void)_prepareForDataSourceReplacement
2155 if (![_private->frameLoader dataSource]) {
2156 ASSERT(![self _childFrameCount]);
2160 // Make sure that any work that is triggered by resigning first reponder can get done.
2161 // The main example where this came up is the textDidEndEditing that is sent to the
2162 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
2163 // remove the views as a side-effect of freeing the bridge, at which point we can't
2164 // post the FormDelegate messages.
2166 // Note that this can also take FirstResponder away from a child of our frameView that
2167 // is not in a child frame's view. This is OK because we are in the process
2168 // of loading new content, which will blow away all editors in this top frame, and if
2169 // a non-editor is firstReponder it will not be affected by endEditingFor:.
2170 // Potentially one day someone could write a DocView whose editors were not all
2171 // replaced by loading new content, but that does not apply currently.
2172 NSView *frameView = [self frameView];
2173 NSWindow *window = [frameView window];
2174 NSResponder *firstResp = [window firstResponder];
2175 if ([firstResp isKindOfClass:[NSView class]]
2176 && [(NSView *)firstResp isDescendantOf:frameView])
2178 [window endEditingFor:firstResp];
2181 [self _detachChildren];
2184 - (void)_frameLoadCompleted
2186 NSScrollView *sv = [[self frameView] _scrollView];
2187 if ([[self webView] drawsBackground])
2188 [sv setDrawsBackground:YES];
2189 [_private setPreviousItem:nil];
2190 [_private->frameLoader frameLoadCompleted];
2193 - (WebDataSource *)_dataSourceForDocumentLoadState:(WebDocumentLoadState *)loadState
2195 return [(WebDocumentLoadStateMac *)loadState dataSource];
2198 - (WebDocumentLoadState *)_createDocumentLoadStateWithRequest:(NSURLRequest *)request
2200 WebDocumentLoadStateMac *loadState = [[WebDocumentLoadStateMac alloc] initWithRequest:request];
2202 WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoadState:loadState];
2203 [loadState setDataSource:dataSource];
2204 [dataSource release];
2210 There is a race condition between the layout and load completion that affects restoring the scroll position.
2211 We try to restore the scroll position at both the first layout and upon load completion.
2213 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
2214 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
2215 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
2216 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
2217 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
2218 fails. We then successfully restore it when the layout happens.
2221 - (void)_restoreScrollPositionAndViewState
2223 ASSERT([_private currentItem]);
2224 NSView <WebDocumentView> *docView = [[self frameView] documentView];
2225 NSPoint point = [[_private currentItem] scrollPoint];
2226 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
2227 id state = [[_private currentItem] viewState];
2229 [(id <_WebDocumentViewState>)docView setViewState:state];
2232 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
2234 [docView scrollPoint:point];
2240 @implementation WebFormState : NSObject
2242 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2244 self = [super init];
2248 _form = [form retain];
2249 _values = [values copy];
2250 _sourceFrame = [sourceFrame retain];
2258 [_sourceFrame release];
2262 - (DOMElement *)form
2267 - (NSDictionary *)values
2272 - (WebFrame *)sourceFrame
2274 return _sourceFrame;
2279 @implementation WebFrame
2283 return [self initWithName:nil webFrameView:nil webView:nil];
2286 // FIXME: this method can't work any more and should be marked deprecated
2287 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2289 return [self _initWithWebFrameView:fv webView:v bridge:nil];
2294 ASSERT(_private->bridge == nil);
2304 ASSERT(_private->bridge == nil);
2313 return [[self _bridge] name];
2316 - (WebFrameView *)frameView
2318 return [_private webFrameView];
2321 - (WebView *)webView
2323 return [[[self _bridge] page] webView];
2326 - (DOMDocument *)DOMDocument
2328 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2331 - (DOMHTMLElement *)frameElement
2333 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2336 - (WebDataSource *)provisionalDataSource
2338 return [_private->frameLoader provisionalDataSource];
2341 - (WebDataSource *)dataSource
2343 return [_private->frameLoader dataSource];
2346 - (void)loadRequest:(NSURLRequest *)request
2348 // FIXME: is this the right place to reset loadType? Perhaps this should be done
2349 // after loading is finished or aborted.
2350 [_private->frameLoader setLoadType:WebFrameLoadTypeStandard];
2351 [_private->frameLoader _loadRequest:request archive:nil];
2354 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2356 NSURLRequest *request = [self _webDataRequestForData:data
2358 textEncodingName:encodingName
2360 unreachableURL:unreachableURL];
2361 [self loadRequest:request];
2365 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2367 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2370 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2372 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
2373 [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
2376 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2378 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2381 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2383 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2386 - (void)loadArchive:(WebArchive *)archive
2388 WebResource *mainResource = [archive mainResource];
2390 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2391 MIMEType:[mainResource MIMEType]
2392 textEncodingName:[mainResource textEncodingName]
2393 baseURL:[mainResource URL]
2394 unreachableURL:nil];
2395 [_private->frameLoader _loadRequest:request archive:archive];
2401 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2402 if (_private->isStoppingLoad)
2405 _private->isStoppingLoad = YES;
2407 [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2409 [self _stopLoadingSubframes];
2410 [_private->frameLoader stopLoading];
2412 _private->isStoppingLoad = NO;
2417 [_private->frameLoader reload];
2420 - (WebFrame *)findFrameNamed:(NSString *)name
2422 return Frame([[self _bridge] findFrameNamed:name]);
2425 - (WebFrame *)parentFrame
2427 return [[Frame([[self _bridge] parent]) retain] autorelease];
2430 - (NSArray *)childFrames
2432 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2433 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2434 [children addObject:child];
2441 @implementation WebFrame (WebFrameLoaderClient)
2443 - (void)_resetBackForwardList
2445 // Note this doesn't verify the current load type as a b/f operation because it is called from
2446 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
2447 ASSERT(self == [[self webView] mainFrame]);
2448 WebHistoryItem *resetItem = [_private currentItem];
2450 [[[self webView] backForwardList] goToItem:resetItem];
2453 - (BOOL)_quickRedirectComing
2455 return _private->quickRedirectComing;
2458 - (BOOL)_provisionalItemIsTarget
2460 return [[_private provisionalItem] isTargetItem];
2463 - (BOOL)_loadProvisionalItemFromPageCache
2465 WebHistoryItem *item = [_private provisionalItem];
2466 if (![item hasPageCache])
2468 NSDictionary *pageCache = [item pageCache];
2469 if (![pageCache objectForKey:WebCorePageCacheStateKey])
2471 LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
2472 [[self provisionalDataSource] _loadFromPageCache:pageCache];