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/WebDocumentLoadStateMac.h>
41 #import <WebKit/WebFormDataStream.h>
42 #import <WebKit/WebFrameLoadDelegate.h>
43 #import <WebKit/WebFrameLoader.h>
44 #import <WebKit/WebFrameViewInternal.h>
45 #import <WebKit/WebHistoryPrivate.h>
46 #import <WebKit/WebHistoryItemPrivate.h>
47 #import <WebKit/WebHTMLRepresentationPrivate.h>
48 #import <WebKit/WebHTMLViewInternal.h>
49 #import <WebKit/WebHTMLViewPrivate.h>
50 #import <WebKit/WebKitErrorsPrivate.h>
51 #import <WebKit/WebKitLogging.h>
52 #import <WebKit/WebKitNSStringExtras.h>
53 #import <WebKit/WebKitStatisticsPrivate.h>
54 #import <WebKit/WebNetscapePluginEmbeddedView.h>
55 #import <WebKit/WebNSObjectExtras.h>
56 #import <WebKit/WebNSURLExtras.h>
57 #import <WebKit/WebNSURLRequestExtras.h>
58 #import <WebKit/WebNullPluginView.h>
59 #import <WebKit/WebPreferencesPrivate.h>
60 #import <WebKit/WebPlugin.h>
61 #import <WebKit/WebPluginController.h>
62 #import <WebKit/WebResourceLoadDelegate.h>
63 #import <WebKit/WebResourcePrivate.h>
64 #import <WebKit/WebViewInternal.h>
65 #import <WebKit/WebUIDelegate.h>
66 #import <WebKit/WebScriptDebugDelegatePrivate.h>
67 #import <WebKitSystemInterface.h>
69 #import <objc/objc-runtime.h>
72 Here is the current behavior matrix for four types of navigations:
76 Restore form state: YES
77 Restore scroll and focus state: YES
78 WF Cache policy: NSURLRequestUseProtocolCachePolicy
79 Add to back/forward list: YES
83 Restore form state: YES
84 Restore scroll and focus state: YES
85 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
86 Add to back/forward list: NO
88 Reload (meaning only the reload button):
90 Restore form state: NO
91 Restore scroll and focus state: YES
92 WF Cache policy: NSURLRequestReloadIgnoringCacheData
93 Add to back/forward list: NO
95 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
97 Restore form state: NO
98 Restore scroll and focus state: NO, reset to initial conditions
99 WF Cache policy: NSURLRequestReloadIgnoringCacheData
100 Add to back/forward list: NO
103 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
104 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
105 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
107 @interface NSObject (WebExtraPerformMethod)
109 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3;
113 @implementation NSObject (WebExtraPerformMethod)
115 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3
117 return objc_msgSend(self, aSelector, object1, object2, object3);
122 // One day we might want to expand the use of this kind of class such that we'd receive one
123 // over the bridge, and possibly hand it on through to the FormsDelegate.
124 // Today it is just used internally to keep some state as we make our way through a bunch
125 // layers while doing a load.
126 @interface WebFormState : NSObject
129 NSDictionary *_values;
130 WebFrame *_sourceFrame;
132 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame;
133 - (DOMElement *)form;
134 - (NSDictionary *)values;
135 - (WebFrame *)sourceFrame;
138 @interface WebFrame (ForwardDecls)
139 - (WebDataSource *)_policyDataSource;
140 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
141 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
143 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
144 - (void)_restoreScrollPositionAndViewState;
146 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
147 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
148 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
149 - (void)_stopLoadingSubframes;
152 @interface WebFrame (FrameTraversal)
153 - (WebFrame *)_firstChildFrame;
154 - (WebFrame *)_lastChildFrame;
155 - (unsigned)_childFrameCount;
156 - (WebFrame *)_previousSiblingFrame;
157 - (WebFrame *)_nextSiblingFrame;
158 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
161 @interface NSView (WebFramePluginHosting)
162 - (void)setWebFrame:(WebFrame *)webFrame;
165 @interface WebFramePrivate : NSObject
168 WebFrameView *webFrameView;
169 WebFrameLoader *frameLoader;
171 WebFrameBridge *bridge;
172 WebFrameLoadType loadType;
173 WebHistoryItem *currentItem; // BF item for our current content
174 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
175 // (only known when navigating to a pre-existing BF item)
176 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
178 WebPolicyDecisionListener *listener;
179 // state we'll need to continue after waiting for the policy delegate's decision
180 NSURLRequest *policyRequest;
181 NSString *policyFrameName;
184 WebFormState *policyFormState;
186 WebFrameLoadType policyLoadType;
188 BOOL quickRedirectComing;
189 BOOL sentRedirectNotification;
191 BOOL delegateIsHandlingProvisionalLoadError;
192 BOOL delegateIsDecidingNavigationPolicy;
193 BOOL delegateIsHandlingUnimplementablePolicy;
194 BOOL firstLayoutDone;
196 id internalLoadDelegate;
197 WebScriptDebugger *scriptDebugger;
199 NSString *frameNamespace;
201 NSMutableSet *plugInViews;
202 NSMutableSet *inspectors;
205 - (void)setWebFrameView:(WebFrameView *)v;
206 - (WebFrameView *)webFrameView;
207 - (WebFrameLoadType)loadType;
208 - (void)setLoadType:(WebFrameLoadType)loadType;
210 - (void)setProvisionalItem:(WebHistoryItem *)item;
211 - (WebHistoryItem *)provisionalItem;
212 - (void)setPreviousItem:(WebHistoryItem *)item;
213 - (WebHistoryItem *)previousItem;
214 - (void)setCurrentItem:(WebHistoryItem *)item;
215 - (WebHistoryItem *)currentItem;
219 @implementation WebFramePrivate
228 loadType = WebFrameLoadTypeStandard;
235 [webFrameView release];
236 [frameLoader release];
238 [currentItem release];
239 [provisionalItem release];
240 [previousItem release];
242 [scriptDebugger release];
244 [inspectors release];
246 ASSERT(listener == nil);
247 ASSERT(policyRequest == nil);
248 ASSERT(policyFrameName == nil);
249 ASSERT(policyTarget == nil);
250 ASSERT(policyFormState == nil);
251 ASSERT(frameNamespace == nil);
252 ASSERT(plugInViews == nil);
257 - (WebFrameView *)webFrameView { return webFrameView; }
258 - (void)setWebFrameView: (WebFrameView *)v
261 [webFrameView release];
265 - (WebFrameLoadType)loadType { return loadType; }
266 - (void)setLoadType: (WebFrameLoadType)t
271 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
272 - (void)setProvisionalItem: (WebHistoryItem *)item
275 [provisionalItem release];
276 provisionalItem = item;
279 - (WebHistoryItem *)previousItem { return previousItem; }
280 - (void)setPreviousItem:(WebHistoryItem *)item
283 [previousItem release];
287 - (WebHistoryItem *)currentItem { return currentItem; }
288 - (void)setCurrentItem:(WebHistoryItem *)item
291 [currentItem release];
297 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
299 return [(WebFrameBridge *)bridge webFrame];
302 @implementation WebFrame (FrameTraversal)
303 - (WebFrame *)_firstChildFrame
305 return Frame([[self _bridge] firstChild]);
308 - (WebFrame *)_lastChildFrame
310 return Frame([[self _bridge] lastChild]);
313 - (unsigned)_childFrameCount
315 return [[self _bridge] childCount];
318 - (WebFrame *)_previousSiblingFrame;
320 return Frame([[self _bridge] previousSibling]);
323 - (WebFrame *)_nextSiblingFrame;
325 return Frame([[self _bridge] nextSibling]);
328 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
330 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
335 @implementation WebFrame (WebPrivate)
337 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
339 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
340 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
341 [request _webDataRequestSetData:data];
342 [request _webDataRequestSetEncoding:encodingName];
343 [request _webDataRequestSetBaseURL:URL];
344 [request _webDataRequestSetUnreachableURL:unreachableURL];
345 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
349 // helper method used in various nav cases below
350 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
352 if ([[self dataSource] _URLForHistory] != nil) {
353 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
354 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
355 [[[self webView] backForwardList] addItem:bfItem];
359 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
361 WebDataSource *dataSrc = [self dataSource];
362 NSURLRequest *request;
363 NSURL *unreachableURL = [dataSrc unreachableURL];
366 WebHistoryItem *bfItem;
369 request = [[dataSrc _documentLoadState] originalRequestCopy];
371 request = [dataSrc request];
373 if (unreachableURL != nil) {
374 URL = unreachableURL;
375 originalURL = unreachableURL;
378 originalURL = [[[dataSrc _documentLoadState] originalRequestCopy] 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 provisionalDocumentLoadState] originalRequestCopy] 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 _documentLoadState] originalRequestCopy] 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] retain];
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];
760 [provisionalDataSource release];
763 - (BOOL)_canCachePage
765 return [[[self webView] backForwardList] _usesPageCache];
768 - (void)_purgePageCache
770 // This method implements the rule for purging the page cache.
771 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
772 unsigned pagesCached = 0;
773 WebBackForwardList *backForwardList = [[self webView] backForwardList];
774 NSArray *backList = [backForwardList backListWithLimit: 999999];
775 WebHistoryItem *oldestNonSnapbackItem = nil;
778 for (i = 0; i < [backList count]; i++){
779 WebHistoryItem *item = [backList objectAtIndex: i];
780 if ([item hasPageCache]){
781 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
782 oldestNonSnapbackItem = item;
787 // Snapback items are never directly purged here.
788 if (pagesCached >= sizeLimit) {
789 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
790 [oldestNonSnapbackItem setHasPageCache:NO];
794 + (CFAbsoluteTime)_timeOfLastCompletedLoad
796 return [WebFrameLoader timeOfLastCompletedLoad];
799 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
801 NSMutableDictionary *pageCache;
803 [item setHasPageCache: YES];
805 if (![_private->bridge saveDocumentToPageCache]){
806 [item setHasPageCache: NO];
810 pageCache = [item pageCache];
811 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
812 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
813 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
818 // Called after we send an openURL:... down to WebCore.
821 if ([self _loadType] == WebFrameLoadTypeStandard && [[self dataSource] _isClientRedirect]) {
822 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
823 // khtml has closed the URL and saved away the form state.
824 WebHistoryItem *item = [_private currentItem];
825 [item setDocumentState:nil];
826 [item setScrollPoint:NSZeroPoint];
829 if ([[self dataSource] _loadingFromPageCache]){
830 // Force a layout to update view size and thereby update scrollbars.
831 NSView <WebDocumentView> *view = [[self frameView] documentView];
832 if ([view isKindOfClass:[WebHTMLView class]]) {
833 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
835 [view setNeedsLayout: YES];
838 NSArray *responses = [[self dataSource] _responses];
839 NSURLResponse *response;
840 int i, count = [responses count];
841 for (i = 0; i < count; i++){
842 response = [responses objectAtIndex: i];
843 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
846 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
847 [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
848 [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
852 // Release the resources kept in the page cache. They will be
853 // reset when we leave this page. The core side of the page cache
854 // will have already been invalidated by the bridge to prevent
855 // premature release.
856 [[_private currentItem] setHasPageCache: NO];
858 [[self dataSource] _setPrimaryLoadComplete: YES];
859 // why only this frame and not parent frames?
860 [self _checkLoadCompleteForThisFrame];
864 - (void)_checkLoadCompleteForThisFrame
866 ASSERT([self webView] != nil);
868 switch ([_private->frameLoader state]) {
869 case WebFrameStateProvisional:
871 if (_private->delegateIsHandlingProvisionalLoadError)
874 WebDataSource *pd = [self provisionalDataSource];
876 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [self name]);
877 // If we've received any errors we may be stuck in the provisional state and actually
879 NSError *error = [pd _mainDocumentError];
881 // Check all children first.
882 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [self name]);
883 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
884 BOOL shouldReset = YES;
885 if (![pd isLoading]) {
886 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [self name]);
887 [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
888 _private->delegateIsHandlingProvisionalLoadError = YES;
889 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
890 didFailProvisionalLoadWithError:error
892 _private->delegateIsHandlingProvisionalLoadError = NO;
893 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
895 // FIXME: can stopping loading here possibly have
896 // any effect, if isLoading is false, which it
897 // must be, to be in this branch of the if? And is it ok to just do
898 // a full-on stopLoading?
899 [self _stopLoadingSubframes];
900 [[pd _documentLoadState] stopLoading];
902 // Finish resetting the load state, but only if another load hasn't been started by the
903 // delegate callback.
904 if (pd == [_private->frameLoader provisionalDataSource])
905 [_private->frameLoader clearProvisionalLoad];
907 NSURL *unreachableURL = [[_private->frameLoader provisionalDataSource] unreachableURL];
908 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
913 if (shouldReset && resetItem != nil) {
914 [[[self webView] backForwardList] goToItem:resetItem];
920 case WebFrameStateCommittedPage:
922 WebDataSource *ds = [self dataSource];
924 //LOG(Loading, "%@: checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
925 if (![ds isLoading]) {
926 WebFrameView *thisView = [self frameView];
927 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
928 ASSERT(thisDocumentView != nil);
930 [_private->frameLoader markLoadComplete];
932 // FIXME: Is this subsequent work important if we already navigated away?
933 // Maybe there are bugs because of that, or extra work we can skip because
934 // the new page is ready.
936 // Tell the just loaded document to layout. This may be necessary
937 // for non-html content that needs a layout message.
938 if (!([[self dataSource] _isDocumentHTML])) {
939 [thisDocumentView setNeedsLayout:YES];
940 [thisDocumentView layout];
941 [thisDocumentView setNeedsDisplay:YES];
944 // If the user had a scroll point scroll to it. This will override
945 // the anchor point. After much discussion it was decided by folks
946 // that the user scroll point should override the anchor point.
947 if ([[self webView] backForwardList]) {
948 switch ([self _loadType]) {
949 case WebFrameLoadTypeForward:
950 case WebFrameLoadTypeBack:
951 case WebFrameLoadTypeIndexedBackForward:
952 case WebFrameLoadTypeReload:
953 [self _restoreScrollPositionAndViewState];
956 case WebFrameLoadTypeStandard:
957 case WebFrameLoadTypeInternal:
958 case WebFrameLoadTypeReloadAllowingStaleData:
959 case WebFrameLoadTypeSame:
960 case WebFrameLoadTypeReplace:
965 ASSERT_NOT_REACHED();
970 NSError *error = [ds _mainDocumentError];
972 [[self webView] _didFailLoadWithError:error forFrame:self];
973 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
974 didFailLoadWithError:error
976 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
978 [[self webView] _didFinishLoadForFrame:self];
979 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
980 didFinishLoadForFrame:self];
981 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
984 [[self webView] _progressCompleted: self];
991 case WebFrameStateComplete:
993 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [self name]);
994 // Even if already complete, we might have set a previous item on a frame that
995 // didn't do any data loading on the past transaction. Make sure to clear these out.
996 [_private setPreviousItem:nil];
1001 // Yikes! Serious horkage.
1002 ASSERT_NOT_REACHED();
1005 - (void)_handledOnloadEvents
1007 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
1010 // Called every time a resource is completely loaded, or an error is received.
1011 - (void)_checkLoadComplete
1013 ASSERT([self webView] != nil);
1016 for (WebFrame *frame = self; frame; frame = parent) {
1018 [frame _checkLoadCompleteForThisFrame];
1019 parent = [frame parentFrame];
1024 - (WebFrameBridge *)_bridge
1026 return _private->bridge;
1029 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1031 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1032 WebView *wv = [self webView];
1033 _private->delegateIsHandlingUnimplementablePolicy = YES;
1034 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];
1035 _private->delegateIsHandlingUnimplementablePolicy = NO;
1038 // helper method that determines whether the subframes described by the item's subitems
1039 // match our own current frameset
1040 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1042 NSArray *childItems = [item children];
1043 int numChildItems = [childItems count];
1044 int numChildFrames = [self _childFrameCount];
1045 if (numChildFrames != numChildItems)
1049 for (i = 0; i < numChildItems; i++) {
1050 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1051 //Search recursive here?
1052 if (![self _immediateChildFrameNamed:itemTargetName])
1053 return NO; // couldn't match the i'th itemTarget
1056 return YES; // found matches for all itemTargets
1059 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1061 return !(([currentURL fragment] || [destinationURL fragment]) &&
1062 [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1065 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1066 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1068 NSURL *currentURL = [[[self dataSource] request] URL];
1070 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1073 NSArray *childItems = [item children];
1074 WebHistoryItem *childItem;
1075 WebFrame *childFrame;
1076 int i, count = [childItems count];
1077 for (i = 0; i < count; i++){
1078 childItem = [childItems objectAtIndex:i];
1079 childFrame = [self _immediateChildFrameNamed:[childItem target]];
1080 if (![childFrame _URLsMatchItem: childItem])
1087 // loads content into this frame, as specified by item
1088 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1090 NSURL *itemURL = [item URL];
1091 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1092 NSURL *currentURL = [[[self dataSource] request] URL];
1093 NSArray *formData = [item formData];
1095 // Are we navigating to an anchor within the page?
1096 // Note if we have child frames we do a real reload, since the child frames might not
1097 // match our current frame structure, or they might not have the right content. We could
1098 // check for all that as an additional optimization.
1099 // We also do not do anchor-style navigation if we're posting a form.
1101 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1102 // Perhaps they should.
1103 if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1106 // FIXME: We need to normalize the code paths for anchor navigation. Something
1107 // like the following line of code should be done, but also accounting for correct
1108 // updates to the back/forward list and scroll position.
1109 // rjw 4/9/03 See 3223929.
1110 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1112 // must do this maintenance here, since we don't go through a real page reload
1113 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1114 // FIXME: form state might want to be saved here too
1116 // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
1117 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
1118 [_private->bridge scrollToAnchorWithURL:[item URL]];
1120 // must do this maintenance here, since we don't go through a real page reload
1121 [_private setCurrentItem:item];
1122 [self _restoreScrollPositionAndViewState];
1124 // Fake the URL change by updating the data source's request. This will no longer
1125 // be necessary if we do the better fix described above.
1126 [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:itemURL];
1128 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1129 didChangeLocationWithinPageForFrame:self];
1130 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1132 // Remember this item so we can traverse any child items as child frames load
1133 [_private setProvisionalItem:item];
1135 WebDataSource *newDataSource;
1136 BOOL inPageCache = NO;
1138 // Check if we'll be using the page cache. We only use the page cache
1139 // if one exists and it is less than _backForwardCacheExpirationInterval
1140 // seconds old. If the cache is expired it gets flushed here.
1141 if ([item hasPageCache]){
1142 NSDictionary *pageCache = [item pageCache];
1143 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1144 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1146 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1147 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1148 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];
1152 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]);
1153 [item setHasPageCache: NO];
1158 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1159 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1161 // If this was a repost that failed the page cache, we might try to repost the form.
1162 NSDictionary *action;
1164 [request setHTTPMethod:@"POST"];
1165 [request _web_setHTTPReferrer:[item formReferrer]];
1166 webSetHTTPBody(request, formData);
1167 [request _web_setHTTPContentType:[item formContentType]];
1169 // Slight hack to test if the WF cache contains the page we're going to. We want
1170 // to know this before talking to the policy delegate, since it affects whether we
1171 // show the DoYouReallyWantToRepost nag.
1173 // This trick has a small bug (3123893) where we might find a cache hit, but then
1174 // have the item vanish when we try to use it in the ensuing nav. This should be
1175 // extremely rare, but in that case the user will get an error on the navigation.
1176 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1177 NSURLResponse *synchResponse = nil;
1178 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1179 if (synchResponse == nil) {
1181 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1182 action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1184 // We can use the cache, don't use navType=resubmit
1185 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1189 case WebFrameLoadTypeReload:
1190 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1192 case WebFrameLoadTypeBack:
1193 case WebFrameLoadTypeForward:
1194 case WebFrameLoadTypeIndexedBackForward:
1195 if (![[itemURL scheme] isEqual:@"https"]) {
1196 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1199 case WebFrameLoadTypeStandard:
1200 case WebFrameLoadTypeInternal:
1201 // no-op: leave as protocol default
1202 // FIXME: I wonder if we ever hit this case
1204 case WebFrameLoadTypeSame:
1205 case WebFrameLoadTypeReloadAllowingStaleData:
1207 ASSERT_NOT_REACHED();
1210 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1213 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1219 // The general idea here is to traverse the frame tree and the item tree in parallel,
1220 // tracking whether each frame already has the content the item requests. If there is
1221 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
1222 // reload that frame, and all its kids.
1223 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1225 NSURL *itemURL = [item URL];
1226 NSURL *currentURL = [[[self dataSource] request] URL];
1228 // Always reload the target frame of the item we're going to. This ensures that we will
1229 // do -some- load for the transition, which means a proper notification will be posted
1231 // The exact URL has to match, including fragment. We want to go through the _load
1232 // method, even if to do a within-page navigation.
1233 // The current frame tree and the frame tree snapshot in the item have to match.
1234 if (![item isTargetItem] &&
1235 [itemURL isEqual:currentURL] &&
1236 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1237 [self _childFramesMatchItem:item])
1239 // This content is good, so leave it alone and look for children that need reloading
1241 // Save form state (works from currentItem, since prevItem is nil)
1242 ASSERT(![_private previousItem]);
1243 [_private->bridge saveDocumentState];
1244 [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1246 [_private setCurrentItem:item];
1248 // Restore form state (works from currentItem)
1249 [_private->bridge restoreDocumentState];
1250 // Restore the scroll position (taken in favor of going back to the anchor)
1251 [self _restoreScrollPositionAndViewState];
1253 NSArray *childItems = [item children];
1254 int numChildItems = childItems ? [childItems count] : 0;
1256 for (i = numChildItems - 1; i >= 0; i--) {
1257 WebHistoryItem *childItem = [childItems objectAtIndex:i];
1258 NSString *childName = [childItem target];
1259 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1260 ASSERT(fromChildItem || [fromItem isTargetItem]);
1261 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1263 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1266 // We need to reload the content
1267 [self _loadItem:item withLoadType:type];
1271 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1272 // This includes recursion to handle loading into framesets properly
1273 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1275 ASSERT(![self parentFrame]);
1276 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1277 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1278 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1279 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1280 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
1281 WebBackForwardList *backForwardList = [[self webView] backForwardList];
1282 WebHistoryItem *currItem = [backForwardList currentItem];
1283 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1284 // - plus, it only makes sense for the top level of the operation through the frametree,
1285 // as opposed to happening for some/one of the page commits that might happen soon
1286 [backForwardList goToItem:item];
1287 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1291 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1293 switch ([event type]) {
1294 case NSLeftMouseDown:
1295 case NSRightMouseDown:
1296 case NSOtherMouseDown:
1298 case NSRightMouseUp:
1299 case NSOtherMouseUp:
1301 NSView *topViewInEventWindow = [[event window] contentView];
1302 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1303 while (viewContainingPoint != nil) {
1304 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1307 viewContainingPoint = [viewContainingPoint superview];
1309 if (viewContainingPoint != nil) {
1310 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1311 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1313 return [NSDictionary dictionaryWithObjectsAndKeys:
1314 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1315 elementInfo, WebActionElementKey,
1316 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1317 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1318 URL, WebActionOriginalURLKey,
1326 return [NSDictionary dictionaryWithObjectsAndKeys:
1327 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1328 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1329 URL, WebActionOriginalURLKey,
1334 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1336 WebNavigationType navType;
1337 if (isFormSubmission) {
1338 navType = WebNavigationTypeFormSubmitted;
1339 } else if (event == nil) {
1340 if (loadType == WebFrameLoadTypeReload) {
1341 navType = WebNavigationTypeReload;
1342 } else if (loadType == WebFrameLoadTypeForward
1343 || loadType == WebFrameLoadTypeBack
1344 || loadType == WebFrameLoadTypeIndexedBackForward) {
1345 navType = WebNavigationTypeBackForward;
1347 navType = WebNavigationTypeOther;
1350 navType = WebNavigationTypeLinkClicked;
1352 return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1355 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1357 [_private->listener _invalidate];
1358 [_private->listener release];
1359 _private->listener = nil;
1361 NSURLRequest *request = _private->policyRequest;
1362 NSString *frameName = _private->policyFrameName;
1363 id target = _private->policyTarget;
1364 SEL selector = _private->policySelector;
1365 WebFormState *formState = _private->policyFormState;
1367 _private->policyRequest = nil;
1368 _private->policyFrameName = nil;
1369 _private->policyTarget = nil;
1370 _private->policySelector = nil;
1371 _private->policyFormState = nil;
1375 [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1377 [target performSelector:selector withObject:nil withObject:nil];
1382 [frameName release];
1384 [formState release];
1387 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1389 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1390 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1392 _private->policyRequest = [request retain];
1393 _private->policyTarget = [target retain];
1394 _private->policyFrameName = [frameName retain];
1395 _private->policySelector = selector;
1396 _private->listener = [listener retain];
1397 _private->policyFormState = [formState retain];
1399 WebView *wv = [self webView];
1400 [[wv _policyDelegateForwarder] webView:wv
1401 decidePolicyForNewWindowAction:action
1403 newFrameName:frameName
1404 decisionListener:listener];
1409 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1411 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1412 NSString *frameName = [[_private->policyFrameName retain] autorelease];
1413 id target = [[_private->policyTarget retain] autorelease];
1414 SEL selector = _private->policySelector;
1415 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1417 // will release _private->policy* objects, hence the above retains
1418 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1420 BOOL shouldContinue = NO;
1423 case WebPolicyIgnore:
1425 case WebPolicyDownload:
1426 // FIXME: should download full request
1427 [[self webView] _downloadURL:[request URL]];
1430 shouldContinue = YES;
1433 ASSERT_NOT_REACHED();
1436 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1439 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1440 dataSource:(WebDataSource *)dataSource
1441 formState:(WebFormState *)formState
1443 withSelector:(SEL)selector
1445 NSDictionary *action = [dataSource _triggeringAction];
1446 if (action == nil) {
1447 action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1448 [dataSource _setTriggeringAction:action];
1451 // Don't ask more than once for the same request or if we are loading an empty URL.
1452 // This avoids confusion on the part of the client.
1453 if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1454 [target performSelector:selector withObject:request withObject:nil];
1458 // We are always willing to show alternate content for unreachable URLs;
1459 // treat it like a reload so it maintains the right state for b/f list.
1460 if ([request _webDataRequestUnreachableURL] != nil) {
1461 if (_private->policyLoadType == WebFrameLoadTypeForward
1462 || _private->policyLoadType == WebFrameLoadTypeBack
1463 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1464 _private->policyLoadType = WebFrameLoadTypeReload;
1466 [target performSelector:selector withObject:request withObject:nil];
1470 [dataSource _setLastCheckedRequest:request];
1472 WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1474 ASSERT(_private->policyRequest == nil);
1475 _private->policyRequest = [request retain];
1476 ASSERT(_private->policyTarget == nil);
1477 _private->policyTarget = [target retain];
1478 _private->policySelector = selector;
1479 ASSERT(_private->listener == nil);
1480 _private->listener = [listener retain];
1481 ASSERT(_private->policyFormState == nil);
1482 _private->policyFormState = [formState retain];
1484 WebView *wv = [self webView];
1485 _private->delegateIsDecidingNavigationPolicy = YES;
1486 [[wv _policyDelegateForwarder] webView:wv
1487 decidePolicyForNavigationAction:action
1490 decisionListener:listener];
1491 _private->delegateIsDecidingNavigationPolicy = NO;
1496 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1498 NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1499 id target = [[_private->policyTarget retain] autorelease];
1500 SEL selector = _private->policySelector;
1501 WebFormState *formState = [[_private->policyFormState retain] autorelease];
1503 // will release _private->policy* objects, hence the above retains
1504 [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1506 BOOL shouldContinue = NO;
1509 case WebPolicyIgnore:
1511 case WebPolicyDownload:
1512 // FIXME: should download full request
1513 [[self webView] _downloadURL:[request URL]];
1516 if (![WebView _canHandleRequest:request]) {
1517 [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1519 shouldContinue = YES;
1523 ASSERT_NOT_REACHED();
1526 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1529 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1535 NSURL *URL = [request URL];
1537 BOOL isRedirect = _private->quickRedirectComing;
1538 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1539 _private->quickRedirectComing = NO;
1541 [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:URL];
1542 if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1543 // NB: must happen after _setURL, since we add based on the current request.
1544 // Must also happen before we openURL and displace the scroll position, since
1545 // adding the BF item will save away scroll state.
1547 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
1548 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1549 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
1550 // though its load is not yet done. I think this all works out OK, for one because
1551 // we have already saved away the scroll and doc state for the long slow load,
1552 // but it's not an obvious case.
1553 [self _addBackForwardItemClippedAtTarget:NO];
1556 [_private->bridge scrollToAnchorWithURL:URL];
1559 // This will clear previousItem from the rest of the frame tree tree that didn't
1560 // doing any loading. We need to make a pass on this now, since for anchor nav
1561 // we'll not go through a real load and reach Completed state
1562 [self _checkLoadComplete];
1565 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1566 didChangeLocationWithinPageForFrame:self];
1567 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1570 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1577 WebView *webView = nil;
1578 WebView *currentWebView = [self webView];
1579 id wd = [currentWebView UIDelegate];
1580 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1581 webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1583 webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1587 WebFrame *frame = [webView mainFrame];
1593 [[frame _bridge] setName:frameName];
1595 [[webView _UIDelegateForwarder] webViewShow:webView];
1597 [[frame _bridge] setOpener:[self _bridge]];
1598 [frame->_private->frameLoader _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1606 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1607 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1609 BOOL isFormSubmission = (values != nil);
1611 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1612 [request _web_setHTTPReferrer:referrer];
1613 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
1614 if (loadType == WebFrameLoadTypeReload) {
1615 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1618 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
1619 // policy of LoadFromOrigin, but I didn't test that.
1620 ASSERT(loadType != WebFrameLoadTypeSame);
1622 NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1623 WebFormState *formState = nil;
1624 if (form && values) {
1625 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1628 if (target != nil) {
1629 WebFrame *targetFrame = [self findFrameNamed:target];
1630 if (targetFrame != nil) {
1631 [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1633 [self _checkNewWindowPolicyForRequest:request
1638 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1641 [formState release];
1645 WebDataSource *oldDataSource = [[self dataSource] retain];
1647 BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1649 // Make sure to do scroll to anchor processing even if the URL is
1650 // exactly the same so pages with '#' links and DHTML side effects
1652 if (!isFormSubmission
1653 && loadType != WebFrameLoadTypeReload
1654 && loadType != WebFrameLoadTypeSame
1655 && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1657 // We don't want to just scroll if a link from within a
1658 // frameset is trying to reload the frameset into _top.
1659 && ![_private->bridge isFrameSet]) {
1661 // Just do anchor navigation within the existing content.
1663 // We don't do this if we are submitting a form, explicitly reloading,
1664 // currently displaying a frameset, or if the new URL does not have a fragment.
1665 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1668 // FIXME: What about load types other than Standard and Reload?
1670 [oldDataSource _setTriggeringAction:action];
1671 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1672 [self _checkNavigationPolicyForRequest:request
1673 dataSource:oldDataSource
1676 withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1678 // must grab this now, since this load may stop the previous load and clear this flag
1679 BOOL isRedirect = _private->quickRedirectComing;
1680 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1682 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1683 _private->quickRedirectComing = NO;
1684 [[self provisionalDataSource] _setIsClientRedirect:YES];
1685 } else if (sameURL) {
1686 // Example of this case are sites that reload the same URL with a different cookie
1687 // driving the generated content, or a master frame with links that drive a target
1688 // frame, where the user has clicked on the same link repeatedly.
1689 [self _setLoadType:WebFrameLoadTypeSame];
1694 [oldDataSource release];
1695 [formState release];
1698 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1700 WebHistoryItem *parentItem = [_private currentItem];
1701 NSArray *childItems = [parentItem children];
1702 WebFrameLoadType loadType = [self _loadType];
1703 WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1704 WebHistoryItem *childItem = nil;
1706 // If we're moving in the backforward list, we might want to replace the content
1707 // of this child frame with whatever was there at that point.
1708 // Reload will maintain the frame contents, LoadSame will not.
1710 (loadType == WebFrameLoadTypeForward
1711 || loadType == WebFrameLoadTypeBack
1712 || loadType == WebFrameLoadTypeIndexedBackForward
1713 || loadType == WebFrameLoadTypeReload
1714 || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1716 childItem = [parentItem childItemWithName:[childFrame name]];
1718 // Use the original URL to ensure we get all the side-effects, such as
1719 // onLoad handlers, of any redirects that happened. An example of where
1720 // this is needed is Radar 3213556.
1721 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1722 // These behaviors implied by these loadTypes should apply to the child frames
1723 childLoadType = loadType;
1725 if (loadType == WebFrameLoadTypeForward
1726 || loadType == WebFrameLoadTypeBack
1727 || loadType == WebFrameLoadTypeIndexedBackForward)
1729 // For back/forward, remember this item so we can traverse any child items as child frames load
1730 [childFrame->_private setProvisionalItem:childItem];
1732 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1733 [childFrame->_private setCurrentItem:childItem];
1738 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1740 [childFrame loadArchive:archive];
1742 [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1746 - (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
1748 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1749 // This prevents a potential bug which may cause a page with a form that uses itself
1750 // as an action to be returned from the cache without submitting.
1752 // FIXME: Where's the code that implements what the comment above says?
1754 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1755 [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1756 [request _web_setHTTPReferrer:referrer];
1757 [request setHTTPMethod:@"POST"];
1758 webSetHTTPBody(request, postData);
1759 [request _web_setHTTPContentType:contentType];
1761 NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1762 WebFormState *formState = nil;
1763 if (form && values) {
1764 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1767 if (target != nil) {
1768 WebFrame *targetFrame = [self findFrameNamed:target];
1770 if (targetFrame != nil) {
1771 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1773 [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1776 [formState release];
1780 [_private->frameLoader _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1783 [formState release];
1786 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
1788 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
1790 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1791 willPerformClientRedirectToURL:URL
1796 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1797 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1798 _private->sentRedirectNotification = YES;
1800 // If a "quick" redirect comes in an, we set a special mode so we treat the next
1801 // load as part of the same navigation.
1803 if (![self dataSource] || isJavaScriptFormAction) {
1804 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
1805 // so we better just treat the redirect as a normal load.
1806 _private->quickRedirectComing = NO;
1807 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1809 _private->quickRedirectComing = lockHistory;
1810 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1814 - (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
1816 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1817 // the redirect succeeded. We should either rename this API, or add a new method, like
1818 // -webView:didFinishClientRedirectForFrame:
1819 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1820 didCancelClientRedirectForFrame:self];
1821 if (!cancelWithLoadInProgress)
1822 _private->quickRedirectComing = NO;
1824 _private->sentRedirectNotification = NO;
1826 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1829 - (void)_setTitle:(NSString *)title
1831 [[_private currentItem] setTitle:title];
1834 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1837 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1838 NSView *parent = [docView superview];
1839 // we might already be detached when this is called from detachFromParent, in which
1840 // case we don't want to override real data earlier gathered with (0,0)
1843 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1844 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1845 // ScrollView instead of using the one provided by the WebFrame
1846 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1847 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1849 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1850 ASSERT([parent isKindOfClass:[NSClipView class]]);
1851 point = [parent bounds].origin;
1853 [item setScrollPoint:point];
1859 There is a race condition between the layout and load completion that affects restoring the scroll position.
1860 We try to restore the scroll position at both the first layout and upon load completion.
1862 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1863 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1864 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
1865 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1866 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1867 fails. We then successfully restore it when the layout happens.
1870 - (void)_restoreScrollPositionAndViewState
1872 ASSERT([_private currentItem]);
1873 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1874 NSPoint point = [[_private currentItem] scrollPoint];
1875 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1876 id state = [[_private currentItem] viewState];
1878 [(id <_WebDocumentViewState>)docView setViewState:state];
1881 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1883 [docView scrollPoint:point];
1887 - (void)_defersCallbacksChanged
1889 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1890 [frame->_private->frameLoader defersCallbacksChanged];
1893 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1895 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1896 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1899 - (void)_viewDidMoveToHostWindow
1901 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1902 [[[frame frameView] documentView] viewDidMoveToHostWindow];
1905 - (void)_addChild:(WebFrame *)child
1907 [[self _bridge] appendChild:[child _bridge]];
1908 [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];
1911 - (void)_resetBackForwardList
1913 // Note this doesn't verify the current load type as a b/f operation because it is called from
1914 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1915 ASSERT(self == [[self webView] mainFrame]);
1916 WebHistoryItem *resetItem = [_private currentItem];
1918 [[[self webView] backForwardList] goToItem:resetItem];
1921 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1922 // item, because we optimistically move it right away at the start of the operation. But when
1923 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1924 // Return the item that we would reset to, so we can decide later whether to actually reset.
1925 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1927 WebFrameLoadType loadType = [self _loadType];
1928 if ((loadType == WebFrameLoadTypeForward
1929 || loadType == WebFrameLoadTypeBack
1930 || loadType == WebFrameLoadTypeIndexedBackForward)
1931 && self == [[self webView] mainFrame]) {
1932 return [_private currentItem];
1937 - (WebHistoryItem *)_itemForSavingDocState
1939 // For a standard page load, we will have a previous item set, which will be used to
1940 // store the form state. However, in some cases we will have no previous item, and
1941 // the current item is the right place to save the state. One example is when we
1942 // detach a bunch of frames because we are navigating from a site with frames to
1943 // another site. Another is when saving the frame state of a frame that is not the
1944 // target of the current navigation (if we even decide to save with that granularity).
1946 // Because of previousItem's "masking" of currentItem for this purpose, it's important
1947 // that previousItem be cleared at the end of a page transition. We leverage the
1948 // checkLoadComplete recursion to achieve this goal.
1950 WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
1954 - (WebHistoryItem *)_itemForRestoringDocState
1956 switch ([self _loadType]) {
1957 case WebFrameLoadTypeReload:
1958 case WebFrameLoadTypeReloadAllowingStaleData:
1959 case WebFrameLoadTypeSame:
1960 case WebFrameLoadTypeReplace:
1961 // Don't restore any form state on reload or loadSame
1963 case WebFrameLoadTypeBack:
1964 case WebFrameLoadTypeForward:
1965 case WebFrameLoadTypeIndexedBackForward:
1966 case WebFrameLoadTypeInternal:
1967 case WebFrameLoadTypeStandard:
1968 return [_private currentItem];
1970 ASSERT_NOT_REACHED();
1974 // Walk the frame tree, telling all frames to save their form state into their current
1976 - (void)_saveDocumentAndScrollState
1978 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1979 [[frame _bridge] saveDocumentState];
1980 [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
1984 // Called after the FormsDelegate is done processing willSubmitForm:
1985 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
1987 if (_private->listener) {
1988 [_private->listener _invalidate];
1989 [_private->listener release];
1990 _private->listener = nil;
1992 [_private->frameLoader startLoading];
1995 - (void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1997 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1998 // nil _private->policyDataSource because loading the alternate page will have passed
1999 // through this method already, nested; otherwise, _private->policyDataSource should still be set.
2000 ASSERT([self _policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
2002 WebHistoryItem *item = [_private provisionalItem];
2004 // Two reasons we can't continue:
2005 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
2006 // is the user responding Cancel to the form repost nag sheet.
2007 // 2) User responded Cancel to an alert popped up by the before unload event handler.
2008 // The "before unload" event handler runs only for the main frame.
2009 BOOL canContinue = request && ([[self webView] mainFrame] != self || [_private->bridge shouldClose]);
2012 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
2013 // need to report that the client redirect was cancelled.
2014 if (_private->quickRedirectComing)
2015 [self _clientRedirectCancelledOrFinished:NO];
2017 [_private->frameLoader _setPolicyDocumentLoadState:nil];
2018 // If the navigation request came from the back/forward menu, and we punt on it, we have the
2019 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
2020 // we only do this when punting a navigation for the target frame or top-level frame.
2021 if (([item isTargetItem] || [[self webView] mainFrame] == self)
2022 && (_private->policyLoadType == WebFrameLoadTypeForward
2023 || _private->policyLoadType == WebFrameLoadTypeBack
2024 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward))
2025 [[[self webView] mainFrame] _resetBackForwardList];
2029 WebFrameLoadType loadType = _private->policyLoadType;
2030 WebDataSource *dataSource = [[self _policyDataSource] retain];
2033 [self _setLoadType:loadType];
2035 [_private->frameLoader startProvisionalLoad:dataSource];
2037 [dataSource release];
2038 [_private->frameLoader _setPolicyDocumentLoadState:nil];
2041 if (self == [[self webView] mainFrame])
2042 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2044 if ((loadType == WebFrameLoadTypeForward ||
2045 loadType == WebFrameLoadTypeBack ||
2046 loadType == WebFrameLoadTypeIndexedBackForward) &&
2047 [item hasPageCache]){
2048 NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2049 if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2050 LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2051 [[_private->frameLoader provisionalDataSource] _loadFromPageCache:pageCache];
2057 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2058 // mechanism across the willSubmitForm callout.
2059 _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2060 [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2063 [self _continueAfterWillSubmitForm:WebPolicyUse];
2067 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2069 ASSERT([self webView] != nil);
2071 // Unfortunately the view must be non-nil, this is ultimately due
2072 // to parser requiring a FrameView. We should fix this dependency.
2074 ASSERT([self frameView] != nil);
2076 _private->policyLoadType = loadType;
2078 WebFrame *parentFrame = [self parentFrame];
2080 [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2082 WebDocumentLoadStateMac *loadState = (WebDocumentLoadStateMac *)[newDataSource _documentLoadState];
2083 [loadState setFrameLoader:_private->frameLoader];
2084 [loadState setDataSource:newDataSource];
2086 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2088 [_private->frameLoader _setPolicyDocumentLoadState:[newDataSource _documentLoadState]];
2090 [self _checkNavigationPolicyForRequest:[newDataSource request]
2091 dataSource:newDataSource
2094 withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2097 // used to decide to use loadType=Same
2098 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2100 WebHistoryItem *item = [_private currentItem];
2101 NSString* URLString = [URL _web_originalDataAsString];
2102 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2105 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2107 if (frameName == nil) {
2108 [self loadRequest:request];
2112 WebFrame *frame = [self findFrameNamed:frameName];
2115 [frame loadRequest:request];
2119 NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2120 [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2123 // Return next frame to be traversed, visiting children after parent
2124 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2126 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
2129 // Return previous frame to be traversed, exact reverse order of _nextFrame
2130 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2132 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
2135 - (void)_setShouldCreateRenderers:(BOOL)f
2137 [_private->bridge setShouldCreateRenderers:f];
2140 - (BOOL)_shouldCreateRenderers
2142 return [_private->bridge shouldCreateRenderers];
2145 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2148 return [[self _bridge] numPendingOrLoadingRequests];
2151 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2152 num += [[frame _bridge] numPendingOrLoadingRequests];
2157 - (NSColor *)_bodyBackgroundColor
2159 return [_private->bridge bodyBackgroundColor];
2162 - (void)_reloadForPluginChanges
2164 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2165 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2166 if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
2171 - (void)_attachScriptDebugger
2173 if (!_private->scriptDebugger)
2174 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
2177 - (void)_detachScriptDebugger
2179 if (_private->scriptDebugger) {
2180 id old = _private->scriptDebugger;
2181 _private->scriptDebugger = nil;
2186 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
2188 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2189 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2190 if ([documentView isKindOfClass:[WebHTMLView class]])
2191 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
2195 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
2197 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2198 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2199 if ([documentView isKindOfClass:[WebHTMLView class]])
2200 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
2204 - (BOOL)_firstLayoutDone
2206 return _private->firstLayoutDone;
2211 @implementation WebFrame (WebInternal)
2213 - (void)_didReceiveServerRedirectForProvisionalLoadForFrame
2215 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
2216 didReceiveServerRedirectForProvisionalLoadForFrame:self];
2219 - (WebDataSource *)_policyDataSource
2221 return [_private->frameLoader policyDataSource];
2224 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
2226 self = [super init];
2230 _private = [[WebFramePrivate alloc] init];
2232 _private->bridge = bridge;
2235 [_private setWebFrameView:fv];
2236 [fv _setWebFrame:self];
2239 _private->frameLoader = [[WebFrameLoader alloc] initWithWebFrame:self];
2246 - (NSArray *)_documentViews
2248 NSMutableArray *result = [NSMutableArray array];
2249 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2250 id docView = [[frame frameView] documentView];
2252 [result addObject:docView];
2258 - (void)_updateBackground
2260 BOOL drawsBackground = [[self webView] drawsBackground];
2261 NSColor *backgroundColor = [[self webView] backgroundColor];
2263 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2264 // Never call setDrawsBackground:YES here on the scroll view or the background color will
2265 // flash between pages loads. setDrawsBackground:YES will be called in WebFrame's _frameLoadCompleted.
2266 if (!drawsBackground)
2267 [[[frame frameView] _scrollView] setDrawsBackground:NO];
2268 [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
2269 id documentView = [[frame frameView] documentView];
2270 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
2271 [documentView setDrawsBackground:drawsBackground];
2272 if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
2273 [documentView setBackgroundColor:backgroundColor];
2274 [[frame _bridge] setDrawsBackground:drawsBackground];
2275 [[frame _bridge] setBaseBackgroundColor:backgroundColor];
2279 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2281 _private->internalLoadDelegate = internalLoadDelegate;
2284 - (id)_internalLoadDelegate
2286 return _private->internalLoadDelegate;
2289 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
2291 ASSERT(request != nil);
2293 WebView *wv = [self webView];
2294 id delegate = [wv resourceLoadDelegate];
2295 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2296 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2297 WebDataSource *dataSource = [self dataSource];
2299 if (implementations.delegateImplementsIdentifierForRequest) {
2300 *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2302 *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2305 NSURLRequest *newRequest;
2306 if (implementations.delegateImplementsWillSendRequest) {
2307 newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2309 newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2312 if (newRequest == nil) {
2313 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
2321 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
2323 WebView *wv = [self webView];
2324 id delegate = [wv resourceLoadDelegate];
2325 id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2326 WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2327 WebDataSource *dataSource = [self dataSource];
2329 if (response != nil) {
2330 if (implementations.delegateImplementsDidReceiveResponse) {
2331 [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2333 [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2338 if (implementations.delegateImplementsDidReceiveContentLength) {
2339 [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2341 [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2346 if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
2347 [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2349 [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2351 [self _checkLoadComplete];
2353 [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
2357 - (void)_safeLoadURL:(NSURL *)URL
2359 // Call the bridge because this is where our security checks are made.
2360 [[self _bridge] loadURL:URL
2361 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2365 triggeringEvent:[NSApp currentEvent]
2370 - (void)_unmarkAllMisspellings
2372 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2373 [[frame _bridge] unmarkAllMisspellings];
2376 - (void)_didFirstLayout
2378 if ([[self webView] backForwardList]) {
2379 WebFrameLoadType loadType = [self _loadType];
2380 if (loadType == WebFrameLoadTypeForward ||
2381 loadType == WebFrameLoadTypeBack ||
2382 loadType == WebFrameLoadTypeIndexedBackForward)
2384 [self _restoreScrollPositionAndViewState];
2388 _private->firstLayoutDone = YES;
2392 - (BOOL)_hasSelection
2394 id documentView = [[self frameView] documentView];
2396 // optimization for common case to avoid creating potentially large selection string
2397 if ([documentView isKindOfClass:[WebHTMLView class]]) {
2398 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
2399 return selectedDOMRange && ![selectedDOMRange collapsed];
2402 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2403 return [[documentView selectedString] length] > 0;
2408 - (void)_clearSelection
2410 id documentView = [[self frameView] documentView];
2411 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2412 [documentView deselectAll];
2417 - (BOOL)_atMostOneFrameHasSelection;
2419 // FIXME: 4186050 is one known case that makes this debug check fail
2421 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2422 if ([frame _hasSelection]) {
2433 - (WebFrame *)_findFrameWithSelection
2435 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2436 if ([frame _hasSelection])
2442 - (void)_clearSelectionInOtherFrames
2444 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
2445 // responder. It would be nicer to just notice first responder changes here instead, but there's no
2446 // notification sent when the first responder changes in general (Radar 2573089).
2447 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
2448 if (frameWithSelection != self)
2449 [frameWithSelection _clearSelection];
2451 // While we're in the general area of selection and frames, check that there is only one now.
2452 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
2455 - (void)_stopLoadingSubframes
2457 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2458 [child stopLoading];
2461 - (BOOL)_subframeIsLoading
2463 // It's most likely that the last added frame is the last to load so we walk backwards.
2464 for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
2465 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
2470 - (void)_addPlugInView:(NSView *)plugInView
2472 ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
2473 ASSERT(![_private->plugInViews containsObject:plugInView]);
2475 if (!_private->plugInViews)
2476 _private->plugInViews = [[NSMutableSet alloc] init];
2478 [plugInView setWebFrame:self];
2479 [_private->plugInViews addObject:plugInView];
2482 - (void)_removeAllPlugInViews
2484 if (!_private->plugInViews)
2487 [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
2488 [_private->plugInViews release];
2489 _private->plugInViews = nil;
2492 // This is called when leaving a page or closing the WebView
2493 - (void)_willCloseURL
2495 [self _removeAllPlugInViews];
2498 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2500 [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
2502 if (_private->loadType == WebFrameLoadTypeReload)
2503 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2505 // Don't set the cookie policy URL if it's already been set.
2506 if ([request mainDocumentURL] == nil) {
2507 if (mainResource && (self == [[self webView] mainFrame] || f))
2508 [request setMainDocumentURL:[request URL]];
2510 [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
2514 [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"];
2517 - (BOOL)_isMainFrame
2519 return self == [[self webView] mainFrame];
2522 - (void)_addInspector:(WebInspector *)inspector
2524 if (!_private->inspectors)
2525 _private->inspectors = [[NSMutableSet alloc] init];
2526 ASSERT(![_private->inspectors containsObject:inspector]);
2527 [_private->inspectors addObject:inspector];
2530 - (void)_removeInspector:(WebInspector *)inspector
2532 ASSERT([_private->inspectors containsObject:inspector]);
2533 [_private->inspectors removeObject:inspector];
2536 - (WebFrameLoader *)_frameLoader
2538 return _private->frameLoader;
2541 - (void)_provisionalLoadStarted
2543 _private->firstLayoutDone = NO;
2544 [_private->bridge provisionalLoadStarted];
2546 // FIXME: This is OK as long as no one resizes the window,
2547 // but in the case where someone does, it means garbage outside
2548 // the occupied part of the scroll view.
2549 [[[self frameView] _scrollView] setDrawsBackground:NO];
2551 // Cache the page, if possible.
2552 // Don't write to the cache if in the middle of a redirect, since we will want to
2553 // store the final page we end up on.
2554 // No point writing to the cache on a reload or loadSame, since we will just write
2555 // over it again when we leave that page.
2556 WebHistoryItem *item = [_private currentItem];
2557 WebFrameLoadType loadType = [self _loadType];
2558 if ([self _canCachePage]
2559 && [_private->bridge canCachePage]
2561 && !_private->quickRedirectComing
2562 && loadType != WebFrameLoadTypeReload
2563 && loadType != WebFrameLoadTypeReloadAllowingStaleData
2564 && loadType != WebFrameLoadTypeSame
2565 && ![[self dataSource] isLoading]
2566 && ![[_private->frameLoader documentLoadState] isStopping]) {
2567 if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
2568 if (![item pageCache]){
2570 // Add the items to this page's cache.
2571 if ([self _createPageCacheForItem:item]) {
2572 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2574 // See if any page caches need to be purged after the addition of this
2576 [self _purgePageCache];
2579 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
2582 // Put the document into a null state, so it can be restored correctly.
2583 [_private->bridge clear];
2585 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2588 - (void)_prepareForDataSourceReplacement
2590 if (![_private->frameLoader dataSource]) {
2591 ASSERT(![self _childFrameCount]);
2595 // Make sure that any work that is triggered by resigning first reponder can get done.
2596 // The main example where this came up is the textDidEndEditing that is sent to the
2597 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
2598 // remove the views as a side-effect of freeing the bridge, at which point we can't
2599 // post the FormDelegate messages.
2601 // Note that this can also take FirstResponder away from a child of our frameView that
2602 // is not in a child frame's view. This is OK because we are in the process
2603 // of loading new content, which will blow away all editors in this top frame, and if
2604 // a non-editor is firstReponder it will not be affected by endEditingFor:.
2605 // Potentially one day someone could write a DocView whose editors were not all
2606 // replaced by loading new content, but that does not apply currently.
2607 NSView *frameView = [self frameView];
2608 NSWindow *window = [frameView window];
2609 NSResponder *firstResp = [window firstResponder];
2610 if ([firstResp isKindOfClass:[NSView class]]
2611 && [(NSView *)firstResp isDescendantOf:frameView])
2613 [window endEditingFor:firstResp];
2616 [self _detachChildren];
2619 - (void)_frameLoadCompleted
2621 NSScrollView *sv = [[self frameView] _scrollView];
2622 if ([[self webView] drawsBackground])
2623 [sv setDrawsBackground:YES];
2624 [_private setPreviousItem:nil];
2625 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
2626 if ([_private->frameLoader dataSource])
2627 _private->firstLayoutDone = YES;
2630 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
2632 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
2633 if (unreachableURL == nil) {
2637 if (_private->policyLoadType != WebFrameLoadTypeForward
2638 && _private->policyLoadType != WebFrameLoadTypeBack
2639 && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
2643 // We only treat unreachableURLs specially during the delegate callbacks
2644 // for provisional load errors and navigation policy decisions. The former
2645 // case handles well-formed URLs that can't be loaded, and the latter
2646 // case handles malformed URLs and unknown schemes. Loading alternate content
2647 // at other times behaves like a standard load.
2648 WebDataSource *compareDataSource = nil;
2649 if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
2650 compareDataSource = [self _policyDataSource];
2651 } else if (_private->delegateIsHandlingProvisionalLoadError) {
2652 compareDataSource = [self provisionalDataSource];
2655 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
2658 - (WebDataSource *)_dataSourceForDocumentLoadState:(WebDocumentLoadState *)loadState
2660 return [(WebDocumentLoadStateMac *)loadState dataSource];
2663 - (WebDocumentLoadState *)_createDocumentLoadStateWithRequest:(NSURLRequest *)request
2665 WebDocumentLoadStateMac *loadState = [[WebDocumentLoadStateMac alloc] initWithRequest:request];
2667 WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoadState:loadState];
2668 [loadState setDataSource:dataSource];
2669 [dataSource release];
2676 @implementation WebFormState : NSObject
2678 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2680 self = [super init];
2684 _form = [form retain];
2685 _values = [values copy];
2686 _sourceFrame = [sourceFrame retain];
2694 [_sourceFrame release];
2698 - (DOMElement *)form
2703 - (NSDictionary *)values
2708 - (WebFrame *)sourceFrame
2710 return _sourceFrame;
2715 @implementation WebFrame
2719 return [self initWithName:nil webFrameView:nil webView:nil];
2722 // FIXME: this method can't work any more and should be marked deprecated
2723 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2725 return [self _initWithWebFrameView:fv webView:v bridge:nil];
2730 ASSERT(_private->bridge == nil);
2740 ASSERT(_private->bridge == nil);
2749 return [[self _bridge] name];
2752 - (WebFrameView *)frameView
2754 return [_private webFrameView];
2757 - (WebView *)webView
2759 return [[[self _bridge] page] webView];
2762 - (DOMDocument *)DOMDocument
2764 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2767 - (DOMHTMLElement *)frameElement
2769 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2772 - (WebDataSource *)provisionalDataSource
2774 return [_private->frameLoader provisionalDataSource];
2777 - (WebDataSource *)dataSource
2779 return [_private->frameLoader dataSource];
2782 - (void)loadRequest:(NSURLRequest *)request
2784 // FIXME: is this the right place to reset loadType? Perhaps, this should be done
2785 // after loading is finished or aborted.
2786 _private->loadType = WebFrameLoadTypeStandard;
2788 [_private->frameLoader _loadRequest:request archive:nil];
2791 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2793 NSURLRequest *request = [self _webDataRequestForData:data
2795 textEncodingName:encodingName
2797 unreachableURL:unreachableURL];
2798 [self loadRequest:request];
2802 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2804 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2807 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2809 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
2810 [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
2813 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2815 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2818 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2820 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2823 - (void)loadArchive:(WebArchive *)archive
2825 WebResource *mainResource = [archive mainResource];
2827 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
2828 MIMEType:[mainResource MIMEType]
2829 textEncodingName:[mainResource textEncodingName]
2830 baseURL:[mainResource URL]
2831 unreachableURL:nil];
2832 [_private->frameLoader _loadRequest:request archive:archive];
2838 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2839 if (_private->isStoppingLoad)
2842 _private->isStoppingLoad = YES;
2844 [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2846 [self _stopLoadingSubframes];
2847 [_private->frameLoader stopLoading];
2849 _private->isStoppingLoad = NO;
2854 [_private->frameLoader reload];
2857 - (WebFrame *)findFrameNamed:(NSString *)name
2859 return Frame([[self _bridge] findFrameNamed:name]);
2862 - (WebFrame *)parentFrame
2864 return [[Frame([[self _bridge] parent]) retain] autorelease];
2867 - (NSArray *)childFrames
2869 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2870 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2871 [children addObject:child];