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/WebDataSourceInternal.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/WebFrameLoader.h>
43 #import <WebKit/WebFrameViewInternal.h>
44 #import <WebKit/WebHistoryPrivate.h>
45 #import <WebKit/WebHistoryItemPrivate.h>
46 #import <WebKit/WebHTMLRepresentationPrivate.h>
47 #import <WebKit/WebHTMLViewInternal.h>
48 #import <WebKit/WebHTMLViewPrivate.h>
49 #import <WebKit/WebKitErrorsPrivate.h>
50 #import <WebKit/WebKitLogging.h>
51 #import <WebKit/WebKitNSStringExtras.h>
52 #import <WebKit/WebKitStatisticsPrivate.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/WebResourceLoadDelegate.h>
62 #import <WebKit/WebResourcePrivate.h>
63 #import <WebKit/WebViewInternal.h>
64 #import <WebKit/WebUIDelegate.h>
65 #import <WebKit/WebScriptDebugDelegatePrivate.h>
66 #import <WebKitSystemInterface.h>
68 #import <objc/objc-runtime.h>
71 Here is the current behavior matrix for four types of navigations:
75 Restore form state: YES
76 Restore scroll and focus state: YES
77 WF Cache policy: NSURLRequestUseProtocolCachePolicy
78 Add to back/forward list: YES
82 Restore form state: YES
83 Restore scroll and focus state: YES
84 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
85 Add to back/forward list: NO
87 Reload (meaning only the reload button):
89 Restore form state: NO
90 Restore scroll and focus state: YES
91 WF Cache policy: NSURLRequestReloadIgnoringCacheData
92 Add to back/forward list: NO
94 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
96 Restore form state: NO
97 Restore scroll and focus state: NO, reset to initial conditions
98 WF Cache policy: NSURLRequestReloadIgnoringCacheData
99 Add to back/forward list: NO
102 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
103 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
104 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
106 @interface NSObject (WebExtraPerformMethod)
108 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3;
112 @implementation NSObject (WebExtraPerformMethod)
114 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3
116 return objc_msgSend(self, aSelector, object1, object2, object3);
121 // One day we might want to expand the use of this kind of class such that we'd receive one
122 // over the bridge, and possibly hand it on through to the FormsDelegate.
123 // Today it is just used internally to keep some state as we make our way through a bunch
124 // layers while doing a load.
125 @interface WebFormState : NSObject
128 NSDictionary *_values;
129 WebFrame *_sourceFrame;
131 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame;
132 - (DOMElement *)form;
133 - (NSDictionary *)values;
134 - (WebFrame *)sourceFrame;
137 @interface WebFrame (ForwardDecls)
138 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
139 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
141 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
142 - (void)_restoreScrollPositionAndViewState;
144 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
145 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
146 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
147 - (void)_stopLoadingSubframes;
150 @interface WebFrame (FrameTraversal)
151 - (WebFrame *)_firstChildFrame;
152 - (WebFrame *)_lastChildFrame;
153 - (unsigned)_childFrameCount;
154 - (WebFrame *)_previousSiblingFrame;
155 - (WebFrame *)_nextSiblingFrame;
156 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
159 @interface NSView (WebFramePluginHosting)
160 - (void)setWebFrame:(WebFrame *)webFrame;
163 @interface WebFramePrivate : NSObject
166 WebFrameView *webFrameView;
167 WebFrameLoader *frameLoader;
169 WebFrameBridge *bridge;
170 WebFrameLoadType loadType;
171 WebHistoryItem *currentItem; // BF item for our current content
172 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
173 // (only known when navigating to a pre-existing BF item)
174 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
176 WebPolicyDecisionListener *listener;
177 // state we'll need to continue after waiting for the policy delegate's decision
178 NSURLRequest *policyRequest;
179 NSString *policyFrameName;
182 WebFormState *policyFormState;
183 WebDataSource *policyDataSource;
184 WebFrameLoadType policyLoadType;
186 BOOL quickRedirectComing;
187 BOOL sentRedirectNotification;
189 BOOL delegateIsHandlingProvisionalLoadError;
190 BOOL delegateIsDecidingNavigationPolicy;
191 BOOL delegateIsHandlingUnimplementablePolicy;
192 BOOL firstLayoutDone;
194 id internalLoadDelegate;
195 WebScriptDebugger *scriptDebugger;
197 NSString *frameNamespace;
199 NSMutableSet *plugInViews;
200 NSMutableSet *inspectors;
203 - (void)setWebFrameView:(WebFrameView *)v;
204 - (WebFrameView *)webFrameView;
205 - (WebFrameLoadType)loadType;
206 - (void)setLoadType:(WebFrameLoadType)loadType;
208 - (void)setProvisionalItem:(WebHistoryItem *)item;
209 - (WebHistoryItem *)provisionalItem;
210 - (void)setPreviousItem:(WebHistoryItem *)item;
211 - (WebHistoryItem *)previousItem;
212 - (void)setCurrentItem:(WebHistoryItem *)item;
213 - (WebHistoryItem *)currentItem;
217 @implementation WebFramePrivate
226 loadType = WebFrameLoadTypeStandard;
233 [webFrameView release];
234 [frameLoader release];
236 [currentItem release];
237 [provisionalItem release];
238 [previousItem release];
240 [scriptDebugger release];
242 [inspectors release];
244 ASSERT(listener == nil);
245 ASSERT(policyRequest == nil);
246 ASSERT(policyFrameName == nil);
247 ASSERT(policyTarget == nil);
248 ASSERT(policyFormState == nil);
249 ASSERT(policyDataSource == nil);
250 ASSERT(frameNamespace == nil);
251 ASSERT(plugInViews == nil);
256 - (WebFrameView *)webFrameView { return webFrameView; }
257 - (void)setWebFrameView: (WebFrameView *)v
260 [webFrameView release];
264 - (WebFrameLoadType)loadType { return loadType; }
265 - (void)setLoadType: (WebFrameLoadType)t
270 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
271 - (void)setProvisionalItem: (WebHistoryItem *)item
274 [provisionalItem release];
275 provisionalItem = item;
278 - (WebHistoryItem *)previousItem { return previousItem; }
279 - (void)setPreviousItem:(WebHistoryItem *)item
282 [previousItem release];
286 - (WebHistoryItem *)currentItem { return currentItem; }
287 - (void)setCurrentItem:(WebHistoryItem *)item
290 [currentItem release];
296 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
298 return [(WebFrameBridge *)bridge webFrame];
301 @implementation WebFrame (FrameTraversal)
302 - (WebFrame *)_firstChildFrame
304 return Frame([[self _bridge] firstChild]);
307 - (WebFrame *)_lastChildFrame
309 return Frame([[self _bridge] lastChild]);
312 - (unsigned)_childFrameCount
314 return [[self _bridge] childCount];
317 - (WebFrame *)_previousSiblingFrame;
319 return Frame([[self _bridge] previousSibling]);
322 - (WebFrame *)_nextSiblingFrame;
324 return Frame([[self _bridge] nextSibling]);
327 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
329 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
334 @implementation WebFrame (WebPrivate)
336 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
338 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
339 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
340 [request _webDataRequestSetData:data];
341 [request _webDataRequestSetEncoding:encodingName];
342 [request _webDataRequestSetBaseURL:URL];
343 [request _webDataRequestSetUnreachableURL:unreachableURL];
344 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
348 // helper method used in various nav cases below
349 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
351 if ([[self dataSource] _URLForHistory] != nil) {
352 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
353 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
354 [[[self webView] backForwardList] addItem:bfItem];
358 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
360 WebDataSource *dataSrc = [self dataSource];
361 NSURLRequest *request;
362 NSURL *unreachableURL = [dataSrc unreachableURL];
365 WebHistoryItem *bfItem;
368 request = [dataSrc _originalRequest];
370 request = [dataSrc request];
373 if (unreachableURL != nil) {
374 URL = unreachableURL;
375 originalURL = unreachableURL;
378 originalURL = [[dataSrc _originalRequest] URL];
381 LOG (History, "creating item for %@", request);
383 // Frames that have never successfully loaded any content
384 // may have no URL at all. Currently our history code can't
385 // deal with such things, so we nip that in the bud here.
386 // Later we may want to learn to live with nil for URL.
387 // See bug 3368236 and related bugs for more information.
389 URL = [NSURL URLWithString:@"about:blank"];
391 if (originalURL == nil) {
392 originalURL = [NSURL URLWithString:@"about:blank"];
395 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
396 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
398 // save form state if this is a POST
399 [bfItem _setFormInfoFromRequest:request];
401 // Set the item for which we will save document state
402 [_private setPreviousItem:[_private currentItem]];
403 [_private setCurrentItem:bfItem];
409 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
410 The item that was the target of the user's navigation is designated as the "targetItem".
411 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
412 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
414 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
416 WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
418 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
419 if (!(doClip && self == targetFrame)) {
420 // save frame state for items that aren't loading (khtml doesn't save those)
421 [_private->bridge saveDocumentState];
423 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
424 [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
426 if (self == targetFrame)
427 [bfItem setIsTargetItem:YES];
432 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
434 return Frame([[self _bridge] childFrameNamed:name]);
437 // FIXME: this exists only as a convenience for Safari, consider moving there
438 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
440 return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
445 return [_private->bridge isFrameSet];
448 - (void)_detachChildren
450 // FIXME: is it really necessary to do this in reverse order any more?
451 WebFrame *child = [self _lastChildFrame];
452 WebFrame *prev = [child _previousSiblingFrame];
453 for (; child; child = prev, prev = [child _previousSiblingFrame])
454 [child _detachFromParent];
457 - (void)_closeOldDataSources
459 // FIXME: is it important for this traversal to be postorder instead of preorder?
460 // FIXME: add helpers for postorder traversal?
461 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
462 [child _closeOldDataSources];
464 if ([_private->frameLoader dataSource])
465 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] willCloseFrame:self];
466 [[self webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
469 - (void)_detachFromParent
471 WebFrameBridge *bridge = [_private->bridge retain];
476 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
477 [self _detachChildren];
478 [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
480 [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
482 [_private->frameLoader clearDataSource];
483 [_private setWebFrameView:nil];
485 [self retain]; // retain self temporarily because dealloc can re-enter this method
487 [[[self parentFrame] _bridge] removeChild:bridge];
493 _private->bridge = nil;
498 - (void)_setLoadType: (WebFrameLoadType)t
500 [_private setLoadType:t];
503 - (WebFrameLoadType)_loadType
505 return [_private loadType];
508 - (void)_makeDocumentView
510 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[_private->frameLoader dataSource]];
514 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
515 WebFrameView *v = _private->webFrameView;
516 [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
517 [self _updateBackground];
518 [_private->bridge installInFrame:[v _scrollView]];
520 // Call setDataSource on the document view after it has been placed in the view hierarchy.
521 // This what we for the top-level view, so should do this for views in subframes as well.
522 [documentView setDataSource:[_private->frameLoader dataSource]];
525 - (void)_receivedMainResourceError:(NSError *)error
527 if ([_private->frameLoader state] == WebFrameStateProvisional) {
528 NSURL *failedURL = [[[_private->frameLoader provisionalDataSource] _originalRequest] URL];
529 // When we are pre-commit, the currentItem is where the pageCache data resides
530 NSDictionary *pageCache = [[_private currentItem] pageCache];
531 [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
532 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
533 [[_private currentItem] setHasPageCache:NO];
535 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
536 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
537 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
538 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
540 if (_private->sentRedirectNotification)
541 [self _clientRedirectCancelledOrFinished:NO];
545 - (void)_transitionToCommitted:(NSDictionary *)pageCache
547 ASSERT([self webView] != nil);
549 switch ([_private->frameLoader state]) {
550 case WebFrameStateProvisional:
552 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
554 WebFrameLoadType loadType = [self _loadType];
555 if (loadType == WebFrameLoadTypeForward ||
556 loadType == WebFrameLoadTypeBack ||
557 loadType == WebFrameLoadTypeIndexedBackForward ||
558 (loadType == WebFrameLoadTypeReload && [[_private->frameLoader provisionalDataSource] unreachableURL] != nil))
560 // Once committed, we want to use current item for saving DocState, and
561 // the provisional item for restoring state.
562 // Note previousItem must be set before we close the URL, which will
563 // happen when the data source is made non-provisional below
564 [_private setPreviousItem:[_private currentItem]];
565 ASSERT([_private provisionalItem]);
566 [_private setCurrentItem:[_private provisionalItem]];
567 [_private setProvisionalItem:nil];
570 // The call to closeURL invokes the unload event handler, which can execute arbitrary
571 // JavaScript. If the script initiates a new load, we need to abandon the current load,
572 // or the two will stomp each other.
573 WebDataSource *pd = [_private->frameLoader provisionalDataSource];
574 [[self _bridge] closeURL];
575 if (pd != [_private->frameLoader provisionalDataSource])
578 [_private->frameLoader commitProvisionalLoad];
580 // Handle adding the URL to the back/forward list.
581 WebDataSource *ds = [self dataSource];
582 NSString *ptitle = [ds pageTitle];
585 case WebFrameLoadTypeForward:
586 case WebFrameLoadTypeBack:
587 case WebFrameLoadTypeIndexedBackForward:
588 if ([[self webView] backForwardList]) {
589 // Must grab the current scroll position before disturbing it
590 [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
592 // Create a document view for this document, or used the cached view.
594 NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
595 ASSERT(cachedView != nil);
596 [[self frameView] _setDocumentView: cachedView];
599 [self _makeDocumentView];
603 case WebFrameLoadTypeReload:
604 case WebFrameLoadTypeSame:
605 case WebFrameLoadTypeReplace:
607 WebHistoryItem *currItem = [_private currentItem];
608 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
609 [currItem setHasPageCache:NO];
610 if (loadType == WebFrameLoadTypeReload) {
611 [self _saveScrollPositionAndViewStateToItem:currItem];
613 NSURLRequest *request = [ds request];
614 if ([request _webDataRequestUnreachableURL] == nil) {
615 // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
616 [currItem setURL:[request URL]];
618 // Update the last visited time. Mostly interesting for URL autocompletion
620 NSURL *URL = [[[ds _originalRequest] URL] _webkit_canonicalize];
621 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
622 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
624 [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
626 [self _makeDocumentView];
630 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
631 case WebFrameLoadTypeReloadAllowingStaleData:
632 [self _makeDocumentView];
635 case WebFrameLoadTypeStandard:
636 if (![ds _isClientRedirect]) {
637 // Add item to history and BF list
638 NSURL *URL = [ds _URLForHistory];
639 if (URL && ![URL _web_isEmpty]){
640 ASSERT([self webView]);
641 if (![[[self webView] preferences] privateBrowsingEnabled]) {
642 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
644 [entry setTitle: ptitle];
646 [self _addBackForwardItemClippedAtTarget:YES];
650 NSURLRequest *request = [ds request];
652 // update the URL in the BF list that we made before the redirect, unless
653 // this is alternate content for an unreachable URL (we want the BF list
654 // item to remember the unreachable URL in case it becomes reachable later)
655 if ([request _webDataRequestUnreachableURL] == nil) {
656 [[_private currentItem] setURL:[request URL]];
658 // clear out the form data so we don't repost it to the wrong place if we
659 // ever go back/forward to this item
660 [[_private currentItem] _setFormInfoFromRequest:request];
662 // We must also clear out form data so we don't try to restore it into the incoming page,
666 [self _makeDocumentView];
669 case WebFrameLoadTypeInternal:
670 // Add an item to the item tree for this frame
671 ASSERT(![ds _isClientRedirect]);
672 WebFrame *parentFrame = [self parentFrame];
674 WebHistoryItem *parentItem = [parentFrame->_private currentItem];
675 // The only case where parentItem==nil should be when a parent frame loaded an
676 // empty URL, which doesn't set up a current item in that parent.
678 [parentItem addChildItem:[self _createItem: YES]];
680 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
681 // for a top-level frame, but that was a likely explanation for those crashes,
682 // so let's guard against it.
683 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
684 LOG_ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
686 [self _makeDocumentView];
689 // FIXME Remove this check when dummy ds is removed. An exception should be thrown
690 // if we're in the WebFrameLoadTypeUninitialized state.
692 ASSERT_NOT_REACHED();
696 // Tell the client we've committed this URL.
697 ASSERT([[self frameView] documentView] != nil);
698 [[self webView] _didCommitLoadForFrame: self];
699 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didCommitLoadForFrame:self];
701 // If we have a title let the WebView know about it.
703 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
704 didReceiveTitle:ptitle
710 case WebFrameStateCommittedPage:
711 case WebFrameStateComplete:
714 ASSERT_NOT_REACHED();
719 - (void)_commitProvisionalLoad:(NSDictionary *)pageCache
721 WebFrameLoadType loadType = [self _loadType];
722 bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
724 WebDataSource *provisionalDataSource = [self provisionalDataSource];
725 NSURLResponse *response = [provisionalDataSource response];
727 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
728 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
730 if (loadType != WebFrameLoadTypeReplace)
731 [self _closeOldDataSources];
734 [provisionalDataSource _makeRepresentation];
736 [self _transitionToCommitted:pageCache];
738 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
739 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
740 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
741 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
742 if (_private->sentRedirectNotification)
743 [self _clientRedirectCancelledOrFinished:NO];
745 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
746 NSURL *URL = baseURL ? baseURL : [response URL];
748 if (!URL || [URL _web_isEmpty])
749 URL = [NSURL URLWithString:@"about:blank"];
751 [[self _bridge] openURL:URL
753 contentType:[response MIMEType]
754 refresh:[headers objectForKey:@"Refresh"]
755 lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
756 pageCache:pageCache];
761 - (BOOL)_canCachePage
763 return [[[self webView] backForwardList] _usesPageCache];
766 - (void)_purgePageCache
768 // This method implements the rule for purging the page cache.
769 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
770 unsigned pagesCached = 0;
771 WebBackForwardList *backForwardList = [[self webView] backForwardList];
772 NSArray *backList = [backForwardList backListWithLimit: 999999];
773 WebHistoryItem *oldestNonSnapbackItem = nil;
776 for (i = 0; i < [backList count]; i++){
777 WebHistoryItem *item = [backList objectAtIndex: i];
778 if ([item hasPageCache]){
779 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
780 oldestNonSnapbackItem = item;
785 // Snapback items are never directly purged here.
786 if (pagesCached >= sizeLimit) {
787 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
788 [oldestNonSnapbackItem setHasPageCache:NO];
792 + (CFAbsoluteTime)_timeOfLastCompletedLoad
794 return [WebFrameLoader timeOfLastCompletedLoad];
797 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
799 NSMutableDictionary *pageCache;
801 [item setHasPageCache: YES];
803 if (![_private->bridge saveDocumentToPageCache]){
804 [item setHasPageCache: NO];
808 pageCache = [item pageCache];
809 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
810 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
811 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
816 // Called after we send an openURL:... down to WebCore.
819 if ([self _loadType] == WebFrameLoadTypeStandard && [[self dataSource] _isClientRedirect]) {
820 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
821 // khtml has closed the URL and saved away the form state.
822 WebHistoryItem *item = [_private currentItem];
823 [item setDocumentState:nil];
824 [item setScrollPoint:NSZeroPoint];
827 if ([[self dataSource] _loadingFromPageCache]){
828 // Force a layout to update view size and thereby update scrollbars.
829 NSView <WebDocumentView> *view = [[self frameView] documentView];
830 if ([view isKindOfClass:[WebHTMLView class]]) {
831 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
833 [view setNeedsLayout: YES];
836 NSArray *responses = [[self dataSource] _responses];
837 NSURLResponse *response;
838 int i, count = [responses count];
839 for (i = 0; i < count; i++){
840 response = [responses objectAtIndex: i];
841 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
844 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
845 [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
846 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
850 // Release the resources kept in the page cache. They will be
851 // reset when we leave this page. The core side of the page cache
852 // will have already been invalidated by the bridge to prevent
853 // premature release.
854 [[_private currentItem] setHasPageCache: NO];
856 [[self dataSource] _setPrimaryLoadComplete: YES];
857 // why only this frame and not parent frames?
858 [self _checkLoadCompleteForThisFrame];
862 - (void)_checkLoadCompleteForThisFrame
864 ASSERT([self webView] != nil);
866 switch ([_private->frameLoader state]) {
867 case WebFrameStateProvisional:
869 if (_private->delegateIsHandlingProvisionalLoadError)
872 WebDataSource *pd = [self provisionalDataSource];
874 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
875 // If we've received any errors we may be stuck in the provisional state and actually
877 NSError *error = [pd _mainDocumentError];
879 // Check all children first.
880 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
881 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
882 BOOL shouldReset = YES;
883 if (![pd isLoading]) {
884 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
885 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
886 _private->delegateIsHandlingProvisionalLoadError = YES;
887 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
888 didFailProvisionalLoadWithError:error
890 _private->delegateIsHandlingProvisionalLoadError = NO;
891 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
893 // FIXME: can stopping loading here possibly have
894 // any effect, if isLoading is false, which it
895 // must be, to be in this branch of the if? And is it ok to just do
896 // a full-on stopLoading?
897 [self _stopLoadingSubframes];
900 // Finish resetting the load state, but only if another load hasn't been started by the
901 // delegate callback.
902 if (pd == [_private->frameLoader provisionalDataSource])
903 [_private->frameLoader clearProvisionalLoad];
905 NSURL *unreachableURL = [[_private->frameLoader provisionalDataSource] unreachableURL];
906 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
911 if (shouldReset && resetItem != nil) {
912 [[[self webView] backForwardList] goToItem:resetItem];
918 case WebFrameStateCommittedPage:
920 WebDataSource *ds = [self dataSource];
922 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
923 if (![ds isLoading]) {
924 WebFrameView *thisView = [self frameView];
925 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
926 ASSERT(thisDocumentView != nil);
928 [_private->frameLoader markLoadComplete];
930 // FIXME: Is this subsequent work important if we already navigated away?
931 // Maybe there are bugs because of that, or extra work we can skip because
932 // the new page is ready.
934 // Tell the just loaded document to layout. This may be necessary
935 // for non-html content that needs a layout message.
936 if (!([[self dataSource] _isDocumentHTML])) {
937 [thisDocumentView setNeedsLayout:YES];
938 [thisDocumentView layout];
939 [thisDocumentView setNeedsDisplay:YES];
942 // If the user had a scroll point scroll to it. This will override
943 // the anchor point. After much discussion it was decided by folks
944 // that the user scroll point should override the anchor point.
945 if ([[self webView] backForwardList]) {
946 switch ([self _loadType]) {
947 case WebFrameLoadTypeForward:
948 case WebFrameLoadTypeBack:
949 case WebFrameLoadTypeIndexedBackForward:
950 case WebFrameLoadTypeReload:
951 [self _restoreScrollPositionAndViewState];
954 case WebFrameLoadTypeStandard:
955 case WebFrameLoadTypeInternal:
956 case WebFrameLoadTypeReloadAllowingStaleData:
957 case WebFrameLoadTypeSame:
958 case WebFrameLoadTypeReplace:
963 ASSERT_NOT_REACHED();
968 NSError *error = [ds _mainDocumentError];
970 [[self webView] _didFailLoadWithError:error forFrame:self];
971 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
972 didFailLoadWithError:error
974 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
976 [[self webView] _didFinishLoadForFrame:self];
977 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
978 didFinishLoadForFrame:self];
979 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
982 [[self webView] _progressCompleted: self];
989 case WebFrameStateComplete:
991 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
992 // Even if already complete, we might have set a previous item on a frame that
993 // didn't do any data loading on the past transaction. Make sure to clear these out.
994 [_private setPreviousItem:nil];
999 // Yikes! Serious horkage.
1000 ASSERT_NOT_REACHED();
1003 - (void)_handledOnloadEvents
1005 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
1008 // Called every time a resource is completely loaded, or an error is received.
1009 - (void)_checkLoadComplete
1011 ASSERT([self webView] != nil);
1013 for (WebFrame *frame = self; frame; frame = [frame parentFrame])
1014 [frame _checkLoadCompleteForThisFrame];
1017 - (WebFrameBridge *)_bridge
1019 return _private->bridge;
1022 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1024 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1025 WebView *wv = [self webView];
1026 _private->delegateIsHandlingUnimplementablePolicy = YES;
1027 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];
1028 _private->delegateIsHandlingUnimplementablePolicy = NO;
1031 // helper method that determines whether the subframes described by the item's subitems
1032 // match our own current frameset
1033 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1035 NSArray *childItems = [item children];
1036 int numChildItems = [childItems count];
1037 int numChildFrames = [self _childFrameCount];
1038 if (numChildFrames != numChildItems)
1042 for (i = 0; i < numChildItems; i++) {
1043 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1044 //Search recursive here?
1045 if (![self _immediateChildFrameNamed:itemTargetName])
1046 return NO; // couldn't match the i'th itemTarget
1049 return YES; // found matches for all itemTargets
1052 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1054 return !(([currentURL fragment] || [destinationURL fragment]) &&
1055 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1058 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1059 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1061 NSURL *currentURL = [[[self dataSource] request] URL];
1063 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1066 NSArray *childItems = [item children];
1067 WebHistoryItem *childItem;
1068 WebFrame *childFrame;
1069 int i, count = [childItems count];
1070 for (i = 0; i < count; i++){
1071 childItem = [childItems objectAtIndex:i];
1072 childFrame = [self _immediateChildFrameNamed:[childItem target]];
1073 if (![childFrame _URLsMatchItem: childItem])
1080 // loads content into this frame, as specified by item
1081 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1083 NSURL *itemURL = [item URL];
1084 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1085 NSURL *currentURL = [[[self dataSource] request] URL];
1086 NSArray *formData = [item formData];
1088 // Are we navigating to an anchor within the page?
1089 // Note if we have child frames we do a real reload, since the child frames might not
1090 // match our current frame structure, or they might not have the right content. We could
1091 // check for all that as an additional optimization.
1092 // We also do not do anchor-style navigation if we're posting a form.
1094 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1095 // Perhaps they should.
1096 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1099 // FIXME: We need to normalize the code paths for anchor navigation. Something
1100 // like the following line of code should be done, but also accounting for correct
1101 // updates to the back/forward list and scroll position.
1102 // rjw 4/9/03 See 3223929.
1103 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1105 // must do this maintenance here, since we don't go through a real page reload
1106 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1107 // FIXME: form state might want to be saved here too
1109 // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
1110 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
1111 [_private->bridge scrollToAnchorWithURL:[item URL]];
1113 // must do this maintenance here, since we don't go through a real page reload
1114 [_private setCurrentItem:item];
1115 [self _restoreScrollPositionAndViewState];
1117 // Fake the URL change by updating the data source's request. This will no longer
1118 // be necessary if we do the better fix described above.
1119 NSMutableURLRequest *hackedRequest = [[[self dataSource] request] mutableCopy];
1120 [hackedRequest setURL: itemURL];
1121 [[self dataSource] __adoptRequest:hackedRequest];
1122 [hackedRequest release];
1124 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1125 didChangeLocationWithinPageForFrame:self];
1126 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1128 // Remember this item so we can traverse any child items as child frames load
1129 [_private setProvisionalItem:item];
1131 WebDataSource *newDataSource;
1132 BOOL inPageCache = NO;
1134 // Check if we'll be using the page cache. We only use the page cache
1135 // if one exists and it is less than _backForwardCacheExpirationInterval
1136 // seconds old. If the cache is expired it gets flushed here.
1137 if ([item hasPageCache]){
1138 NSDictionary *pageCache = [item pageCache];
1139 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1140 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1142 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1143 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1144 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
1148 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]);
1149 [item setHasPageCache: NO];
1154 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1155 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1157 // If this was a repost that failed the page cache, we might try to repost the form.
1158 NSDictionary *action;
1160 [request setHTTPMethod:@"POST"];
1161 [request _web_setHTTPReferrer:[item formReferrer]];
1162 webSetHTTPBody(request, formData);
1163 [request _web_setHTTPContentType:[item formContentType]];
1165 // Slight hack to test if the WF cache contains the page we're going to. We want
1166 // to know this before talking to the policy delegate, since it affects whether we
1167 // show the DoYouReallyWantToRepost nag.
1169 // This trick has a small bug (3123893) where we might find a cache hit, but then
1170 // have the item vanish when we try to use it in the ensuing nav. This should be
1171 // extremely rare, but in that case the user will get an error on the navigation.
1172 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1173 NSURLResponse *synchResponse = nil;
1174 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1175 if (synchResponse == nil) {
1177 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1178 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1180 // We can use the cache, don't use navType=resubmit
1181 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1185 case WebFrameLoadTypeReload:
1186 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1188 case WebFrameLoadTypeBack:
1189 case WebFrameLoadTypeForward:
1190 case WebFrameLoadTypeIndexedBackForward:
1191 if (![[itemURL scheme] isEqual:@"https"]) {
1192 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1195 case WebFrameLoadTypeStandard:
1196 case WebFrameLoadTypeInternal:
1197 // no-op: leave as protocol default
1198 // FIXME: I wonder if we ever hit this case
1200 case WebFrameLoadTypeSame:
1201 case WebFrameLoadTypeReloadAllowingStaleData:
1203 ASSERT_NOT_REACHED();
1206 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1209 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1215 // The general idea here is to traverse the frame tree and the item tree in parallel,
1216 // tracking whether each frame already has the content the item requests. If there is
1217 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1218 // reload that frame, and all its kids.
1219 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1221 NSURL *itemURL = [item URL];
1222 NSURL *currentURL = [[[self dataSource] request] URL];
1224 // Always reload the target frame of the item we're going to. This ensures that we will
1225 // do -some- load for the transition, which means a proper notification will be posted
1227 // The exact URL has to match, including fragment. We want to go through the _load
1228 // method, even if to do a within-page navigation.
1229 // The current frame tree and the frame tree snapshot in the item have to match.
1230 if (![item isTargetItem] &&
1231 [itemURL isEqual:currentURL] &&
1232 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1233 [self _childFramesMatchItem:item])
1235 // This content is good, so leave it alone and look for children that need reloading
1237 // Save form state (works from currentItem, since prevItem is nil)
1238 ASSERT(![_private previousItem]);
1239 [_private->bridge saveDocumentState];
1240 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1242 [_private setCurrentItem:item];
1244 // Restore form state (works from currentItem)
1245 [_private->bridge restoreDocumentState];
1246 // Restore the scroll position (taken in favor of going back to the anchor)
1247 [self _restoreScrollPositionAndViewState];
1249 NSArray *childItems = [item children];
1250 int numChildItems = childItems ? [childItems count] : 0;
1252 for (i = numChildItems - 1; i >= 0; i--) {
1253 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1254 NSString *childName = [childItem target];
1255 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1256 ASSERT(fromChildItem || [fromItem isTargetItem]);
1257 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1259 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1262 // We need to reload the content
1263 [self _loadItem:item withLoadType:type];
1267 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1268 // This includes recursion to handle loading into framesets properly
1269 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1271 ASSERT(![self parentFrame]);
1272 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1273 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1274 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1275 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1276 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
1277 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1278 WebHistoryItem *currItem = [backForwardList currentItem];
1279 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1280 // - plus, it only makes sense for the top level of the operation through the frametree,
1281 // as opposed to happening for some/one of the page commits that might happen soon
1282 [backForwardList goToItem:item];
1283 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1287 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1289 switch ([event type]) {
1290 case NSLeftMouseDown:
1291 case NSRightMouseDown:
1292 case NSOtherMouseDown:
1294 case NSRightMouseUp:
1295 case NSOtherMouseUp:
1297 NSView *topViewInEventWindow = [[event window] contentView];
1298 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1299 while (viewContainingPoint != nil) {
1300 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1303 viewContainingPoint = [viewContainingPoint superview];
1305 if (viewContainingPoint != nil) {
1306 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1307 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1309 return [NSDictionary dictionaryWithObjectsAndKeys:
1310 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1311 elementInfo, WebActionElementKey,
1312 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1313 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1314 URL, WebActionOriginalURLKey,
1322 return [NSDictionary dictionaryWithObjectsAndKeys:
1323 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1324 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1325 URL, WebActionOriginalURLKey,
1330 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1332 WebNavigationType navType;
1333 if (isFormSubmission) {
1334 navType = WebNavigationTypeFormSubmitted;
1335 } else if (event == nil) {
1336 if (loadType == WebFrameLoadTypeReload) {
1337 navType = WebNavigationTypeReload;
1338 } else if (loadType == WebFrameLoadTypeForward
1339 || loadType == WebFrameLoadTypeBack
1340 || loadType == WebFrameLoadTypeIndexedBackForward) {
1341 navType = WebNavigationTypeBackForward;
1343 navType = WebNavigationTypeOther;
1346 navType = WebNavigationTypeLinkClicked;
1348 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1351 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1353 [_private->listener _invalidate];
1354 [_private->listener release];
1355 _private->listener = nil;
1357 NSURLRequest *request = _private->policyRequest;
1358 NSString *frameName = _private->policyFrameName;
1359 id target = _private->policyTarget;
1360 SEL selector = _private->policySelector;
1361 WebFormState *formState = _private->policyFormState;
1363 _private->policyRequest = nil;
1364 _private->policyFrameName = nil;
1365 _private->policyTarget = nil;
1366 _private->policySelector = nil;
1367 _private->policyFormState = nil;
1371 [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1373 [target performSelector:selector withObject:nil withObject:nil];
1378 [frameName release];
1380 [formState release];
1383 - (void)_setPolicyDataSource:(WebDataSource *)dataSource
1385 [dataSource retain];
1386 [_private->policyDataSource release];
1387 _private->policyDataSource = dataSource;
1390 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1392 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1393 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1395 _private->policyRequest = [request retain];
1396 _private->policyTarget = [target retain];
1397 _private->policyFrameName = [frameName retain];
1398 _private->policySelector = selector;
1399 _private->listener = [listener retain];
1400 _private->policyFormState = [formState retain];
1402 WebView *wv = [self webView];
1403 [[wv _policyDelegateForwarder] webView:wv
1404 decidePolicyForNewWindowAction:action
1406 newFrameName:frameName
1407 decisionListener:listener];
1412 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1414 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1415 NSString *frameName = [[_private->policyFrameName retain] autorelease];
1416 id target = [[_private->policyTarget retain] autorelease];
1417 SEL selector = _private->policySelector;
1418 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1420 // will release _private->policy* objects, hence the above retains
1421 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1423 BOOL shouldContinue = NO;
1426 case WebPolicyIgnore:
1428 case WebPolicyDownload:
1429 // FIXME: should download full request
1430 [[self webView] _downloadURL:[request URL]];
1433 shouldContinue = YES;
1436 ASSERT_NOT_REACHED();
1439 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1442 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1443 dataSource:(WebDataSource *)dataSource
1444 formState:(WebFormState *)formState
1446 withSelector:(SEL)selector
1448 NSDictionary *action = [dataSource _triggeringAction];
1449 if (action == nil) {
1450 action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1451 [dataSource _setTriggeringAction:action];
1454 // Don't ask more than once for the same request or if we are loading an empty URL.
1455 // This avoids confusion on the part of the client.
1456 if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1457 [target performSelector:selector withObject:request withObject:nil];
1461 // We are always willing to show alternate content for unreachable URLs;
1462 // treat it like a reload so it maintains the right state for b/f list.
1463 if ([request _webDataRequestUnreachableURL] != nil) {
1464 if (_private->policyLoadType == WebFrameLoadTypeForward
1465 || _private->policyLoadType == WebFrameLoadTypeBack
1466 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1467 _private->policyLoadType = WebFrameLoadTypeReload;
1469 [target performSelector:selector withObject:request withObject:nil];
1473 [dataSource _setLastCheckedRequest:request];
1475 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1477 ASSERT(_private->policyRequest == nil);
1478 _private->policyRequest = [request retain];
1479 ASSERT(_private->policyTarget == nil);
1480 _private->policyTarget = [target retain];
1481 _private->policySelector = selector;
1482 ASSERT(_private->listener == nil);
1483 _private->listener = [listener retain];
1484 ASSERT(_private->policyFormState == nil);
1485 _private->policyFormState = [formState retain];
1487 WebView *wv = [self webView];
1488 _private->delegateIsDecidingNavigationPolicy = YES;
1489 [[wv _policyDelegateForwarder] webView:wv
1490 decidePolicyForNavigationAction:action
1493 decisionListener:listener];
1494 _private->delegateIsDecidingNavigationPolicy = NO;
1499 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1501 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1502 id target = [[_private->policyTarget retain] autorelease];
1503 SEL selector = _private->policySelector;
1504 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1506 // will release _private->policy* objects, hence the above retains
1507 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1509 BOOL shouldContinue = NO;
1512 case WebPolicyIgnore:
1514 case WebPolicyDownload:
1515 // FIXME: should download full request
1516 [[self webView] _downloadURL:[request URL]];
1519 if (![WebView _canHandleRequest:request]) {
1520 [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1522 shouldContinue = YES;
1526 ASSERT_NOT_REACHED();
1529 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1532 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1538 NSURL *URL = [request URL];
1539 WebDataSource *dataSrc = [self dataSource];
1541 BOOL isRedirect = _private->quickRedirectComing;
1542 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1543 _private->quickRedirectComing = NO;
1545 [dataSrc _setURL:URL];
1546 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1547 // NB: must happen after _setURL, since we add based on the current request.
1548 // Must also happen before we openURL and displace the scroll position, since
1549 // adding the BF item will save away scroll state.
1551 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1552 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1553 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1554 // though its load is not yet done. I think this all works out OK, for one because
1555 // we have already saved away the scroll and doc state for the long slow load,
1556 // but it's not an obvious case.
1557 [self _addBackForwardItemClippedAtTarget:NO];
1560 [_private->bridge scrollToAnchorWithURL:URL];
1563 // This will clear previousItem from the rest of the frame tree tree that didn't
1564 // doing any loading. We need to make a pass on this now, since for anchor nav
1565 // we'll not go through a real load and reach Completed state
1566 [self _checkLoadComplete];
1569 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1570 didChangeLocationWithinPageForFrame:self];
1571 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1574 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1580 WebView *webView = nil;
1581 WebView *currentWebView = [self webView];
1582 id wd = [currentWebView UIDelegate];
1583 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1584 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1586 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1589 WebFrame *frame = [webView mainFrame];
1590 [[frame _bridge] setName:frameName];
1592 [[webView _UIDelegateForwarder] webViewShow:webView];
1594 [[self _bridge] setOpener:[frame _bridge]];
1595 [_private->frameLoader _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1599 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1600 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1602 BOOL isFormSubmission = (values != nil);
1604 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1605 [request _web_setHTTPReferrer:referrer];
1606 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
1607 if (loadType == WebFrameLoadTypeReload) {
1608 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1611 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1612 // policy of LoadFromOrigin, but I didn't test that.
1613 ASSERT(loadType != WebFrameLoadTypeSame);
1615 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1616 WebFormState *formState = nil;
1617 if (form && values) {
1618 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1621 if (target != nil) {
1622 WebFrame *targetFrame = [self findFrameNamed:target];
1623 if (targetFrame != nil) {
1624 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1626 [self _checkNewWindowPolicyForRequest:request
1631 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1634 [formState release];
1638 WebDataSource *oldDataSource = [[self dataSource] retain];
1640 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1642 // Make sure to do scroll to anchor processing even if the URL is
1643 // exactly the same so pages with '#' links and DHTML side effects
1645 if (!isFormSubmission
1646 && loadType != WebFrameLoadTypeReload
1647 && loadType != WebFrameLoadTypeSame
1648 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1650 // We don't want to just scroll if a link from within a
1651 // frameset is trying to reload the frameset into _top.
1652 && ![_private->bridge isFrameSet]) {
1654 // Just do anchor navigation within the existing content.
1656 // We don't do this if we are submitting a form, explicitly reloading,
1657 // currently displaying a frameset, or if the new URL does not have a fragment.
1658 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1661 // FIXME: What about load types other than Standard and Reload?
1663 [oldDataSource _setTriggeringAction:action];
1664 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1665 [self _checkNavigationPolicyForRequest:request
1666 dataSource:oldDataSource
1669 withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1671 // must grab this now, since this load may stop the previous load and clear this flag
1672 BOOL isRedirect = _private->quickRedirectComing;
1673 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1675 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1676 _private->quickRedirectComing = NO;
1677 [[self provisionalDataSource] _setIsClientRedirect:YES];
1678 } else if (sameURL) {
1679 // Example of this case are sites that reload the same URL with a different cookie
1680 // driving the generated content, or a master frame with links that drive a target
1681 // frame, where the user has clicked on the same link repeatedly.
1682 [self _setLoadType:WebFrameLoadTypeSame];
1687 [oldDataSource release];
1688 [formState release];
1691 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1693 WebHistoryItem *parentItem = [_private currentItem];
1694 NSArray *childItems = [parentItem children];
1695 WebFrameLoadType loadType = [self _loadType];
1696 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1697 WebHistoryItem *childItem = nil;
1699 // If we're moving in the backforward list, we might want to replace the content
1700 // of this child frame with whatever was there at that point.
1701 // Reload will maintain the frame contents, LoadSame will not.
1703 (loadType == WebFrameLoadTypeForward
1704 || loadType == WebFrameLoadTypeBack
1705 || loadType == WebFrameLoadTypeIndexedBackForward
1706 || loadType == WebFrameLoadTypeReload
1707 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1709 childItem = [parentItem childItemWithName:[childFrame name]];
1711 // Use the original URL to ensure we get all the side-effects, such as
1712 // onLoad handlers, of any redirects that happened. An example of where
1713 // this is needed is Radar 3213556.
1714 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1715 // These behaviors implied by these loadTypes should apply to the child frames
1716 childLoadType = loadType;
1718 if (loadType == WebFrameLoadTypeForward
1719 || loadType == WebFrameLoadTypeBack
1720 || loadType == WebFrameLoadTypeIndexedBackForward)
1722 // For back/forward, remember this item so we can traverse any child items as child frames load
1723 [childFrame->_private setProvisionalItem:childItem];
1725 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1726 [childFrame->_private setCurrentItem:childItem];
1731 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1733 [childFrame loadArchive:archive];
1735 [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1739 - (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
1741 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1742 // This prevents a potential bug which may cause a page with a form that uses itself
1743 // as an action to be returned from the cache without submitting.
1745 // FIXME: Where's the code that implements what the comment above says?
1747 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1748 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1749 [request _web_setHTTPReferrer:referrer];
1750 [request setHTTPMethod:@"POST"];
1751 webSetHTTPBody(request, postData);
1752 [request _web_setHTTPContentType:contentType];
1754 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1755 WebFormState *formState = nil;
1756 if (form && values) {
1757 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1760 if (target != nil) {
1761 WebFrame *targetFrame = [self findFrameNamed:target];
1763 if (targetFrame != nil) {
1764 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1766 [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1769 [formState release];
1773 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1776 [formState release];
1779 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
1781 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
1783 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1784 willPerformClientRedirectToURL:URL
1789 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1790 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1791 _private->sentRedirectNotification = YES;
1793 // If a "quick" redirect comes in an, we set a special mode so we treat the next
1794 // load as part of the same navigation.
1796 if (![self dataSource] || isJavaScriptFormAction) {
1797 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
1798 // so we better just treat the redirect as a normal load.
1799 _private->quickRedirectComing = NO;
1800 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1802 _private->quickRedirectComing = lockHistory;
1803 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1807 - (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
1809 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1810 // the redirect succeeded. We should either rename this API, or add a new method, like
1811 // -webView:didFinishClientRedirectForFrame:
1812 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1813 didCancelClientRedirectForFrame:self];
1814 if (!cancelWithLoadInProgress)
1815 _private->quickRedirectComing = NO;
1817 _private->sentRedirectNotification = NO;
1819 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1822 - (void)_setTitle:(NSString *)title
1824 [[_private currentItem] setTitle:title];
1827 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1830 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1831 NSView *parent = [docView superview];
1832 // we might already be detached when this is called from detachFromParent, in which
1833 // case we don't want to override real data earlier gathered with (0,0)
1836 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1837 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1838 // ScrollView instead of using the one provided by the WebFrame
1839 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1840 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1842 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1843 ASSERT([parent isKindOfClass:[NSClipView class]]);
1844 point = [parent bounds].origin;
1846 [item setScrollPoint:point];
1852 There is a race condition between the layout and load completion that affects restoring the scroll position.
1853 We try to restore the scroll position at both the first layout and upon load completion.
1855 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1856 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1857 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
1858 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1859 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1860 fails. We then successfully restore it when the layout happens.
1863 - (void)_restoreScrollPositionAndViewState
1865 ASSERT([_private currentItem]);
1866 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1867 NSPoint point = [[_private currentItem] scrollPoint];
1868 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1869 id state = [[_private currentItem] viewState];
1871 [(id <_WebDocumentViewState>)docView setViewState:state];
1874 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1876 [docView scrollPoint:point];
1880 - (void)_defersCallbacksChanged
1882 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1883 [[frame provisionalDataSource] _defersCallbacksChanged];
1884 [[frame dataSource] _defersCallbacksChanged];
1888 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1890 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1891 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1894 - (void)_viewDidMoveToHostWindow
1896 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1897 [[[frame frameView] documentView] viewDidMoveToHostWindow];
1900 - (void)_addChild:(WebFrame *)child
1902 [[self _bridge] appendChild:[child _bridge]];
1903 [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
1906 - (void)_resetBackForwardList
1908 // Note this doesn't verify the current load type as a b/f operation because it is called from
1909 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1910 ASSERT(self == [[self webView] mainFrame]);
1911 WebHistoryItem *resetItem = [_private currentItem];
1913 [[[self webView] backForwardList] goToItem:resetItem];
1916 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1917 // item, because we optimistically move it right away at the start of the operation. But when
1918 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1919 // Return the item that we would reset to, so we can decide later whether to actually reset.
1920 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1922 WebFrameLoadType loadType = [self _loadType];
1923 if ((loadType == WebFrameLoadTypeForward
1924 || loadType == WebFrameLoadTypeBack
1925 || loadType == WebFrameLoadTypeIndexedBackForward)
1926 && self == [[self webView] mainFrame]) {
1927 return [_private currentItem];
1932 - (WebHistoryItem *)_itemForSavingDocState
1934 // For a standard page load, we will have a previous item set, which will be used to
1935 // store the form state. However, in some cases we will have no previous item, and
1936 // the current item is the right place to save the state. One example is when we
1937 // detach a bunch of frames because we are navigating from a site with frames to
1938 // another site. Another is when saving the frame state of a frame that is not the
1939 // target of the current navigation (if we even decide to save with that granularity).
1941 // Because of previousItem's "masking" of currentItem for this purpose, it's important
1942 // that previousItem be cleared at the end of a page transition. We leverage the
1943 // checkLoadComplete recursion to achieve this goal.
1945 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
1949 - (WebHistoryItem *)_itemForRestoringDocState
1951 switch ([self _loadType]) {
1952 case WebFrameLoadTypeReload:
1953 case WebFrameLoadTypeReloadAllowingStaleData:
1954 case WebFrameLoadTypeSame:
1955 case WebFrameLoadTypeReplace:
1956 // Don't restore any form state on reload or loadSame
1958 case WebFrameLoadTypeBack:
1959 case WebFrameLoadTypeForward:
1960 case WebFrameLoadTypeIndexedBackForward:
1961 case WebFrameLoadTypeInternal:
1962 case WebFrameLoadTypeStandard:
1963 return [_private currentItem];
1965 ASSERT_NOT_REACHED();
1969 // Walk the frame tree, telling all frames to save their form state into their current
1971 - (void)_saveDocumentAndScrollState
1973 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1974 [[frame _bridge] saveDocumentState];
1975 [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
1979 // Called after the FormsDelegate is done processing willSubmitForm:
1980 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
1982 if (_private->listener) {
1983 [_private->listener _invalidate];
1984 [_private->listener release];
1985 _private->listener = nil;
1987 [_private->frameLoader startLoading];
1990 -(void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1992 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1993 // nil _private->policyDataSource because loading the alternate page will have passed
1994 // through this method already, nested; otherwise, _private->policyDataSource should still be set.
1995 ASSERT(_private->policyDataSource || [[self provisionalDataSource] unreachableURL] != nil);
1997 WebHistoryItem *item = [_private provisionalItem];
1999 // Two reasons we can't continue:
2000 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2001 // is the user responding Cancel to the form repost nag sheet.
2002 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2003 // The "before unload" event handler runs only for the main frame.
2004 BOOL canContinue = request && ([[self webView] mainFrame] != self || [_private->bridge shouldClose]);
2007 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2008 // need to report that the client redirect was cancelled.
2009 if (_private->quickRedirectComing)
2010 [self _clientRedirectCancelledOrFinished:NO];
2012 [self _setPolicyDataSource:nil];
2013 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2014 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2015 // we only do this when punting a navigation for the target frame or top-level frame.
2016 if (([item isTargetItem] || [[self webView] mainFrame] == self)
2017 && (_private->policyLoadType == WebFrameLoadTypeForward
2018 || _private->policyLoadType == WebFrameLoadTypeBack
2019 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward))
2020 [[[self webView] mainFrame] _resetBackForwardList];
2024 WebFrameLoadType loadType = _private->policyLoadType;
2025 WebDataSource *dataSource = [_private->policyDataSource retain];
2028 [self _setLoadType:loadType];
2030 [_private->frameLoader startProvisionalLoad:dataSource];
2032 [dataSource release];
2033 [self _setPolicyDataSource:nil];
2036 if (self == [[self webView] mainFrame])
2037 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2039 if ((loadType == WebFrameLoadTypeForward ||
2040 loadType == WebFrameLoadTypeBack ||
2041 loadType == WebFrameLoadTypeIndexedBackForward) &&
2042 [item hasPageCache]){
2043 NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2044 if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2045 LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2046 [[_private->frameLoader provisionalDataSource] _loadFromPageCache:pageCache];
2052 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2053 // mechanism across the willSubmitForm callout.
2054 _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2055 [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2058 [self _continueAfterWillSubmitForm:WebPolicyUse];
2062 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2064 ASSERT([self webView] != nil);
2066 // Unfortunately the view must be non-nil, this is ultimately due
2067 // to parser requiring a FrameView. We should fix this dependency.
2069 ASSERT([self frameView] != nil);
2071 _private->policyLoadType = loadType;
2073 WebFrame *parentFrame = [self parentFrame];
2075 [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2076 [newDataSource _setWebFrame:self];
2078 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2080 [self _setPolicyDataSource:newDataSource];
2082 [self _checkNavigationPolicyForRequest:[newDataSource request]
2083 dataSource:newDataSource
2086 withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2089 // used to decide to use loadType=Same
2090 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2092 WebHistoryItem *item = [_private currentItem];
2093 NSString* URLString = [URL _web_originalDataAsString];
2094 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2097 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2099 if (frameName == nil) {
2100 [self loadRequest:request];
2104 WebFrame *frame = [self findFrameNamed:frameName];
2107 [frame loadRequest:request];
2111 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2112 [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2115 // Return next frame to be traversed, visiting children after parent
2116 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2118 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
2121 // Return previous frame to be traversed, exact reverse order of _nextFrame
2122 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2124 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
2127 - (void)_setShouldCreateRenderers:(BOOL)f
2129 [_private->bridge setShouldCreateRenderers:f];
2132 - (BOOL)_shouldCreateRenderers
2134 return [_private->bridge shouldCreateRenderers];
2137 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2140 return [[self _bridge] numPendingOrLoadingRequests];
2143 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2144 num += [[frame _bridge] numPendingOrLoadingRequests];
2149 - (NSColor *)_bodyBackgroundColor
2151 return [_private->bridge bodyBackgroundColor];
2154 - (void)_reloadForPluginChanges
2156 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2157 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2158 if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
2163 - (void)_attachScriptDebugger
2165 if (!_private->scriptDebugger)
2166 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
2169 - (void)_detachScriptDebugger
2171 if (_private->scriptDebugger) {
2172 id old = _private->scriptDebugger;
2173 _private->scriptDebugger = nil;
2178 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
2180 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2181 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2182 if ([documentView isKindOfClass:[WebHTMLView class]])
2183 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
2187 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
2189 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2190 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2191 if ([documentView isKindOfClass:[WebHTMLView class]])
2192 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
2196 - (BOOL)_firstLayoutDone
2198 return _private->firstLayoutDone;
2203 @implementation WebFrame (WebInternal)
2205 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
2207 self = [super init];
2211 _private = [[WebFramePrivate alloc] init];
2213 _private->bridge = bridge;
2216 [_private setWebFrameView:fv];
2217 [fv _setWebFrame:self];
2220 _private->frameLoader = [[WebFrameLoader alloc] initWithWebFrame:self];
2227 - (NSArray *)_documentViews
2229 NSMutableArray *result = [NSMutableArray array];
2230 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2231 id docView = [[frame frameView] documentView];
2233 [result addObject:docView];
2239 - (void)_updateBackground
2241 BOOL drawsBackground = [[self webView] drawsBackground];
2242 NSColor *backgroundColor = [[self webView] backgroundColor];
2244 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2245 // Never call setDrawsBackground:YES on the scroll view or the background color will
2246 // flash between pages loads, very noticeable during the PLT.
2247 if (!drawsBackground)
2248 [[[frame frameView] _scrollView] setDrawsBackground:NO];
2249 [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
2250 id documentView = [[frame frameView] documentView];
2251 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
2252 [documentView setDrawsBackground:drawsBackground];
2253 if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
2254 [documentView setBackgroundColor:backgroundColor];
2255 [[frame _bridge] setDrawsBackground:drawsBackground];
2256 [[frame _bridge] setBaseBackgroundColor:backgroundColor];
2260 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2262 _private->internalLoadDelegate = internalLoadDelegate;
2265 - (id)_internalLoadDelegate
2267 return _private->internalLoadDelegate;
2270 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
2272 ASSERT(request != nil);
2274 WebView *wv = [self webView];
2275 id delegate = [wv resourceLoadDelegate];
2276 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2277 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2278 WebDataSource *dataSource = [self dataSource];
2280 if (implementations.delegateImplementsIdentifierForRequest) {
2281 *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2283 *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2286 NSURLRequest *newRequest;
2287 if (implementations.delegateImplementsWillSendRequest) {
2288 newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2290 newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2293 if (newRequest == nil) {
2294 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
2302 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
2304 WebView *wv = [self webView];
2305 id delegate = [wv resourceLoadDelegate];
2306 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2307 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2308 WebDataSource *dataSource = [self dataSource];
2310 if (response != nil) {
2311 if (implementations.delegateImplementsDidReceiveResponse) {
2312 [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2314 [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2319 if (implementations.delegateImplementsDidReceiveContentLength) {
2320 [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2322 [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2327 if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
2328 [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2330 [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2332 [self _checkLoadComplete];
2334 [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
2338 - (void)_safeLoadURL:(NSURL *)URL
2340 // Call the bridge because this is where our security checks are made.
2341 [[self _bridge] loadURL:URL
2342 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2346 triggeringEvent:[NSApp currentEvent]
2351 - (void)_unmarkAllMisspellings
2353 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2354 [[frame _bridge] unmarkAllMisspellings];
2357 - (void)_didFirstLayout
2359 if ([[self webView] backForwardList]) {
2360 WebFrameLoadType loadType = [self _loadType];
2361 if (loadType == WebFrameLoadTypeForward ||
2362 loadType == WebFrameLoadTypeBack ||
2363 loadType == WebFrameLoadTypeIndexedBackForward)
2365 [self _restoreScrollPositionAndViewState];
2369 _private->firstLayoutDone = YES;
2373 - (BOOL)_hasSelection
2375 id documentView = [[self frameView] documentView];
2377 // optimization for common case to avoid creating potentially large selection string
2378 if ([documentView isKindOfClass:[WebHTMLView class]]) {
2379 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
2380 return selectedDOMRange && ![selectedDOMRange collapsed];
2383 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2384 return [[documentView selectedString] length] > 0;
2389 - (void)_clearSelection
2391 id documentView = [[self frameView] documentView];
2392 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2393 [documentView deselectAll];
2398 - (BOOL)_atMostOneFrameHasSelection;
2400 // FIXME: 4186050 is one known case that makes this debug check fail
2402 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2403 if ([frame _hasSelection]) {
2414 - (WebFrame *)_findFrameWithSelection
2416 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2417 if ([frame _hasSelection])
2423 - (void)_clearSelectionInOtherFrames
2425 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
2426 // responder. It would be nicer to just notice first responder changes here instead, but there's no
2427 // notification sent when the first responder changes in general (Radar 2573089).
2428 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
2429 if (frameWithSelection != self)
2430 [frameWithSelection _clearSelection];
2432 // While we're in the general area of selection and frames, check that there is only one now.
2433 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
2436 - (void)_stopLoadingSubframes
2438 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2439 [child stopLoading];
2442 - (BOOL)_subframeIsLoading
2444 // It's most likely that the last added frame is the last to load so we walk backwards.
2445 for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
2446 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
2451 - (void)_addPlugInView:(NSView *)plugInView
2453 ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
2454 ASSERT(![_private->plugInViews containsObject:plugInView]);
2456 if (!_private->plugInViews)
2457 _private->plugInViews = [[NSMutableSet alloc] init];
2459 [plugInView setWebFrame:self];
2460 [_private->plugInViews addObject:plugInView];
2463 - (void)_removeAllPlugInViews
2465 if (!_private->plugInViews)
2468 [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
2469 [_private->plugInViews release];
2470 _private->plugInViews = nil;
2473 // This is called when leaving a page or closing the WebView
2474 - (void)_willCloseURL
2476 [self _removeAllPlugInViews];
2479 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2481 [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
2483 if (_private->loadType == WebFrameLoadTypeReload)
2484 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2486 // Don't set the cookie policy URL if it's already been set.
2487 if ([request mainDocumentURL] == nil) {
2488 if (mainResource && (self == [[self webView] mainFrame] || f))
2489 [request setMainDocumentURL:[request URL]];
2491 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
2495 [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
2498 - (BOOL)_isMainFrame
2500 return self == [[self webView] mainFrame];
2503 - (void)_addInspector:(WebInspector *)inspector
2505 if (!_private->inspectors)
2506 _private->inspectors = [[NSMutableSet alloc] init];
2507 ASSERT(![_private->inspectors containsObject:inspector]);
2508 [_private->inspectors addObject:inspector];
2511 - (void)_removeInspector:(WebInspector *)inspector
2513 ASSERT([_private->inspectors containsObject:inspector]);
2514 [_private->inspectors removeObject:inspector];
2517 - (WebFrameLoader *)_frameLoader
2519 return _private->frameLoader;
2522 - (void)_provisionalLoadStarted
2524 _private->firstLayoutDone = NO;
2525 [_private->bridge provisionalLoadStarted];
2527 // FIXME: This is OK as long as no one resizes the window,
2528 // but in the case where someone does, it means garbage outside
2529 // the occupied part of the scroll view.
2530 [[[self frameView] _scrollView] setDrawsBackground:NO];
2532 // Cache the page, if possible.
2533 // Don't write to the cache if in the middle of a redirect, since we will want to
2534 // store the final page we end up on.
2535 // No point writing to the cache on a reload or loadSame, since we will just write
2536 // over it again when we leave that page.
2537 WebHistoryItem *item = [_private currentItem];
2538 WebFrameLoadType loadType = [self _loadType];
2539 if ([self _canCachePage]
2540 && [_private->bridge canCachePage]
2542 && !_private->quickRedirectComing
2543 && loadType != WebFrameLoadTypeReload
2544 && loadType != WebFrameLoadTypeReloadAllowingStaleData
2545 && loadType != WebFrameLoadTypeSame
2546 && ![[self dataSource] isLoading]
2547 && ![[self dataSource] _isStopping]) {
2548 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
2549 if (![item pageCache]){
2551 // Add the items to this page's cache.
2552 if ([self _createPageCacheForItem:item]) {
2553 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2555 // See if any page caches need to be purged after the addition of this
2557 [self _purgePageCache];
2560 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
2563 // Put the document into a null state, so it can be restored correctly.
2564 [_private->bridge clear];
2566 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2569 - (void)_prepareForDataSourceReplacement
2571 if (![_private->frameLoader dataSource]) {
2572 ASSERT(![self _childFrameCount]);
2576 // Make sure that any work that is triggered by resigning first reponder can get done.
2577 // The main example where this came up is the textDidEndEditing that is sent to the
2578 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
2579 // remove the views as a side-effect of freeing the bridge, at which point we can't
2580 // post the FormDelegate messages.
2582 // Note that this can also take FirstResponder away from a child of our frameView that
2583 // is not in a child frame's view. This is OK because we are in the process
2584 // of loading new content, which will blow away all editors in this top frame, and if
2585 // a non-editor is firstReponder it will not be affected by endEditingFor:.
2586 // Potentially one day someone could write a DocView whose editors were not all
2587 // replaced by loading new content, but that does not apply currently.
2588 NSView *frameView = [self frameView];
2589 NSWindow *window = [frameView window];
2590 NSResponder *firstResp = [window firstResponder];
2591 if ([firstResp isKindOfClass:[NSView class]]
2592 && [(NSView *)firstResp isDescendantOf:frameView])
2594 [window endEditingFor:firstResp];
2597 [self _detachChildren];
2600 - (void)_frameLoadCompleted
2602 NSScrollView *sv = [[self frameView] _scrollView];
2603 if ([[self webView] drawsBackground])
2604 [sv setDrawsBackground:YES];
2605 [_private setPreviousItem:nil];
2606 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
2607 if ([_private->frameLoader dataSource])
2608 _private->firstLayoutDone = YES;
2611 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
2613 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
2614 if (unreachableURL == nil) {
2618 if (_private->policyLoadType != WebFrameLoadTypeForward
2619 && _private->policyLoadType != WebFrameLoadTypeBack
2620 && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
2624 // We only treat unreachableURLs specially during the delegate callbacks
2625 // for provisional load errors and navigation policy decisions. The former
2626 // case handles well-formed URLs that can't be loaded, and the latter
2627 // case handles malformed URLs and unknown schemes. Loading alternate content
2628 // at other times behaves like a standard load.
2629 WebDataSource *compareDataSource = nil;
2630 if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
2631 compareDataSource = _private->policyDataSource;
2632 } else if (_private->delegateIsHandlingProvisionalLoadError) {
2633 compareDataSource = [self provisionalDataSource];
2636 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
2641 @implementation WebFormState : NSObject
2643 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2645 self = [super init];
2649 _form = [form retain];
2650 _values = [values copy];
2651 _sourceFrame = [sourceFrame retain];
2659 [_sourceFrame release];
2663 - (DOMElement *)form
2668 - (NSDictionary *)values
2673 - (WebFrame *)sourceFrame
2675 return _sourceFrame;
2680 @implementation WebFrame
2684 return [self initWithName:nil webFrameView:nil webView:nil];
2687 // FIXME: this method can't work any more and should be marked deprecated
2688 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2690 return [self _initWithWebFrameView:fv webView:v bridge:nil];
2695 ASSERT(_private->bridge == nil);
2705 ASSERT(_private->bridge == nil);
2714 return [[self _bridge] name];
2717 - (WebFrameView *)frameView
2719 return [_private webFrameView];
2722 - (WebView *)webView
2724 return [[[self _bridge] page] webView];
2727 - (DOMDocument *)DOMDocument
2729 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2732 - (DOMHTMLElement *)frameElement
2734 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2737 - (WebDataSource *)provisionalDataSource
2739 return [_private->frameLoader provisionalDataSource];
2742 - (WebDataSource *)dataSource
2744 return [_private->frameLoader dataSource];
2747 - (void)loadRequest:(NSURLRequest *)request
2749 // FIXME: is this the right place to reset loadType? Perhaps, this should be done
2750 // after loading is finished or aborted.
2751 _private->loadType = WebFrameLoadTypeStandard;
2753 [_private->frameLoader _loadRequest:request archive:nil];
2756 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2758 NSURLRequest *request = [self _webDataRequestForData:data
2760 textEncodingName:encodingName
2762 unreachableURL:unreachableURL];
2763 [self loadRequest:request];
2767 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2769 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2772 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2774 CFStringEncoding cfencoding = CFStringGetFastestEncoding((CFStringRef)string);
2775 NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
2776 CFStringRef cfencodingName = CFStringConvertEncodingToIANACharSetName(cfencoding);
2778 if (!cfencodingName || nsencoding == kCFStringEncodingInvalidId){
2779 NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
2780 [self _loadData:data MIMEType:nil textEncodingName:@"utf-16" baseURL:URL unreachableURL:unreachableURL];
2783 NSData *data = [string dataUsingEncoding: nsencoding];
2784 [self _loadData:data MIMEType:nil textEncodingName:(NSString *)cfencodingName baseURL:URL unreachableURL:unreachableURL];
2788 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2790 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2793 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2795 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2798 - (void)loadArchive:(WebArchive *)archive
2800 WebResource *mainResource = [archive mainResource];
2802 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2803 MIMEType:[mainResource MIMEType]
2804 textEncodingName:[mainResource textEncodingName]
2805 baseURL:[mainResource URL]
2806 unreachableURL:nil];
2807 [_private->frameLoader _loadRequest:request archive:archive];
2813 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2814 if (_private->isStoppingLoad)
2817 _private->isStoppingLoad = YES;
2819 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2821 [self _stopLoadingSubframes];
2822 [_private->frameLoader stopLoading];
2824 _private->isStoppingLoad = NO;
2829 [_private->frameLoader reload];
2832 - (WebFrame *)findFrameNamed:(NSString *)name
2834 return Frame([[self _bridge] findFrameNamed:name]);
2837 - (WebFrame *)parentFrame
2839 return [[Frame([[self _bridge] parent]) retain] autorelease];
2842 - (NSArray *)childFrames
2844 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2845 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2846 [children addObject:child];