2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import <WebKit/WebFrameInternal.h>
31 #import <WebKit/DOM.h>
32 #import <WebKit/WebArchive.h>
33 #import <WebKit/WebBackForwardList.h>
34 #import <WebKit/WebFrameBridge.h>
35 #import <WebKit/WebDataProtocol.h>
36 #import <WebKit/WebDataSourcePrivate.h>
37 #import <WebKit/WebDefaultResourceLoadDelegate.h>
38 #import <WebKit/WebDefaultUIDelegate.h>
39 #import <WebKit/WebDocumentInternal.h>
40 #import <WebKit/WebFormDataStream.h>
41 #import <WebKit/WebFrameLoadDelegate.h>
42 #import <WebKit/WebFrameViewInternal.h>
43 #import <WebKit/WebHistoryPrivate.h>
44 #import <WebKit/WebHistoryItemPrivate.h>
45 #import <WebKit/WebHTMLRepresentationPrivate.h>
46 #import <WebKit/WebHTMLViewInternal.h>
47 #import <WebKit/WebHTMLViewPrivate.h>
48 #import <WebKit/WebKitErrorsPrivate.h>
49 #import <WebKit/WebKitLogging.h>
50 #import <WebKit/WebKitNSStringExtras.h>
51 #import <WebKit/WebKitStatisticsPrivate.h>
52 #import <WebKit/WebNetscapePluginDocumentView.h>
53 #import <WebKit/WebNetscapePluginEmbeddedView.h>
54 #import <WebKit/WebNSObjectExtras.h>
55 #import <WebKit/WebNSURLExtras.h>
56 #import <WebKit/WebNSURLRequestExtras.h>
57 #import <WebKit/WebNullPluginView.h>
58 #import <WebKit/WebPreferencesPrivate.h>
59 #import <WebKit/WebPlugin.h>
60 #import <WebKit/WebPluginController.h>
61 #import <WebKit/WebPluginDocumentView.h>
62 #import <WebKit/WebResourceLoadDelegate.h>
63 #import <WebKit/WebResourcePrivate.h>
64 #import <WebKit/WebViewInternal.h>
65 #import <WebKit/WebUIDelegate.h>
66 #import <WebKit/WebScriptDebugDelegatePrivate.h>
67 #import <WebKitSystemInterface.h>
69 #import <objc/objc-runtime.h>
72 static const char * const stateNames[] = {
73 "WebFrameStateProvisional",
74 "WebFrameStateCommittedPage",
75 "WebFrameStateComplete"
80 Here is the current behavior matrix for four types of navigations:
84 Restore form state: YES
85 Restore scroll and focus state: YES
86 WF Cache policy: NSURLRequestUseProtocolCachePolicy
87 Add to back/forward list: YES
91 Restore form state: YES
92 Restore scroll and focus state: YES
93 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
94 Add to back/forward list: NO
96 Reload (meaning only the reload button):
98 Restore form state: NO
99 Restore scroll and focus state: YES
100 WF Cache policy: NSURLRequestReloadIgnoringCacheData
101 Add to back/forward list: NO
103 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
105 Restore form state: NO
106 Restore scroll and focus state: NO, reset to initial conditions
107 WF Cache policy: NSURLRequestReloadIgnoringCacheData
108 Add to back/forward list: NO
111 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
112 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
113 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
115 @interface NSObject (WebExtraPerformMethod)
117 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3;
121 @implementation NSObject (WebExtraPerformMethod)
123 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3
125 return objc_msgSend(self, aSelector, object1, object2, object3);
130 // One day we might want to expand the use of this kind of class such that we'd receive one
131 // over the bridge, and possibly hand it on through to the FormsDelegate.
132 // Today it is just used internally to keep some state as we make our way through a bunch
133 // layers while doing a load.
134 @interface WebFormState : NSObject
137 NSDictionary *_values;
138 WebFrame *_sourceFrame;
140 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame;
141 - (DOMElement *)form;
142 - (NSDictionary *)values;
143 - (WebFrame *)sourceFrame;
146 @interface WebFrame (ForwardDecls)
147 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState;
148 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
149 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
151 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
152 - (void)_restoreScrollPositionAndViewState;
154 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
155 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
156 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
157 - (void)_stopLoadingSubframes;
160 @interface WebFrame (FrameTraversal)
161 - (WebFrame *)_firstChildFrame;
162 - (WebFrame *)_lastChildFrame;
163 - (unsigned)_childFrameCount;
164 - (WebFrame *)_previousSiblingFrame;
165 - (WebFrame *)_nextSiblingFrame;
166 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
169 @interface WebFramePrivate : NSObject
172 WebFrameView *webFrameView;
173 WebDataSource *dataSource;
174 WebDataSource *provisionalDataSource;
175 WebFrameBridge *bridge;
177 WebFrameLoadType loadType;
178 WebHistoryItem *currentItem; // BF item for our current content
179 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
180 // (only known when navigating to a pre-existing BF item)
181 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
183 WebPolicyDecisionListener *listener;
184 // state we'll need to continue after waiting for the policy delegate's decision
185 NSURLRequest *policyRequest;
186 NSString *policyFrameName;
189 WebFormState *policyFormState;
190 WebDataSource *policyDataSource;
191 WebFrameLoadType policyLoadType;
193 BOOL quickRedirectComing;
195 BOOL delegateIsHandlingProvisionalLoadError;
196 BOOL delegateIsDecidingNavigationPolicy;
197 BOOL delegateIsHandlingUnimplementablePolicy;
198 BOOL firstLayoutDone;
200 id internalLoadDelegate;
201 WebScriptDebugger *scriptDebugger;
203 NSString *frameNamespace;
206 - (void)setWebFrameView:(WebFrameView *)v;
207 - (WebFrameView *)webFrameView;
208 - (void)setDataSource:(WebDataSource *)d;
209 - (WebDataSource *)dataSource;
210 - (void)setProvisionalDataSource:(WebDataSource *)d;
211 - (WebDataSource *)provisionalDataSource;
212 - (WebFrameLoadType)loadType;
213 - (void)setLoadType:(WebFrameLoadType)loadType;
215 - (void)setProvisionalItem:(WebHistoryItem *)item;
216 - (WebHistoryItem *)provisionalItem;
217 - (void)setPreviousItem:(WebHistoryItem *)item;
218 - (WebHistoryItem *)previousItem;
219 - (void)setCurrentItem:(WebHistoryItem *)item;
220 - (WebHistoryItem *)currentItem;
224 @implementation WebFramePrivate
233 state = WebFrameStateComplete;
234 loadType = WebFrameLoadTypeStandard;
241 [webFrameView release];
242 [dataSource release];
243 [provisionalDataSource release];
245 [currentItem release];
246 [provisionalItem release];
247 [previousItem release];
249 [scriptDebugger release];
251 ASSERT(listener == nil);
252 ASSERT(policyRequest == nil);
253 ASSERT(policyFrameName == nil);
254 ASSERT(policyTarget == nil);
255 ASSERT(policyFormState == nil);
256 ASSERT(policyDataSource == nil);
257 ASSERT(frameNamespace == nil);
262 - (WebFrameView *)webFrameView { return webFrameView; }
263 - (void)setWebFrameView: (WebFrameView *)v
266 [webFrameView release];
270 - (WebDataSource *)dataSource { return dataSource; }
271 - (void)setDataSource: (WebDataSource *)d
274 [dataSource release];
278 - (WebDataSource *)provisionalDataSource { return provisionalDataSource; }
279 - (void)setProvisionalDataSource: (WebDataSource *)d
281 ASSERT(!d || !provisionalDataSource);
283 [provisionalDataSource release];
284 provisionalDataSource = d;
287 - (WebFrameLoadType)loadType { return loadType; }
288 - (void)setLoadType: (WebFrameLoadType)t
293 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
294 - (void)setProvisionalItem: (WebHistoryItem *)item
297 [provisionalItem release];
298 provisionalItem = item;
301 - (WebHistoryItem *)previousItem { return previousItem; }
302 - (void)setPreviousItem:(WebHistoryItem *)item
305 [previousItem release];
309 - (WebHistoryItem *)currentItem { return currentItem; }
310 - (void)setCurrentItem:(WebHistoryItem *)item
313 [currentItem release];
319 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
321 return [(WebFrameBridge *)bridge webFrame];
324 @implementation WebFrame (FrameTraversal)
325 - (WebFrame *)_firstChildFrame
327 return Frame([[self _bridge] firstChild]);
330 - (WebFrame *)_lastChildFrame
332 return Frame([[self _bridge] lastChild]);
335 - (unsigned)_childFrameCount
337 return [[self _bridge] childCount];
340 - (WebFrame *)_previousSiblingFrame;
342 return Frame([[self _bridge] previousSibling]);
345 - (WebFrame *)_nextSiblingFrame;
347 return Frame([[self _bridge] nextSibling]);
350 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
352 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
357 @implementation WebFrame (WebPrivate)
359 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
361 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
362 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
363 [request _webDataRequestSetData:data];
364 [request _webDataRequestSetEncoding:encodingName];
365 [request _webDataRequestSetBaseURL:URL];
366 [request _webDataRequestSetUnreachableURL:unreachableURL];
367 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
371 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
373 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
374 if (unreachableURL == nil) {
378 if (_private->policyLoadType != WebFrameLoadTypeForward
379 && _private->policyLoadType != WebFrameLoadTypeBack
380 && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
384 // We only treat unreachableURLs specially during the delegate callbacks
385 // for provisional load errors and navigation policy decisions. The former
386 // case handles well-formed URLs that can't be loaded, and the latter
387 // case handles malformed URLs and unknown schemes. Loading alternate content
388 // at other times behaves like a standard load.
389 WebDataSource *compareDataSource = nil;
390 if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
391 compareDataSource = _private->policyDataSource;
392 } else if (_private->delegateIsHandlingProvisionalLoadError) {
393 compareDataSource = [self provisionalDataSource];
396 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
399 - (void)_loadRequest:(NSURLRequest *)request subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
401 WebFrameLoadType loadType;
403 // note this copies request
404 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
405 NSMutableURLRequest *r = [newDataSource request];
406 [self _addExtraFieldsToRequest:r alwaysFromRequest: NO];
407 if ([self _shouldTreatURLAsSameAsCurrent:[request URL]]) {
408 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
409 loadType = WebFrameLoadTypeSame;
411 loadType = WebFrameLoadTypeStandard;
414 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
415 [newDataSource _addSubresources:subresources];
416 [newDataSource _addSubframeArchives:subframeArchives];
418 // When we loading alternate content for an unreachable URL that we're
419 // visiting in the b/f list, we treat it as a reload so the b/f list
420 // is appropriately maintained.
421 if ([self _shouldReloadToHandleUnreachableURLFromRequest:request]) {
422 ASSERT(loadType == WebFrameLoadTypeStandard);
423 loadType = WebFrameLoadTypeReload;
426 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
427 [newDataSource release];
430 // helper method used in various nav cases below
431 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
433 if ([[self dataSource] _URLForHistory] != nil) {
434 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
435 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
436 [[[self webView] backForwardList] addItem:bfItem];
440 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
442 WebDataSource *dataSrc = [self dataSource];
443 NSURLRequest *request;
444 NSURL *unreachableURL = [dataSrc unreachableURL];
447 WebHistoryItem *bfItem;
450 request = [dataSrc _originalRequest];
452 request = [dataSrc request];
455 if (unreachableURL != nil) {
456 URL = unreachableURL;
457 originalURL = unreachableURL;
460 originalURL = [[dataSrc _originalRequest] URL];
463 LOG (History, "creating item for %@", request);
465 // Frames that have never successfully loaded any content
466 // may have no URL at all. Currently our history code can't
467 // deal with such things, so we nip that in the bud here.
468 // Later we may want to learn to live with nil for URL.
469 // See bug 3368236 and related bugs for more information.
471 URL = [NSURL URLWithString:@"about:blank"];
473 if (originalURL == nil) {
474 originalURL = [NSURL URLWithString:@"about:blank"];
477 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
478 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
480 // save form state if this is a POST
481 [bfItem _setFormInfoFromRequest:request];
483 // Set the item for which we will save document state
484 [_private setPreviousItem:[_private currentItem]];
485 [_private setCurrentItem:bfItem];
491 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
492 The item that was the target of the user's navigation is designated as the "targetItem".
493 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
494 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
496 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
498 WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
500 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
501 if (!(doClip && self == targetFrame)) {
502 // save frame state for items that aren't loading (khtml doesn't save those)
503 [_private->bridge saveDocumentState];
505 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
506 [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
508 if (self == targetFrame)
509 [bfItem setIsTargetItem:YES];
514 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
516 return Frame([[self _bridge] childFrameNamed:name]);
519 // FIXME: this exists only as a convenience for Safari, consider moving there
520 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
522 return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
527 return [_private->bridge isFrameSet];
530 - (void)_detachChildren
532 // FIXME: is it really necessary to do this in reverse order any more?
533 WebFrame *child = [self _lastChildFrame];
534 WebFrame *prev = [child _previousSiblingFrame];
535 for (; child; child = prev, prev = [child _previousSiblingFrame])
536 [child _detachFromParent];
539 - (void)_closeOldDataSources
541 // FIXME: is it important for this traversal to be postorder instead of preorder?
542 // FIXME: add helpers for postorder traversal?
543 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
544 [child _closeOldDataSources];
546 if (_private->dataSource)
547 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] willCloseFrame:self];
550 - (void)_detachFromParent
552 WebFrameBridge *bridge = _private->bridge;
557 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
558 [self _detachChildren];
560 [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
562 [self _setDataSource:nil];
563 [_private setWebFrameView:nil];
565 [self retain]; // retain self temporarily because dealloc can re-enter this method
568 [[[self parentFrame] _bridge] removeChild:bridge];
570 _private->bridge = nil;
575 - (void)_setDataSource:(WebDataSource *)ds
577 if (ds == nil && _private->dataSource == nil) {
581 ASSERT(ds != _private->dataSource);
583 if (_private->dataSource) {
584 // Make sure that any work that is triggered by resigning first reponder can get done.
585 // The main example where this came up is the textDidEndEditing that is sent to the
586 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
587 // remove the views as a side-effect of freeing the bridge, at which point we can't
588 // post the FormDelegate messages.
590 // Note that this can also take FirstResponder away from a child of our frameView that
591 // is not in a child frame's view. This is OK because we are in the process
592 // of loading new content, which will blow away all editors in this top frame, and if
593 // a non-editor is firstReponder it will not be affected by endEditingFor:.
594 // Potentially one day someone could write a DocView whose editors were not all
595 // replaced by loading new content, but that does not apply currently.
596 NSView *frameView = [self frameView];
597 NSWindow *window = [frameView window];
598 NSResponder *firstResp = [window firstResponder];
599 if ([firstResp isKindOfClass:[NSView class]]
600 && [(NSView *)firstResp isDescendantOf:frameView])
602 [window endEditingFor:firstResp];
605 [self _detachChildren];
607 [_private->dataSource _setWebFrame:nil];
609 ASSERT(![self _childFrameCount]);
612 [_private setDataSource:ds];
613 [ds _setWebFrame:self];
616 - (void)_setLoadType: (WebFrameLoadType)t
618 [_private setLoadType:t];
621 - (WebFrameLoadType)_loadType
623 return [_private loadType];
626 - (void)_makeDocumentView
628 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:_private->dataSource];
633 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
634 WebFrameView *v = _private->webFrameView;
635 [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
636 [self _updateDrawsBackground];
637 [_private->bridge installInFrame:[v _scrollView]];
639 // Call setDataSource on the document view after it has been placed in the view hierarchy.
640 // This what we for the top-level view, so should do this for views in subframes as well.
641 [documentView setDataSource:_private->dataSource];
644 - (void)_receivedMainResourceError:(NSError *)error
646 if ([self _state] == WebFrameStateProvisional) {
647 NSURL *failedURL = [[_private->provisionalDataSource _originalRequest] URL];
648 // When we are pre-commit, the currentItem is where the pageCache data resides
649 NSDictionary *pageCache = [[_private currentItem] pageCache];
650 [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
651 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
652 [[_private currentItem] setHasPageCache:NO];
656 - (void)_transitionToCommitted:(NSDictionary *)pageCache
658 ASSERT([self webView] != nil);
660 switch ([self _state]) {
661 case WebFrameStateProvisional:
663 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
665 WebFrameLoadType loadType = [self _loadType];
666 if (loadType == WebFrameLoadTypeForward ||
667 loadType == WebFrameLoadTypeBack ||
668 loadType == WebFrameLoadTypeIndexedBackForward ||
669 (loadType == WebFrameLoadTypeReload && [_private->provisionalDataSource unreachableURL] != nil))
671 // Once committed, we want to use current item for saving DocState, and
672 // the provisional item for restoring state.
673 // Note previousItem must be set before we close the URL, which will
674 // happen when the data source is made non-provisional below
675 [_private setPreviousItem:[_private currentItem]];
676 ASSERT([_private provisionalItem]);
677 [_private setCurrentItem:[_private provisionalItem]];
678 [_private setProvisionalItem:nil];
681 // The call to closeURL invokes the unload event handler, which can execute arbitrary
682 // JavaScript. If the script initiates a new load, we need to abandon the current load,
683 // or the two will stomp each other.
684 WebDataSource *pd = _private->provisionalDataSource;
685 [[self _bridge] closeURL];
686 if (pd != _private->provisionalDataSource)
689 // Set the committed data source on the frame.
690 [self _setDataSource:_private->provisionalDataSource];
692 [self _setProvisionalDataSource: nil];
694 [self _setState: WebFrameStateCommittedPage];
696 // Handle adding the URL to the back/forward list.
697 WebDataSource *ds = [self dataSource];
698 NSString *ptitle = [ds pageTitle];
701 case WebFrameLoadTypeForward:
702 case WebFrameLoadTypeBack:
703 case WebFrameLoadTypeIndexedBackForward:
704 if ([[self webView] backForwardList]) {
705 // Must grab the current scroll position before disturbing it
706 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
708 // Create a document view for this document, or used the cached view.
710 NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
711 ASSERT(cachedView != nil);
712 [[self frameView] _setDocumentView: cachedView];
715 [self _makeDocumentView];
719 case WebFrameLoadTypeReload:
720 case WebFrameLoadTypeSame:
721 case WebFrameLoadTypeReplace:
723 WebHistoryItem *currItem = [_private currentItem];
724 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
725 [currItem setHasPageCache:NO];
726 if (loadType == WebFrameLoadTypeReload) {
727 [self _saveScrollPositionAndViewStateToItem:currItem];
729 NSURLRequest *request = [ds request];
730 if ([request _webDataRequestUnreachableURL] == nil) {
731 // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
732 [currItem setURL:[request URL]];
734 // Update the last visited time. Mostly interesting for URL autocompletion
736 NSURL *URL = [[[ds _originalRequest] URL] _webkit_canonicalize];
737 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
738 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
740 [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
742 [self _makeDocumentView];
746 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
747 case WebFrameLoadTypeReloadAllowingStaleData:
748 [self _makeDocumentView];
751 case WebFrameLoadTypeStandard:
752 if (![ds _isClientRedirect]) {
753 // Add item to history and BF list
754 NSURL *URL = [ds _URLForHistory];
755 if (URL && ![URL _web_isEmpty]){
756 ASSERT([self webView]);
757 if (![[[self webView] preferences] privateBrowsingEnabled]) {
758 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
760 [entry setTitle: ptitle];
762 [self _addBackForwardItemClippedAtTarget:YES];
766 NSURLRequest *request = [ds request];
768 // update the URL in the BF list that we made before the redirect, unless
769 // this is alternate content for an unreachable URL (we want the BF list
770 // item to remember the unreachable URL in case it becomes reachable later)
771 if ([request _webDataRequestUnreachableURL] == nil) {
772 [[_private currentItem] setURL:[request URL]];
774 // clear out the form data so we don't repost it to the wrong place if we
775 // ever go back/forward to this item
776 [[_private currentItem] _setFormInfoFromRequest:request];
778 // We must also clear out form data so we don't try to restore it into the incoming page,
782 [self _makeDocumentView];
785 case WebFrameLoadTypeInternal:
786 // Add an item to the item tree for this frame
787 ASSERT(![ds _isClientRedirect]);
788 WebFrame *parentFrame = [self parentFrame];
790 WebHistoryItem *parentItem = [parentFrame->_private currentItem];
791 // The only case where parentItem==nil should be when a parent frame loaded an
792 // empty URL, which doesn't set up a current item in that parent.
794 [parentItem addChildItem:[self _createItem: YES]];
796 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
797 // for a top-level frame, but that was a likely explanation for those crashes,
798 // so let's guard against it.
799 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
800 ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
802 [self _makeDocumentView];
805 // FIXME Remove this check when dummy ds is removed. An exception should be thrown
806 // if we're in the WebFrameLoadTypeUninitialized state.
808 ASSERT_NOT_REACHED();
812 // Tell the client we've committed this URL.
813 ASSERT([[self frameView] documentView] != nil);
814 [[self webView] _didCommitLoadForFrame: self];
815 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didCommitLoadForFrame:self];
817 // If we have a title let the WebView know about it.
819 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
820 didReceiveTitle:ptitle
826 case WebFrameStateCommittedPage:
827 case WebFrameStateComplete:
830 ASSERT_NOT_REACHED();
835 - (void)_commitProvisionalLoad:(NSDictionary *)pageCache
837 WebFrameLoadType loadType = [self _loadType];
838 bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
840 WebDataSource *provisionalDataSource = [self provisionalDataSource];
841 NSURLResponse *response = [provisionalDataSource response];
843 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
844 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
846 if (loadType != WebFrameLoadTypeReplace)
847 [self _closeOldDataSources];
850 [provisionalDataSource _makeRepresentation];
852 [self _transitionToCommitted:pageCache];
854 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
855 NSURL *URL = baseURL ? baseURL : [response URL];
857 if (!URL || [URL _web_isEmpty])
858 URL = [NSURL URLWithString:@"about:blank"];
860 [[self _bridge] openURL:URL
862 contentType:[response MIMEType]
863 refresh:[headers objectForKey:@"Refresh"]
864 lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
865 pageCache:pageCache];
870 - (BOOL)_canCachePage
872 return [[[self webView] backForwardList] _usesPageCache];
875 - (void)_purgePageCache
877 // This method implements the rule for purging the page cache.
878 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
879 unsigned pagesCached = 0;
880 WebBackForwardList *backForwardList = [[self webView] backForwardList];
881 NSArray *backList = [backForwardList backListWithLimit: 999999];
882 WebHistoryItem *oldestNonSnapbackItem = nil;
885 for (i = 0; i < [backList count]; i++){
886 WebHistoryItem *item = [backList objectAtIndex: i];
887 if ([item hasPageCache]){
888 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
889 oldestNonSnapbackItem = item;
894 // Snapback items are never directly purged here.
895 if (pagesCached >= sizeLimit) {
896 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
897 [oldestNonSnapbackItem setHasPageCache:NO];
901 - (WebFrameState)_state
903 return _private->state;
906 static CFAbsoluteTime _timeOfLastCompletedLoad;
907 + (CFAbsoluteTime)_timeOfLastCompletedLoad
909 return _timeOfLastCompletedLoad;
912 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
914 NSMutableDictionary *pageCache;
916 [item setHasPageCache: YES];
918 if (![_private->bridge saveDocumentToPageCache]){
919 [item setHasPageCache: NO];
923 pageCache = [item pageCache];
924 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
925 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
926 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
931 - (void)_setState: (WebFrameState)newState
933 LOG(Loading, "%@: transition from %s to %s", [self name], stateNames[_private->state], stateNames[newState]);
935 LOG(Timing, "%@: transition from %s to %s, %f seconds since start of document load", [self name], stateNames[_private->state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[self webView] mainFrame] dataSource] _loadingStartedTime]);
937 if (newState == WebFrameStateComplete && self == [[self webView] mainFrame]){
938 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[self dataSource] _loadingStartedTime]);
941 _private->state = newState;
943 if (_private->state == WebFrameStateProvisional) {
944 _private->firstLayoutDone = NO;
945 [_private->bridge provisionalLoadStarted];
947 // FIXME: This is OK as long as no one resizes the window,
948 // but in the case where someone does, it means garbage outside
949 // the occupied part of the scroll view.
950 [[[self frameView] _scrollView] setDrawsBackground:NO];
952 // Cache the page, if possible.
953 // Don't write to the cache if in the middle of a redirect, since we will want to
954 // store the final page we end up on.
955 // No point writing to the cache on a reload or loadSame, since we will just write
956 // over it again when we leave that page.
957 WebHistoryItem *item = [_private currentItem];
958 WebFrameLoadType loadType = [self _loadType];
959 if ([self _canCachePage]
960 && [_private->bridge canCachePage]
962 && !_private->quickRedirectComing
963 && loadType != WebFrameLoadTypeReload
964 && loadType != WebFrameLoadTypeReloadAllowingStaleData
965 && loadType != WebFrameLoadTypeSame
966 && ![[self dataSource] isLoading]
967 && ![[self dataSource] _isStopping])
969 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
970 if (![item pageCache]){
972 // Add the items to this page's cache.
973 if ([self _createPageCacheForItem:item]) {
974 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
976 // See if any page caches need to be purged after the addition of this
978 [self _purgePageCache];
981 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
986 // Put the document into a null state, so it can be restored correctly.
987 [_private->bridge clear];
991 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
995 if (_private->state == WebFrameStateComplete) {
996 NSScrollView *sv = [[self frameView] _scrollView];
997 if ([[self webView] drawsBackground])
998 [sv setDrawsBackground:YES];
999 [_private setPreviousItem:nil];
1000 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
1002 [[self dataSource] _stopRecordingResponses];
1004 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1005 if (_private->dataSource)
1006 _private->firstLayoutDone = YES;
1010 // Called after we send an openURL:... down to WebCore.
1013 if ([self _loadType] == WebFrameLoadTypeStandard && [[self dataSource] _isClientRedirect]) {
1014 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
1015 // khtml has closed the URL and saved away the form state.
1016 WebHistoryItem *item = [_private currentItem];
1017 [item setDocumentState:nil];
1018 [item setScrollPoint:NSZeroPoint];
1021 if ([[self dataSource] _loadingFromPageCache]){
1022 // Force a layout to update view size and thereby update scrollbars.
1023 NSView <WebDocumentView> *view = [[self frameView] documentView];
1024 if ([view isKindOfClass:[WebHTMLView class]]) {
1025 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
1027 [view setNeedsLayout: YES];
1030 NSArray *responses = [[self dataSource] _responses];
1031 NSURLResponse *response;
1032 int i, count = [responses count];
1033 for (i = 0; i < count; i++){
1034 response = [responses objectAtIndex: i];
1035 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
1038 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
1039 [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
1040 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:[response expectedContentLength] error:error];
1044 // Release the resources kept in the page cache. They will be
1045 // reset when we leave this page. The core side of the page cache
1046 // will have already been invalidated by the bridge to prevent
1047 // premature release.
1048 [[_private currentItem] setHasPageCache: NO];
1050 [[self dataSource] _setPrimaryLoadComplete: YES];
1051 // why only this frame and not parent frames?
1052 [self _checkLoadCompleteForThisFrame];
1056 - (void)_checkLoadCompleteForThisFrame
1058 ASSERT([self webView] != nil);
1060 switch ([self _state]) {
1061 case WebFrameStateProvisional:
1063 WebDataSource *pd = [self provisionalDataSource];
1065 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
1066 // If we've received any errors we may be stuck in the provisional state and actually
1068 NSError *error = [pd _mainDocumentError];
1070 // Check all children first.
1071 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
1072 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
1073 BOOL shouldReset = YES;
1074 if (![pd isLoading]) {
1075 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
1076 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
1077 _private->delegateIsHandlingProvisionalLoadError = YES;
1078 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1079 didFailProvisionalLoadWithError:error
1081 _private->delegateIsHandlingProvisionalLoadError = NO;
1082 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1084 // FIXME: can stopping loading here possibly have
1085 // any effect, if isLoading is false, which it
1086 // must be, to be in this branch of the if? And is it ok to just do
1087 // a full-on stopLoading?
1088 [self _stopLoadingSubframes];
1092 // Finish resetting the load state, but only if another load hasn't been started by the
1093 // delegate callback.
1094 if (pd == _private->provisionalDataSource) {
1095 [self _setProvisionalDataSource:nil];
1097 [[self webView] _progressCompleted:self];
1099 [self _setState:WebFrameStateComplete];
1101 NSURL *unreachableURL = [_private->provisionalDataSource unreachableURL];
1102 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
1107 if (shouldReset && resetItem != nil) {
1108 [[[self webView] backForwardList] goToItem:resetItem];
1114 case WebFrameStateCommittedPage:
1116 WebDataSource *ds = [self dataSource];
1118 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
1119 if (![ds isLoading]) {
1120 WebFrameView *thisView = [self frameView];
1121 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1122 ASSERT(thisDocumentView != nil);
1124 // FIXME: need to avoid doing this in the non-HTML case or the bridge may assert.
1125 // Should instead make sure the bridge/part is in the proper state even for
1126 // non-HTML content, or make a call to the document and let it deal with the bridge.
1128 [self _setState:WebFrameStateComplete];
1130 // FIXME: Is this subsequent work important if we already navigated away?
1131 // Maybe there are bugs because of that, or extra work we can skip because
1132 // the new page is ready.
1134 // Tell the just loaded document to layout. This may be necessary
1135 // for non-html content that needs a layout message.
1136 if (!([[self dataSource] _isDocumentHTML])) {
1137 [thisDocumentView setNeedsLayout:YES];
1138 [thisDocumentView layout];
1139 [thisDocumentView setNeedsDisplay:YES];
1142 // If the user had a scroll point scroll to it. This will override
1143 // the anchor point. After much discussion it was decided by folks
1144 // that the user scroll point should override the anchor point.
1145 if ([[self webView] backForwardList]) {
1146 switch ([self _loadType]) {
1147 case WebFrameLoadTypeForward:
1148 case WebFrameLoadTypeBack:
1149 case WebFrameLoadTypeIndexedBackForward:
1150 case WebFrameLoadTypeReload:
1151 [self _restoreScrollPositionAndViewState];
1154 case WebFrameLoadTypeStandard:
1155 case WebFrameLoadTypeInternal:
1156 case WebFrameLoadTypeReloadAllowingStaleData:
1157 case WebFrameLoadTypeSame:
1158 case WebFrameLoadTypeReplace:
1163 ASSERT_NOT_REACHED();
1168 NSError *error = [ds _mainDocumentError];
1170 [[self webView] _didFailLoadWithError:error forFrame:self];
1171 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1172 didFailLoadWithError:error
1174 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
1176 [[self webView] _didFinishLoadForFrame:self];
1177 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1178 didFinishLoadForFrame:self];
1179 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1182 [[self webView] _progressCompleted: self];
1189 case WebFrameStateComplete:
1191 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
1192 // Even if already complete, we might have set a previous item on a frame that
1193 // didn't do any data loading on the past transaction. Make sure to clear these out.
1194 [_private setPreviousItem:nil];
1199 // Yikes! Serious horkage.
1200 ASSERT_NOT_REACHED();
1203 - (void)_handledOnloadEvents
1205 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
1208 // Called every time a resource is completely loaded, or an error is received.
1209 - (void)_checkLoadComplete
1211 ASSERT([self webView] != nil);
1213 for (WebFrame *frame = self; frame; frame = [frame parentFrame])
1214 [frame _checkLoadCompleteForThisFrame];
1217 - (WebFrameBridge *)_bridge
1219 return _private->bridge;
1222 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1224 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1225 WebView *wv = [self webView];
1226 _private->delegateIsHandlingUnimplementablePolicy = YES;
1227 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];
1228 _private->delegateIsHandlingUnimplementablePolicy = NO;
1231 - (void)_clearProvisionalDataSource
1233 [self _setProvisionalDataSource:nil];
1236 // helper method that determines whether the subframes described by the item's subitems
1237 // match our own current frameset
1238 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1240 NSArray *childItems = [item children];
1241 int numChildItems = [childItems count];
1242 int numChildFrames = [self _childFrameCount];
1243 if (numChildFrames != numChildItems)
1247 for (i = 0; i < numChildItems; i++) {
1248 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1249 //Search recursive here?
1250 if (![self _immediateChildFrameNamed:itemTargetName])
1251 return NO; // couldn't match the i'th itemTarget
1254 return YES; // found matches for all itemTargets
1257 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1259 return !(([currentURL fragment] || [destinationURL fragment]) &&
1260 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1263 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1264 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1266 NSURL *currentURL = [[[self dataSource] request] URL];
1268 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1271 NSArray *childItems = [item children];
1272 WebHistoryItem *childItem;
1273 WebFrame *childFrame;
1274 int i, count = [childItems count];
1275 for (i = 0; i < count; i++){
1276 childItem = [childItems objectAtIndex:i];
1277 childFrame = [self _immediateChildFrameNamed:[childItem target]];
1278 if (![childFrame _URLsMatchItem: childItem])
1285 // loads content into this frame, as specified by item
1286 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1288 NSURL *itemURL = [item URL];
1289 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1290 NSURL *currentURL = [[[self dataSource] request] URL];
1291 NSArray *formData = [item formData];
1293 // Are we navigating to an anchor within the page?
1294 // Note if we have child frames we do a real reload, since the child frames might not
1295 // match our current frame structure, or they might not have the right content. We could
1296 // check for all that as an additional optimization.
1297 // We also do not do anchor-style navigation if we're posting a form.
1299 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1300 // Perhaps they should.
1301 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1304 // FIXME: We need to normalize the code paths for anchor navigation. Something
1305 // like the following line of code should be done, but also accounting for correct
1306 // updates to the back/forward list and scroll position.
1307 // rjw 4/9/03 See 3223929.
1308 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1310 // must do this maintenance here, since we don't go through a real page reload
1311 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1312 // FIXME: form state might want to be saved here too
1314 // FIXME: Perhaps we can use scrollToAnchorWithURL here instead and remove the older scrollToAnchor:?
1315 NSString *anchor = [[item URLString] _webkit_URLFragment];
1317 [[_private->dataSource _bridge] scrollToAnchor: anchor];
1319 // must do this maintenance here, since we don't go through a real page reload
1320 [_private setCurrentItem:item];
1321 [self _restoreScrollPositionAndViewState];
1323 // Fake the URL change by updating the data source's request. This will no longer
1324 // be necessary if we do the better fix described above.
1325 NSMutableURLRequest *hackedRequest = [[[self dataSource] request] mutableCopy];
1326 [hackedRequest setURL: itemURL];
1327 [[self dataSource] __adoptRequest:hackedRequest];
1328 [hackedRequest release];
1330 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1331 didChangeLocationWithinPageForFrame:self];
1332 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1334 // Remember this item so we can traverse any child items as child frames load
1335 [_private setProvisionalItem:item];
1337 WebDataSource *newDataSource;
1338 BOOL inPageCache = NO;
1340 // Check if we'll be using the page cache. We only use the page cache
1341 // if one exists and it is less than _backForwardCacheExpirationInterval
1342 // seconds old. If the cache is expired it gets flushed here.
1343 if ([item hasPageCache]){
1344 NSDictionary *pageCache = [item pageCache];
1345 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1346 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1348 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1349 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1350 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
1354 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]);
1355 [item setHasPageCache: NO];
1360 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1361 [self _addExtraFieldsToRequest:request alwaysFromRequest: (formData != nil)?YES:NO];
1363 // If this was a repost that failed the page cache, we might try to repost the form.
1364 NSDictionary *action;
1366 [request setHTTPMethod:@"POST"];
1367 [request _web_setHTTPReferrer:[item formReferrer]];
1368 webSetHTTPBody(request, formData);
1369 [request _web_setHTTPContentType:[item formContentType]];
1371 // Slight hack to test if the WF cache contains the page we're going to. We want
1372 // to know this before talking to the policy delegate, since it affects whether we
1373 // show the DoYouReallyWantToRepost nag.
1375 // This trick has a small bug (3123893) where we might find a cache hit, but then
1376 // have the item vanish when we try to use it in the ensuing nav. This should be
1377 // extremely rare, but in that case the user will get an error on the navigation.
1378 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1379 NSURLResponse *synchResponse = nil;
1380 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1381 if (synchResponse == nil) {
1383 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1384 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1386 // We can use the cache, don't use navType=resubmit
1387 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1391 case WebFrameLoadTypeReload:
1392 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1394 case WebFrameLoadTypeBack:
1395 case WebFrameLoadTypeForward:
1396 case WebFrameLoadTypeIndexedBackForward:
1397 if (![[itemURL scheme] isEqual:@"https"]) {
1398 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1401 case WebFrameLoadTypeStandard:
1402 case WebFrameLoadTypeInternal:
1403 // no-op: leave as protocol default
1404 // FIXME: I wonder if we ever hit this case
1406 case WebFrameLoadTypeSame:
1407 case WebFrameLoadTypeReloadAllowingStaleData:
1409 ASSERT_NOT_REACHED();
1412 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1415 [self _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1421 // The general idea here is to traverse the frame tree and the item tree in parallel,
1422 // tracking whether each frame already has the content the item requests. If there is
1423 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1424 // reload that frame, and all its kids.
1425 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1427 NSURL *itemURL = [item URL];
1428 NSURL *currentURL = [[[self dataSource] request] URL];
1430 // Always reload the target frame of the item we're going to. This ensures that we will
1431 // do -some- load for the transition, which means a proper notification will be posted
1433 // The exact URL has to match, including fragment. We want to go through the _load
1434 // method, even if to do a within-page navigation.
1435 // The current frame tree and the frame tree snapshot in the item have to match.
1436 if (![item isTargetItem] &&
1437 [itemURL isEqual:currentURL] &&
1438 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1439 [self _childFramesMatchItem:item])
1441 // This content is good, so leave it alone and look for children that need reloading
1443 // Save form state (works from currentItem, since prevItem is nil)
1444 ASSERT(![_private previousItem]);
1445 [_private->bridge saveDocumentState];
1446 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1448 [_private setCurrentItem:item];
1450 // Restore form state (works from currentItem)
1451 [_private->bridge restoreDocumentState];
1452 // Restore the scroll position (taken in favor of going back to the anchor)
1453 [self _restoreScrollPositionAndViewState];
1455 NSArray *childItems = [item children];
1456 int numChildItems = childItems ? [childItems count] : 0;
1458 for (i = numChildItems - 1; i >= 0; i--) {
1459 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1460 NSString *childName = [childItem target];
1461 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1462 ASSERT(fromChildItem || [fromItem isTargetItem]);
1463 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1465 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1468 // We need to reload the content
1469 [self _loadItem:item withLoadType:type];
1473 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1474 // This includes recursion to handle loading into framesets properly
1475 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1477 ASSERT(![self parentFrame]);
1478 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1479 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1480 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1481 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1482 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
1483 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1484 WebHistoryItem *currItem = [backForwardList currentItem];
1485 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1486 // - plus, it only makes sense for the top level of the operation through the frametree,
1487 // as opposed to happening for some/one of the page commits that might happen soon
1488 [backForwardList goToItem:item];
1489 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1493 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
1495 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
1496 [newDataSource _setTriggeringAction:action];
1498 [newDataSource _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
1500 [self _loadDataSource:newDataSource withLoadType:loadType formState:formState];
1502 [newDataSource release];
1505 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1507 switch ([event type]) {
1508 case NSLeftMouseDown:
1509 case NSRightMouseDown:
1510 case NSOtherMouseDown:
1512 case NSRightMouseUp:
1513 case NSOtherMouseUp:
1515 NSView *topViewInEventWindow = [[event window] contentView];
1516 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1517 while (viewContainingPoint != nil) {
1518 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1521 viewContainingPoint = [viewContainingPoint superview];
1523 if (viewContainingPoint != nil) {
1524 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1525 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1527 return [NSDictionary dictionaryWithObjectsAndKeys:
1528 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1529 elementInfo, WebActionElementKey,
1530 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1531 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1532 URL, WebActionOriginalURLKey,
1540 return [NSDictionary dictionaryWithObjectsAndKeys:
1541 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1542 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1543 URL, WebActionOriginalURLKey,
1548 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1550 WebNavigationType navType;
1551 if (isFormSubmission) {
1552 navType = WebNavigationTypeFormSubmitted;
1553 } else if (event == nil) {
1554 if (loadType == WebFrameLoadTypeReload) {
1555 navType = WebNavigationTypeReload;
1556 } else if (loadType == WebFrameLoadTypeForward
1557 || loadType == WebFrameLoadTypeBack
1558 || loadType == WebFrameLoadTypeIndexedBackForward) {
1559 navType = WebNavigationTypeBackForward;
1561 navType = WebNavigationTypeOther;
1564 navType = WebNavigationTypeLinkClicked;
1566 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1569 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1571 [_private->listener _invalidate];
1572 [_private->listener release];
1573 _private->listener = nil;
1575 NSURLRequest *request = _private->policyRequest;
1576 NSString *frameName = _private->policyFrameName;
1577 id target = _private->policyTarget;
1578 SEL selector = _private->policySelector;
1579 WebFormState *formState = _private->policyFormState;
1581 _private->policyRequest = nil;
1582 _private->policyFrameName = nil;
1583 _private->policyTarget = nil;
1584 _private->policySelector = nil;
1585 _private->policyFormState = nil;
1589 [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1591 [target performSelector:selector withObject:nil withObject:nil];
1596 [frameName release];
1598 [formState release];
1601 - (void)_setPolicyDataSource:(WebDataSource *)dataSource
1603 [dataSource retain];
1604 [_private->policyDataSource release];
1605 _private->policyDataSource = dataSource;
1608 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1610 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1611 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1613 _private->policyRequest = [request retain];
1614 _private->policyTarget = [target retain];
1615 _private->policyFrameName = [frameName retain];
1616 _private->policySelector = selector;
1617 _private->listener = [listener retain];
1618 _private->policyFormState = [formState retain];
1620 WebView *wv = [self webView];
1621 [[wv _policyDelegateForwarder] webView:wv
1622 decidePolicyForNewWindowAction:action
1624 newFrameName:frameName
1625 decisionListener:listener];
1630 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1632 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1633 NSString *frameName = [[_private->policyFrameName retain] autorelease];
1634 id target = [[_private->policyTarget retain] autorelease];
1635 SEL selector = _private->policySelector;
1636 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1638 // will release _private->policy* objects, hence the above retains
1639 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1641 BOOL shouldContinue = NO;
1644 case WebPolicyIgnore:
1646 case WebPolicyDownload:
1647 // FIXME: should download full request
1648 [[self webView] _downloadURL:[request URL]];
1651 shouldContinue = YES;
1654 ASSERT_NOT_REACHED();
1657 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1660 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1661 dataSource:(WebDataSource *)dataSource
1662 formState:(WebFormState *)formState
1664 withSelector:(SEL)selector
1666 NSDictionary *action = [dataSource _triggeringAction];
1667 if (action == nil) {
1668 action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1669 [dataSource _setTriggeringAction:action];
1672 // Don't ask more than once for the same request or if we are loading an empty URL.
1673 // This avoids confusion on the part of the client.
1674 if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1675 [target performSelector:selector withObject:request withObject:nil];
1679 // We are always willing to show alternate content for unreachable URLs;
1680 // treat it like a reload so it maintains the right state for b/f list.
1681 if ([request _webDataRequestUnreachableURL] != nil) {
1682 if (_private->policyLoadType == WebFrameLoadTypeForward
1683 || _private->policyLoadType == WebFrameLoadTypeBack
1684 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1685 _private->policyLoadType = WebFrameLoadTypeReload;
1687 [target performSelector:selector withObject:request withObject:nil];
1691 [dataSource _setLastCheckedRequest:request];
1693 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1695 ASSERT(_private->policyRequest == nil);
1696 _private->policyRequest = [request retain];
1697 ASSERT(_private->policyTarget == nil);
1698 _private->policyTarget = [target retain];
1699 _private->policySelector = selector;
1700 ASSERT(_private->listener == nil);
1701 _private->listener = [listener retain];
1702 ASSERT(_private->policyFormState == nil);
1703 _private->policyFormState = [formState retain];
1705 WebView *wv = [self webView];
1706 _private->delegateIsDecidingNavigationPolicy = YES;
1707 [[wv _policyDelegateForwarder] webView:wv
1708 decidePolicyForNavigationAction:action
1711 decisionListener:listener];
1712 _private->delegateIsDecidingNavigationPolicy = NO;
1717 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1719 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1720 id target = [[_private->policyTarget retain] autorelease];
1721 SEL selector = _private->policySelector;
1722 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1724 // will release _private->policy* objects, hence the above retains
1725 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1727 BOOL shouldContinue = NO;
1730 case WebPolicyIgnore:
1732 case WebPolicyDownload:
1733 // FIXME: should download full request
1734 [[self webView] _downloadURL:[request URL]];
1737 if (![WebView _canHandleRequest:request]) {
1738 [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1740 shouldContinue = YES;
1744 ASSERT_NOT_REACHED();
1747 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1750 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1756 NSURL *URL = [request URL];
1757 WebDataSource *dataSrc = [self dataSource];
1759 BOOL isRedirect = _private->quickRedirectComing;
1760 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1761 _private->quickRedirectComing = NO;
1763 [dataSrc _setURL:URL];
1764 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1765 // NB: must happen after _setURL, since we add based on the current request.
1766 // Must also happen before we openURL and displace the scroll position, since
1767 // adding the BF item will save away scroll state.
1769 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1770 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1771 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1772 // though its load is not yet done. I think this all works out OK, for one because
1773 // we have already saved away the scroll and doc state for the long slow load,
1774 // but it's not an obvious case.
1775 [self _addBackForwardItemClippedAtTarget:NO];
1778 [_private->bridge scrollToAnchorWithURL:URL];
1781 // This will clear previousItem from the rest of the frame tree tree that didn't
1782 // doing any loading. We need to make a pass on this now, since for anchor nav
1783 // we'll not go through a real load and reach Completed state
1784 [self _checkLoadComplete];
1787 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1788 didChangeLocationWithinPageForFrame:self];
1789 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1792 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request alwaysFromRequest: (BOOL)f
1794 [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
1796 // Don't set the cookie policy URL if it's already been set.
1797 if ([request mainDocumentURL] == nil){
1798 if (self == [[self webView] mainFrame] || f) {
1799 [request setMainDocumentURL:[request URL]];
1801 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
1806 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1812 WebView *webView = nil;
1813 WebView *currentWebView = [self webView];
1814 id wd = [currentWebView UIDelegate];
1815 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1816 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1818 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1821 WebFrame *frame = [webView mainFrame];
1822 [[frame _bridge] setName:frameName];
1824 [[webView _UIDelegateForwarder] webViewShow:webView];
1826 [[self _bridge] setOpener:[frame _bridge]];
1827 [frame _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1831 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1832 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1834 BOOL isFormSubmission = (values != nil);
1836 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1837 [request _web_setHTTPReferrer:referrer];
1838 [self _addExtraFieldsToRequest:request alwaysFromRequest: (event != nil || isFormSubmission)];
1839 if (loadType == WebFrameLoadTypeReload) {
1840 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1843 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1844 // policy of LoadFromOrigin, but I didn't test that.
1845 ASSERT(loadType != WebFrameLoadTypeSame);
1847 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1848 WebFormState *formState = nil;
1849 if (form && values) {
1850 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1853 if (target != nil) {
1854 WebFrame *targetFrame = [self findFrameNamed:target];
1855 if (targetFrame != nil) {
1856 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1858 [self _checkNewWindowPolicyForRequest:request
1863 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1866 [formState release];
1870 WebDataSource *oldDataSource = [[self dataSource] retain];
1872 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1874 // Make sure to do scroll to anchor processing even if the URL is
1875 // exactly the same so pages with '#' links and DHTML side effects
1877 if (!isFormSubmission
1878 && loadType != WebFrameLoadTypeReload
1879 && loadType != WebFrameLoadTypeSame
1880 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1882 // We don't want to just scroll if a link from within a
1883 // frameset is trying to reload the frameset into _top.
1884 && ![_private->bridge isFrameSet]) {
1886 // Just do anchor navigation within the existing content.
1888 // We don't do this if we are submitting a form, explicitly reloading,
1889 // currently displaying a frameset, or if the new URL does not have a fragment.
1890 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1893 // FIXME: What about load types other than Standard and Reload?
1895 [oldDataSource _setTriggeringAction:action];
1896 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1897 [self _checkNavigationPolicyForRequest:request
1898 dataSource:oldDataSource
1901 withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1903 // must grab this now, since this load may stop the previous load and clear this flag
1904 BOOL isRedirect = _private->quickRedirectComing;
1905 [self _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1907 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1908 _private->quickRedirectComing = NO;
1909 [[self provisionalDataSource] _setIsClientRedirect:YES];
1910 } else if (sameURL) {
1911 // Example of this case are sites that reload the same URL with a different cookie
1912 // driving the generated content, or a master frame with links that drive a target
1913 // frame, where the user has clicked on the same link repeatedly.
1914 [self _setLoadType:WebFrameLoadTypeSame];
1919 [oldDataSource release];
1920 [formState release];
1923 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1925 WebHistoryItem *parentItem = [_private currentItem];
1926 NSArray *childItems = [parentItem children];
1927 WebFrameLoadType loadType = [self _loadType];
1928 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1929 WebHistoryItem *childItem = nil;
1931 // If we're moving in the backforward list, we might want to replace the content
1932 // of this child frame with whatever was there at that point.
1933 // Reload will maintain the frame contents, LoadSame will not.
1935 (loadType == WebFrameLoadTypeForward
1936 || loadType == WebFrameLoadTypeBack
1937 || loadType == WebFrameLoadTypeIndexedBackForward
1938 || loadType == WebFrameLoadTypeReload
1939 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1941 childItem = [parentItem childItemWithName:[childFrame name]];
1943 // Use the original URL to ensure we get all the side-effects, such as
1944 // onLoad handlers, of any redirects that happened. An example of where
1945 // this is needed is Radar 3213556.
1946 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1947 // These behaviors implied by these loadTypes should apply to the child frames
1948 childLoadType = loadType;
1950 if (loadType == WebFrameLoadTypeForward
1951 || loadType == WebFrameLoadTypeBack
1952 || loadType == WebFrameLoadTypeIndexedBackForward)
1954 // For back/forward, remember this item so we can traverse any child items as child frames load
1955 [childFrame->_private setProvisionalItem:childItem];
1957 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1958 [childFrame->_private setCurrentItem:childItem];
1963 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1965 [childFrame loadArchive:archive];
1967 [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1971 - (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
1973 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1974 // This prevents a potential bug which may cause a page with a form that uses itself
1975 // as an action to be returned from the cache without submitting.
1977 // FIXME: Where's the code that implements what the comment above says?
1979 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1980 [self _addExtraFieldsToRequest:request alwaysFromRequest:YES];
1981 [request _web_setHTTPReferrer:referrer];
1982 [request setHTTPMethod:@"POST"];
1983 webSetHTTPBody(request, postData);
1984 [request _web_setHTTPContentType:contentType];
1986 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1987 WebFormState *formState = nil;
1988 if (form && values) {
1989 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1992 if (target != nil) {
1993 WebFrame *targetFrame = [self findFrameNamed:target];
1995 if (targetFrame != nil) {
1996 [targetFrame _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1998 [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2001 [formState release];
2005 [self _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
2008 [formState release];
2011 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
2013 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
2015 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
2016 willPerformClientRedirectToURL:URL
2020 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2021 // load as part of the same navigation.
2023 if (![self dataSource] || isJavaScriptFormAction) {
2024 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
2025 // so we better just treat the redirect as a normal load.
2026 _private->quickRedirectComing = NO;
2027 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2029 _private->quickRedirectComing = lockHistory;
2030 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2034 - (void)_clientRedirectCancelled:(BOOL)cancelWithLoadInProgress
2036 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
2037 didCancelClientRedirectForFrame:self];
2038 if (!cancelWithLoadInProgress)
2039 _private->quickRedirectComing = NO;
2040 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
2043 - (void)_setTitle:(NSString *)title
2045 [[_private currentItem] setTitle:title];
2048 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
2051 NSView <WebDocumentView> *docView = [[self frameView] documentView];
2052 NSView *parent = [docView superview];
2053 // we might already be detached when this is called from detachFromParent, in which
2054 // case we don't want to override real data earlier gathered with (0,0)
2057 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
2058 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
2059 // ScrollView instead of using the one provided by the WebFrame
2060 point = [(id <_WebDocumentViewState>)docView scrollPoint];
2061 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
2063 // Parent is the clipview of the DynamicScrollView the WebFrame installs
2064 ASSERT([parent isKindOfClass:[NSClipView class]]);
2065 point = [parent bounds].origin;
2067 [item setScrollPoint:point];
2073 There is a race condition between the layout and load completion that affects restoring the scroll position.
2074 We try to restore the scroll position at both the first layout and upon load completion.
2076 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
2077 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
2078 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
2079 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
2080 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
2081 fails. We then successfully restore it when the layout happens.
2084 - (void)_restoreScrollPositionAndViewState
2086 ASSERT([_private currentItem]);
2087 NSView <WebDocumentView> *docView = [[self frameView] documentView];
2088 NSPoint point = [[_private currentItem] scrollPoint];
2089 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
2090 id state = [[_private currentItem] viewState];
2092 [(id <_WebDocumentViewState>)docView setViewState:state];
2095 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
2097 [docView scrollPoint:point];
2101 - (void)_defersCallbacksChanged
2103 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2104 [[frame provisionalDataSource] _defersCallbacksChanged];
2105 [[frame dataSource] _defersCallbacksChanged];
2109 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
2111 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2112 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
2115 - (void)_viewDidMoveToHostWindow
2117 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2118 [[[frame frameView] documentView] viewDidMoveToHostWindow];
2121 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
2123 WebDataSource *dataSource = [self dataSource];
2124 if (dataSource == nil) {
2128 NSMutableURLRequest *request = [[dataSource request] mutableCopy];
2129 NSURL *unreachableURL = [dataSource unreachableURL];
2130 if (unreachableURL != nil) {
2131 [request setURL:unreachableURL];
2133 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
2134 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:request];
2137 [newDataSource _setOverrideEncoding:encoding];
2139 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
2141 [newDataSource release];
2144 - (void)_addChild:(WebFrame *)child
2146 [[self _bridge] appendChild:[child _bridge]];
2147 [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
2150 - (void)_resetBackForwardList
2152 // Note this doesn't verify the current load type as a b/f operation because it is called from
2153 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
2154 ASSERT(self == [[self webView] mainFrame]);
2155 WebHistoryItem *resetItem = [_private currentItem];
2157 [[[self webView] backForwardList] goToItem:resetItem];
2160 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
2161 // item, because we optimistically move it right away at the start of the operation. But when
2162 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
2163 // Return the item that we would reset to, so we can decide later whether to actually reset.
2164 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
2166 WebFrameLoadType loadType = [self _loadType];
2167 if ((loadType == WebFrameLoadTypeForward
2168 || loadType == WebFrameLoadTypeBack
2169 || loadType == WebFrameLoadTypeIndexedBackForward)
2170 && self == [[self webView] mainFrame]) {
2171 return [_private currentItem];
2176 - (WebHistoryItem *)_itemForSavingDocState
2178 // For a standard page load, we will have a previous item set, which will be used to
2179 // store the form state. However, in some cases we will have no previous item, and
2180 // the current item is the right place to save the state. One example is when we
2181 // detach a bunch of frames because we are navigating from a site with frames to
2182 // another site. Another is when saving the frame state of a frame that is not the
2183 // target of the current navigation (if we even decide to save with that granularity).
2185 // Because of previousItem's "masking" of currentItem for this purpose, it's important
2186 // that previousItem be cleared at the end of a page transition. We leverage the
2187 // checkLoadComplete recursion to achieve this goal.
2189 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
2193 - (WebHistoryItem *)_itemForRestoringDocState
2195 switch ([self _loadType]) {
2196 case WebFrameLoadTypeReload:
2197 case WebFrameLoadTypeReloadAllowingStaleData:
2198 case WebFrameLoadTypeSame:
2199 case WebFrameLoadTypeReplace:
2200 // Don't restore any form state on reload or loadSame
2202 case WebFrameLoadTypeBack:
2203 case WebFrameLoadTypeForward:
2204 case WebFrameLoadTypeIndexedBackForward:
2205 case WebFrameLoadTypeInternal:
2206 case WebFrameLoadTypeStandard:
2207 return [_private currentItem];
2209 ASSERT_NOT_REACHED();
2213 // Walk the frame tree, telling all frames to save their form state into their current
2215 - (void)_saveDocumentAndScrollState
2217 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2218 [[frame _bridge] saveDocumentState];
2219 [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
2223 // Called after the FormsDelegate is done processing willSubmitForm:
2224 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
2226 if (_private->listener) {
2227 [_private->listener _invalidate];
2228 [_private->listener release];
2229 _private->listener = nil;
2231 [_private->provisionalDataSource _startLoading];
2234 -(void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
2236 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
2237 // nil _private->policyDataSource because loading the alternate page will have passed
2238 // through this method already, nested; otherwise, _private->policyDataSource should still be set.
2239 ASSERT(_private->policyDataSource || [[self provisionalDataSource] unreachableURL] != nil);
2241 WebHistoryItem *item = [_private provisionalItem];
2243 // Two reasons we can't continue:
2244 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2245 // is the user responding Cancel to the form repost nag sheet.
2246 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2247 // The "before unload" event handler runs only for the main frame.
2248 BOOL canContinue = request && ([[self webView] mainFrame] != self || [_private->bridge shouldClose]);
2251 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2252 // need to report that the client redirect was cancelled.
2253 if (_private->quickRedirectComing)
2254 [self _clientRedirectCancelled:NO];
2256 [self _setPolicyDataSource:nil];
2257 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2258 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2259 // we only do this when punting a navigation for the target frame or top-level frame.
2260 if (([item isTargetItem] || [[self webView] mainFrame] == self)
2261 && (_private->policyLoadType == WebFrameLoadTypeForward
2262 || _private->policyLoadType == WebFrameLoadTypeBack
2263 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward))
2264 [[[self webView] mainFrame] _resetBackForwardList];
2268 WebFrameLoadType loadType = _private->policyLoadType;
2269 WebDataSource *dataSource = [_private->policyDataSource retain];
2272 [self _setLoadType:loadType];
2273 [self _setProvisionalDataSource:dataSource];
2274 [dataSource release];
2276 [self _setPolicyDataSource:nil];
2278 // We tell the documentView provisionalDataSourceChanged:
2279 // once it has been created by the WebView.
2281 [self _setState: WebFrameStateProvisional];
2283 if (self == [[self webView] mainFrame])
2284 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2286 if ((loadType == WebFrameLoadTypeForward ||
2287 loadType == WebFrameLoadTypeBack ||
2288 loadType == WebFrameLoadTypeIndexedBackForward) &&
2289 [item hasPageCache]){
2290 NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2291 if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2292 LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2293 [_private->provisionalDataSource _loadFromPageCache:pageCache];
2299 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2300 // mechanism across the willSubmitForm callout.
2301 _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2302 [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2305 [self _continueAfterWillSubmitForm:WebPolicyUse];
2309 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2311 ASSERT([self webView] != nil);
2313 // Unfortunately the view must be non-nil, this is ultimately due
2314 // to KDE parser requiring a KHTMLView. Once we settle on a final
2315 // KDE drop we should fix this dependency.
2317 ASSERT([self frameView] != nil);
2319 _private->policyLoadType = loadType;
2321 WebFrame *parentFrame = [self parentFrame];
2323 [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2324 [newDataSource _setWebFrame:self];
2326 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2328 [self _setPolicyDataSource:newDataSource];
2330 [self _checkNavigationPolicyForRequest:[newDataSource request]
2331 dataSource:newDataSource
2334 withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2337 - (void)_setProvisionalDataSource: (WebDataSource *)d
2339 if (_private->provisionalDataSource != _private->dataSource) {
2340 [_private->provisionalDataSource _setWebFrame:nil];
2342 [_private setProvisionalDataSource: d];
2343 [d _setWebFrame:self];
2346 // used to decide to use loadType=Same
2347 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2349 WebHistoryItem *item = [_private currentItem];
2350 NSString* URLString = [URL _web_originalDataAsString];
2351 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2354 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2356 if (frameName == nil) {
2357 [self loadRequest:request];
2361 WebFrame *frame = [self findFrameNamed:frameName];
2364 [frame loadRequest:request];
2368 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2369 [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2372 // Return next frame to be traversed, visiting children after parent
2373 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2375 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
2378 // Return previous frame to be traversed, exact reverse order of _nextFrame
2379 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2381 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
2384 - (void)_setShouldCreateRenderers:(BOOL)f
2386 [_private->bridge setShouldCreateRenderers:f];
2389 - (BOOL)_shouldCreateRenderers
2391 return [_private->bridge shouldCreateRenderers];
2394 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2397 return [[self _bridge] numPendingOrLoadingRequests];
2400 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2401 num += [[frame _bridge] numPendingOrLoadingRequests];
2406 - (NSColor *)_bodyBackgroundColor
2408 return [_private->bridge bodyBackgroundColor];
2411 - (void)_reloadForPluginChanges
2413 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2414 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2415 if ([documentView isKindOfClass:[WebNetscapePluginDocumentView class]] ||
2416 [documentView isKindOfClass:[WebPluginDocumentView class]]) {
2418 } else if ([documentView isKindOfClass:[WebHTMLView class]]) {
2419 NSEnumerator *viewEnumerator = [[documentView subviews] objectEnumerator];
2421 // FIXME: We should ask the frame if it contains plugins, rather
2422 // than doing this check.
2423 while ((view = [viewEnumerator nextObject]) != nil) {
2424 if ([view isKindOfClass:[WebNetscapePluginEmbeddedView class]] ||
2425 [view isKindOfClass:[WebNullPluginView class]] ||
2426 [WebPluginController isPlugInView:view]) {
2435 - (void)_attachScriptDebugger
2437 if (!_private->scriptDebugger) {
2438 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
2442 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
2444 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2445 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2446 // FIXME: what about plugin document view?
2447 if ([documentView isKindOfClass:[WebHTMLView class]])
2448 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
2452 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
2454 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2455 // FIXME: what about plugin document view?
2456 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2457 if ([documentView isKindOfClass:[WebHTMLView class]])
2458 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
2462 - (BOOL)_firstLayoutDone
2464 return _private->firstLayoutDone;
2469 @implementation WebFrame (WebInternal)
2471 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
2473 self = [super init];
2477 _private = [[WebFramePrivate alloc] init];
2479 _private->bridge = bridge;
2482 [_private setWebFrameView:fv];
2483 [fv _setWebFrame:self];
2491 - (NSArray *)_documentViews
2493 NSMutableArray *result = [NSMutableArray array];
2494 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2495 id docView = [[frame frameView] documentView];
2497 [result addObject:docView];
2503 - (void)_updateDrawsBackground
2505 BOOL drawsBackground = [[self webView] drawsBackground];
2507 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2508 // FIXME: why not the other way for scroll view?
2509 if (!drawsBackground)
2510 [[[frame frameView] _scrollView] setDrawsBackground:NO];
2511 id documentView = [[frame frameView] documentView];
2512 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
2513 [documentView setDrawsBackground:drawsBackground];
2514 [[frame _bridge] setDrawsBackground:drawsBackground];
2518 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2520 _private->internalLoadDelegate = internalLoadDelegate;
2523 - (id)_internalLoadDelegate
2525 return _private->internalLoadDelegate;
2528 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
2530 ASSERT(request != nil);
2532 WebView *wv = [self webView];
2533 id delegate = [wv resourceLoadDelegate];
2534 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2535 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2536 WebDataSource *dataSource = [self dataSource];
2538 if (implementations.delegateImplementsIdentifierForRequest) {
2539 *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2541 *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2544 NSURLRequest *newRequest;
2545 if (implementations.delegateImplementsWillSendRequest) {
2546 newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2548 newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2551 if (newRequest == nil) {
2552 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
2560 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
2562 WebView *wv = [self webView];
2563 id delegate = [wv resourceLoadDelegate];
2564 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2565 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2566 WebDataSource *dataSource = [self dataSource];
2568 if (response != nil) {
2569 if (implementations.delegateImplementsDidReceiveResponse) {
2570 [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2572 [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2577 if (implementations.delegateImplementsDidReceiveContentLength) {
2578 [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInt)length fromDataSource:dataSource];
2580 [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInt)length fromDataSource:dataSource];
2585 if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
2586 [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2588 [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2590 [wv _finishedLoadingResourceFromDataSource:dataSource];
2592 [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
2596 - (void)_safeLoadURL:(NSURL *)URL
2598 // Call the bridge because this is where our security checks are made.
2599 [[self _bridge] loadURL:URL
2600 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2604 triggeringEvent:[NSApp currentEvent]
2609 - (void)_saveResourceAndSendRemainingDelegateMessagesWithRequest:(NSURLRequest *)request
2610 identifier:(id)identifier
2611 response:(NSURLResponse *)response
2613 error:(NSError *)error
2615 unsigned length = [data length];
2616 if (length > 0 && error == nil) {
2617 ASSERT(request != nil);
2618 WebResource *resource = [[WebResource alloc] _initWithData:data URL:[request URL] response:response];
2619 ASSERT(resource != nil);
2620 [[self dataSource] addSubresource:resource];
2623 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:length error:error];
2626 - (void)_unmarkAllMisspellings
2628 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2629 [[frame _bridge] unmarkAllMisspellings];
2632 - (void)_didFirstLayout
2634 if ([[self webView] backForwardList]) {
2635 WebFrameLoadType loadType = [self _loadType];
2636 if (loadType == WebFrameLoadTypeForward ||
2637 loadType == WebFrameLoadTypeBack ||
2638 loadType == WebFrameLoadTypeIndexedBackForward)
2640 [self _restoreScrollPositionAndViewState];
2644 _private->firstLayoutDone = YES;
2647 - (void)_setupForReplace
2649 [self _setState:WebFrameStateProvisional];
2650 WebDataSource *old = _private->provisionalDataSource;
2651 _private->provisionalDataSource = _private->dataSource;
2652 _private->dataSource = nil;
2655 [self _detachChildren];
2658 - (BOOL)_hasSelection
2660 id documentView = [[self frameView] documentView];
2662 // optimization for common case to avoid creating potentially large selection string
2663 if ([documentView isKindOfClass:[WebHTMLView class]]) {
2664 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
2665 return selectedDOMRange && ![selectedDOMRange collapsed];
2668 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2669 return [[documentView selectedString] length] > 0;
2674 - (void)_clearSelection
2676 id documentView = [[self frameView] documentView];
2677 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2678 [documentView deselectAll];
2683 - (BOOL)_atMostOneFrameHasSelection;
2685 // FIXME: 4186050 is one known case that makes this debug check fail
2687 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2688 if ([frame _hasSelection]) {
2699 - (WebFrame *)_findFrameWithSelection
2701 ASSERT([self _atMostOneFrameHasSelection]);
2703 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2704 if ([frame _hasSelection])
2710 - (void)_clearSelectionInOtherFrames
2712 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
2713 // responder. It would be nicer to just notice first responder changes here instead, but there's no
2714 // notification sent when the first responder changes in general (Radar 2573089).
2715 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
2716 if (frameWithSelection != self)
2717 [frameWithSelection _clearSelection];
2719 // While we're in the general area of selection and frames, check that there is only one now.
2720 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
2723 - (void)_stopLoadingSubframes
2725 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2726 [child stopLoading];
2729 - (BOOL)_subframeIsLoading
2731 // Put in the auto-release pool because it's common to call this from a run loop source,
2732 // and then the entire list of frames lasts until the next autorelease.
2733 // FIXME: is this really still true? we use _firstChildFrame/_nextSiblingFrame now
2734 // which does not make a copy.
2735 NSAutoreleasePool *pool = [NSAutoreleasePool new];
2738 for (frame = [self _firstChildFrame]; frame; frame = [frame _nextSiblingFrame])
2739 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
2744 return frame != nil;
2749 @implementation WebFormState : NSObject
2751 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2753 self = [super init];
2757 _form = [form retain];
2758 _values = [values copy];
2759 _sourceFrame = [sourceFrame retain];
2767 [_sourceFrame release];
2771 - (DOMElement *)form
2776 - (NSDictionary *)values
2781 - (WebFrame *)sourceFrame
2783 return _sourceFrame;
2788 @implementation WebFrame
2792 return [self initWithName:nil webFrameView:nil webView:nil];
2795 // FIXME: this method can't work any more and should be marked deprecated
2796 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2798 return [self _initWithWebFrameView:fv webView:v bridge:nil];
2803 [self _detachFromParent];
2813 // FIXME: Should not do this work at finalize time. Need to do it at a predictable time instead.
2814 [self _detachFromParent];
2822 return [[self _bridge] name];
2825 - (WebFrameView *)frameView
2827 return [_private webFrameView];
2830 - (WebView *)webView
2832 return [[[self _bridge] page] webView];
2835 - (DOMDocument *)DOMDocument
2837 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2840 - (DOMHTMLElement *)frameElement
2842 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2845 - (WebDataSource *)provisionalDataSource
2847 return [_private provisionalDataSource];
2850 - (WebDataSource *)dataSource
2852 return [_private dataSource];
2855 - (void)loadRequest:(NSURLRequest *)request
2857 [self _loadRequest:request subresources:nil subframeArchives:nil];
2860 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2862 NSURLRequest *request = [self _webDataRequestForData:data
2864 textEncodingName:encodingName
2866 unreachableURL:unreachableURL];
2867 [self loadRequest:request];
2871 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2873 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2876 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2878 CFStringEncoding cfencoding = CFStringGetFastestEncoding((CFStringRef)string);
2879 NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
2880 CFStringRef cfencodingName = CFStringConvertEncodingToIANACharSetName(cfencoding);
2882 if (!cfencodingName || nsencoding == kCFStringEncodingInvalidId){
2883 NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
2884 [self _loadData:data MIMEType:nil textEncodingName:@"utf-16" baseURL:URL unreachableURL:unreachableURL];
2887 NSData *data = [string dataUsingEncoding: nsencoding];
2888 [self _loadData:data MIMEType:nil textEncodingName:(NSString *)cfencodingName baseURL:URL unreachableURL:unreachableURL];
2892 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2894 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2897 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2899 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2902 - (void)loadArchive:(WebArchive *)archive
2904 WebResource *mainResource = [archive mainResource];
2906 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2907 MIMEType:[mainResource MIMEType]
2908 textEncodingName:[mainResource textEncodingName]
2909 baseURL:[mainResource URL]
2910 unreachableURL:nil];
2911 [self _loadRequest:request subresources:[archive subresources] subframeArchives:[archive subframeArchives]];
2917 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2918 if (_private->isStoppingLoad)
2921 _private->isStoppingLoad = YES;
2923 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2925 [self _stopLoadingSubframes];
2926 [_private->provisionalDataSource _stopLoading];
2927 [_private->dataSource _stopLoading];
2929 [self _setProvisionalDataSource:nil];
2931 _private->isStoppingLoad = NO;
2936 WebDataSource *dataSource = [self dataSource];
2937 if (dataSource == nil)
2940 NSMutableURLRequest *initialRequest = [dataSource request];
2942 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2943 // Reloading in this case will lose the current contents (see 4151001).
2944 if ([[[[dataSource request] URL] absoluteString] length] == 0) {
2948 // Replace error-page URL with the URL we were trying to reach.
2949 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
2950 if (unreachableURL != nil) {
2951 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
2954 // initWithRequest copies the request
2955 WebDataSource *newDataSource = [[WebDataSource alloc] initWithRequest:initialRequest];
2956 NSMutableURLRequest *request = [newDataSource request];
2958 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
2960 // If we're about to rePOST, set up action so the app can warn the user
2961 if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
2962 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
2963 [newDataSource _setTriggeringAction:action];
2966 [newDataSource _setOverrideEncoding:[dataSource _overrideEncoding]];
2968 [self _loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
2970 [newDataSource release];
2973 - (WebFrame *)findFrameNamed:(NSString *)name
2975 return Frame([[self _bridge] findFrameNamed:name]);
2978 - (WebFrame *)parentFrame
2980 return [[Frame([[self _bridge] parent]) retain] autorelease];
2983 - (NSArray *)childFrames
2985 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2986 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2987 [children addObject:child];