2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #import "WebFrameInternal.h"
31 #import "WebArchive.h"
32 #import "WebBackForwardList.h"
33 #import "WebDataProtocol.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultResourceLoadDelegate.h"
36 #import "WebDefaultUIDelegate.h"
37 #import "WebDocumentInternal.h"
38 #import "WebDocumentLoaderMac.h"
39 #import "WebDownloadInternal.h"
40 #import "WebFormDataStream.h"
41 #import "WebFrameBridge.h"
42 #import "WebFrameLoadDelegate.h"
43 #import "WebFrameLoader.h"
44 #import "WebFrameViewInternal.h"
45 #import "WebHTMLRepresentationPrivate.h"
46 #import "WebHTMLViewInternal.h"
47 #import "WebHTMLViewPrivate.h"
48 #import "WebHistoryItemPrivate.h"
49 #import "WebHistoryPrivate.h"
50 #import "WebKitErrorsPrivate.h"
51 #import "WebKitLogging.h"
52 #import "WebKitNSStringExtras.h"
53 #import "WebKitStatisticsPrivate.h"
54 #import "WebNSObjectExtras.h"
55 #import "WebNSURLExtras.h"
56 #import "WebNSURLRequestExtras.h"
57 #import "WebNetscapePluginEmbeddedView.h"
58 #import "WebNullPluginView.h"
60 #import "WebPluginController.h"
61 #import "WebPreferencesPrivate.h"
62 #import "WebResourceLoadDelegate.h"
63 #import "WebResourcePrivate.h"
64 #import "WebScriptDebugDelegatePrivate.h"
65 #import "WebUIDelegate.h"
66 #import "WebViewInternal.h"
67 #import <WebKit/DOM.h>
68 #import <WebKitSystemInterface.h>
69 #import <objc/objc-runtime.h>
72 Here is the current behavior matrix for four types of navigations:
76 Restore form state: YES
77 Restore scroll and focus state: YES
78 WF Cache policy: NSURLRequestUseProtocolCachePolicy
79 Add to back/forward list: YES
83 Restore form state: YES
84 Restore scroll and focus state: YES
85 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
86 Add to back/forward list: NO
88 Reload (meaning only the reload button):
90 Restore form state: NO
91 Restore scroll and focus state: YES
92 WF Cache policy: NSURLRequestReloadIgnoringCacheData
93 Add to back/forward list: NO
95 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
97 Restore form state: NO
98 Restore scroll and focus state: NO, reset to initial conditions
99 WF Cache policy: NSURLRequestReloadIgnoringCacheData
100 Add to back/forward list: NO
103 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
104 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
105 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
107 @interface WebFrame (ForwardDecls)
108 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
109 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
110 - (WebHistoryItem *)_createItem:(BOOL)useOriginal;
111 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
112 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
115 @interface NSView (WebFramePluginHosting)
116 - (void)setWebFrame:(WebFrame *)webFrame;
119 @interface WebFramePrivate : NSObject
122 WebFrameView *webFrameView;
124 WebFrameBridge *bridge;
125 WebHistoryItem *currentItem; // BF item for our current content
126 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
127 // (only known when navigating to a pre-existing BF item)
128 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
130 WebScriptDebugger *scriptDebugger;
131 id internalLoadDelegate;
133 NSMutableSet *plugInViews;
134 NSMutableSet *inspectors;
137 - (void)setWebFrameView:(WebFrameView *)v;
139 - (void)setProvisionalItem:(WebHistoryItem *)item;
140 - (void)setPreviousItem:(WebHistoryItem *)item;
141 - (void)setCurrentItem:(WebHistoryItem *)item;
145 @implementation WebFramePrivate
149 [webFrameView release];
151 [currentItem release];
152 [provisionalItem release];
153 [previousItem release];
155 [scriptDebugger release];
157 [inspectors release];
159 ASSERT(plugInViews == nil);
164 - (void)setWebFrameView:(WebFrameView *)v
167 [webFrameView release];
171 - (void)setProvisionalItem:(WebHistoryItem *)item
174 [provisionalItem release];
175 provisionalItem = item;
178 - (void)setPreviousItem:(WebHistoryItem *)item
181 [previousItem release];
185 - (void)setCurrentItem:(WebHistoryItem *)item
188 [currentItem release];
194 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
196 return [(WebFrameBridge *)bridge webFrame];
199 @implementation WebFrame (FrameTraversal)
201 - (WebFrame *)_firstChildFrame
203 return Frame([[self _bridge] firstChild]);
206 - (WebFrame *)_lastChildFrame
208 return Frame([[self _bridge] lastChild]);
211 - (unsigned)_childFrameCount
213 return [[self _bridge] childCount];
216 - (WebFrame *)_previousSiblingFrame;
218 return Frame([[self _bridge] previousSibling]);
221 - (WebFrame *)_nextSiblingFrame;
223 return Frame([[self _bridge] nextSibling]);
226 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
228 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
233 @implementation WebFrame (WebInternal)
235 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
237 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
238 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
239 [request _webDataRequestSetData:data];
240 [request _webDataRequestSetEncoding:encodingName];
241 [request _webDataRequestSetBaseURL:URL];
242 [request _webDataRequestSetUnreachableURL:unreachableURL];
243 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
247 // helper method used in various nav cases below
248 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
250 if ([[self dataSource] _URLForHistory] != nil) {
251 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
252 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
253 [[[self webView] backForwardList] addItem:bfItem];
257 - (void)_addHistoryItemForFragmentScroll
259 [self _addBackForwardItemClippedAtTarget:NO];
262 - (void)_didFinishLoad
264 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
267 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
269 WebDataSource *dataSrc = [self dataSource];
270 NSURLRequest *request;
271 NSURL *unreachableURL = [dataSrc unreachableURL];
274 WebHistoryItem *bfItem;
277 request = [[dataSrc _documentLoader] originalRequestCopy];
279 request = [dataSrc request];
281 if (unreachableURL != nil) {
282 URL = unreachableURL;
283 originalURL = unreachableURL;
286 originalURL = [[[dataSrc _documentLoader] originalRequestCopy] URL];
289 LOG (History, "creating item for %@", request);
291 // Frames that have never successfully loaded any content
292 // may have no URL at all. Currently our history code can't
293 // deal with such things, so we nip that in the bud here.
294 // Later we may want to learn to live with nil for URL.
295 // See bug 3368236 and related bugs for more information.
297 URL = [NSURL URLWithString:@"about:blank"];
299 if (originalURL == nil) {
300 originalURL = [NSURL URLWithString:@"about:blank"];
303 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
304 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
306 // save form state if this is a POST
307 [bfItem _setFormInfoFromRequest:request];
309 // Set the item for which we will save document state
310 [_private setPreviousItem:_private->currentItem];
311 [_private setCurrentItem:bfItem];
317 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
318 The item that was the target of the user's navigation is designated as the "targetItem".
319 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
320 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
322 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
324 WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
326 [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
327 if (!(doClip && self == targetFrame)) {
328 // save frame state for items that aren't loading (khtml doesn't save those)
329 [_private->bridge saveDocumentState];
331 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
332 [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
334 if (self == targetFrame)
335 [bfItem setIsTargetItem:YES];
340 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
342 return Frame([[self _bridge] childFrameNamed:name]);
345 - (BOOL)_canCachePage
347 return [[[self webView] backForwardList] _usesPageCache];
350 - (void)_purgePageCache
352 // This method implements the rule for purging the page cache.
353 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
354 unsigned pagesCached = 0;
355 WebBackForwardList *backForwardList = [[self webView] backForwardList];
356 NSArray *backList = [backForwardList backListWithLimit: 999999];
357 WebHistoryItem *oldestNonSnapbackItem = nil;
360 for (i = 0; i < [backList count]; i++){
361 WebHistoryItem *item = [backList objectAtIndex: i];
362 if ([item hasPageCache]){
363 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
364 oldestNonSnapbackItem = item;
369 // Snapback items are never directly purged here.
370 if (pagesCached >= sizeLimit) {
371 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
372 [oldestNonSnapbackItem setHasPageCache:NO];
376 + (CFAbsoluteTime)_timeOfLastCompletedLoad
378 return [WebFrameLoader timeOfLastCompletedLoad];
381 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
383 NSMutableDictionary *pageCache;
385 [item setHasPageCache: YES];
387 if (![_private->bridge saveDocumentToPageCache]){
388 [item setHasPageCache: NO];
392 pageCache = [item pageCache];
393 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
394 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
395 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
400 - (void)_provisionalLoadStarted
402 FrameLoadType loadType = [[self _frameLoader] loadType];
404 // FIXME: This is OK as long as no one resizes the window,
405 // but in the case where someone does, it means garbage outside
406 // the occupied part of the scroll view.
407 [[[self frameView] _scrollView] setDrawsBackground:NO];
409 // Cache the page, if possible.
410 // Don't write to the cache if in the middle of a redirect, since we will want to
411 // store the final page we end up on.
412 // No point writing to the cache on a reload or loadSame, since we will just write
413 // over it again when we leave that page.
414 WebHistoryItem *item = _private->currentItem;
415 if ([self _canCachePage]
416 && [_private->bridge canCachePage]
418 && ![[self _frameLoader] isQuickRedirectComing]
419 && loadType != FrameLoadTypeReload
420 && loadType != FrameLoadTypeReloadAllowingStaleData
421 && loadType != FrameLoadTypeSame
422 && ![[self dataSource] isLoading]
423 && ![[[self _frameLoader] documentLoader] isStopping]) {
424 if ([[[self dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]) {
425 if (![item pageCache]){
426 // Add the items to this page's cache.
427 if ([self _createPageCacheForItem:item]) {
428 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
430 // See if any page caches need to be purged after the addition of this
432 [self _purgePageCache];
435 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
438 // Put the document into a null state, so it can be restored correctly.
439 [_private->bridge clear];
441 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
444 - (WebFrameBridge *)_bridge
446 return _private->bridge;
449 // helper method that determines whether the subframes described by the item's subitems
450 // match our own current frameset
451 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
453 NSArray *childItems = [item children];
454 int numChildItems = [childItems count];
455 int numChildFrames = [self _childFrameCount];
456 if (numChildFrames != numChildItems)
460 for (i = 0; i < numChildItems; i++) {
461 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
462 //Search recursive here?
463 if (![self _immediateChildFrameNamed:itemTargetName])
464 return NO; // couldn't match the i'th itemTarget
467 return YES; // found matches for all itemTargets
470 // Walk the frame tree and ensure that the URLs match the URLs in the item.
471 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
473 NSURL *currentURL = [[[self dataSource] request] URL];
475 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
478 NSArray *childItems = [item children];
479 WebHistoryItem *childItem;
480 WebFrame *childFrame;
481 int i, count = [childItems count];
482 for (i = 0; i < count; i++){
483 childItem = [childItems objectAtIndex:i];
484 childFrame = [self _immediateChildFrameNamed:[childItem target]];
485 if (![childFrame _URLsMatchItem: childItem])
492 // loads content into this frame, as specified by item
493 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)loadType
495 NSURL *itemURL = [item URL];
496 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
497 NSURL *currentURL = [[[self dataSource] request] URL];
498 NSArray *formData = [item formData];
500 // Are we navigating to an anchor within the page?
501 // Note if we have child frames we do a real reload, since the child frames might not
502 // match our current frame structure, or they might not have the right content. We could
503 // check for all that as an additional optimization.
504 // We also do not do anchor-style navigation if we're posting a form.
506 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
507 // Perhaps they should.
508 if (!formData && ![[self _frameLoader] shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
511 // FIXME: We need to normalize the code paths for anchor navigation. Something
512 // like the following line of code should be done, but also accounting for correct
513 // updates to the back/forward list and scroll position.
514 // rjw 4/9/03 See 3223929.
515 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
517 // must do this maintenance here, since we don't go through a real page reload
518 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
519 // FIXME: form state might want to be saved here too
521 // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
522 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
523 [_private->bridge scrollToAnchorWithURL:[item URL]];
525 // must do this maintenance here, since we don't go through a real page reload
526 [_private setCurrentItem:item];
527 [self _restoreScrollPositionAndViewState];
529 // Fake the URL change by updating the data source's request. This will no longer
530 // be necessary if we do the better fix described above.
531 [[[self _frameLoader] documentLoader] replaceRequestURLForAnchorScrollWithURL:itemURL];
533 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
534 didChangeLocationWithinPageForFrame:self];
535 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
537 // Remember this item so we can traverse any child items as child frames load
538 [_private setProvisionalItem:item];
540 WebDataSource *newDataSource;
541 BOOL inPageCache = NO;
543 // Check if we'll be using the page cache. We only use the page cache
544 // if one exists and it is less than _backForwardCacheExpirationInterval
545 // seconds old. If the cache is expired it gets flushed here.
546 if ([item hasPageCache]){
547 NSDictionary *pageCache = [item pageCache];
548 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
549 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
550 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]) {
551 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
552 [[self _frameLoader] loadDataSource:newDataSource withLoadType:loadType formState:nil];
555 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]);
556 [item setHasPageCache: NO];
561 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
562 [[self _frameLoader] addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
564 // If this was a repost that failed the page cache, we might try to repost the form.
565 NSDictionary *action;
567 [request setHTTPMethod:@"POST"];
568 [request _web_setHTTPReferrer:[item formReferrer]];
569 webSetHTTPBody(request, formData);
570 [request _web_setHTTPContentType:[item formContentType]];
572 // Slight hack to test if the WF cache contains the page we're going to. We want
573 // to know this before talking to the policy delegate, since it affects whether we
574 // show the DoYouReallyWantToRepost nag.
576 // This trick has a small bug (3123893) where we might find a cache hit, but then
577 // have the item vanish when we try to use it in the ensuing nav. This should be
578 // extremely rare, but in that case the user will get an error on the navigation.
579 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
580 NSURLResponse *synchResponse = nil;
581 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
582 if (synchResponse == nil) {
584 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
585 action = [[self _frameLoader] actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
587 // We can use the cache, don't use navType=resubmit
588 action = [[self _frameLoader] actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
592 case FrameLoadTypeReload:
593 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
595 case FrameLoadTypeBack:
596 case FrameLoadTypeForward:
597 case FrameLoadTypeIndexedBackForward:
598 if (![[itemURL scheme] isEqual:@"https"])
599 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
601 case FrameLoadTypeStandard:
602 case FrameLoadTypeInternal:
603 // no-op: leave as protocol default
604 // FIXME: I wonder if we ever hit this case
606 case FrameLoadTypeSame:
607 case FrameLoadTypeReloadAllowingStaleData:
609 ASSERT_NOT_REACHED();
612 action = [[self _frameLoader] actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
615 [[self _frameLoader] _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
621 // The general idea here is to traverse the frame tree and the item tree in parallel,
622 // tracking whether each frame already has the content the item requests. If there is
623 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
624 // reload that frame, and all its kids.
625 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(FrameLoadType)type
627 NSURL *itemURL = [item URL];
628 NSURL *currentURL = [[[self dataSource] request] URL];
630 // Always reload the target frame of the item we're going to. This ensures that we will
631 // do -some- load for the transition, which means a proper notification will be posted
633 // The exact URL has to match, including fragment. We want to go through the _load
634 // method, even if to do a within-page navigation.
635 // The current frame tree and the frame tree snapshot in the item have to match.
636 if (![item isTargetItem] &&
637 [itemURL isEqual:currentURL] &&
638 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
639 [self _childFramesMatchItem:item])
641 // This content is good, so leave it alone and look for children that need reloading
643 // Save form state (works from currentItem, since prevItem is nil)
644 ASSERT(!_private->previousItem);
645 [_private->bridge saveDocumentState];
646 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
648 [_private setCurrentItem:item];
650 // Restore form state (works from currentItem)
651 [_private->bridge restoreDocumentState];
652 // Restore the scroll position (taken in favor of going back to the anchor)
653 [self _restoreScrollPositionAndViewState];
655 NSArray *childItems = [item children];
656 int numChildItems = childItems ? [childItems count] : 0;
658 for (i = numChildItems - 1; i >= 0; i--) {
659 WebHistoryItem *childItem = [childItems objectAtIndex:i];
660 NSString *childName = [childItem target];
661 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
662 ASSERT(fromChildItem || [fromItem isTargetItem]);
663 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
665 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
668 // We need to reload the content
669 [self _loadItem:item withLoadType:type];
673 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
674 // This includes recursion to handle loading into framesets properly
675 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)type
677 ASSERT(![self parentFrame]);
678 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
679 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
680 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
681 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
682 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
683 WebBackForwardList *backForwardList = [[self webView] backForwardList];
684 WebHistoryItem *currItem = [backForwardList currentItem];
685 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
686 // - plus, it only makes sense for the top level of the operation through the frametree,
687 // as opposed to happening for some/one of the page commits that might happen soon
688 [backForwardList goToItem:item];
689 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
693 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
695 WebHistoryItem *parentItem = _private->currentItem;
696 NSArray *childItems = [parentItem children];
697 FrameLoadType loadType = [[self _frameLoader] loadType];
698 FrameLoadType childLoadType = FrameLoadTypeInternal;
699 WebHistoryItem *childItem = nil;
701 // If we're moving in the backforward list, we might want to replace the content
702 // of this child frame with whatever was there at that point.
703 // Reload will maintain the frame contents, LoadSame will not.
705 (isBackForwardLoadType(loadType)
706 || loadType == FrameLoadTypeReload
707 || loadType == FrameLoadTypeReloadAllowingStaleData))
709 childItem = [parentItem childItemWithName:[childFrame name]];
711 // Use the original URL to ensure we get all the side-effects, such as
712 // onLoad handlers, of any redirects that happened. An example of where
713 // this is needed is Radar 3213556.
714 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
715 // These behaviors implied by these loadTypes should apply to the child frames
716 childLoadType = loadType;
718 if (isBackForwardLoadType(loadType))
719 // For back/forward, remember this item so we can traverse any child items as child frames load
720 [childFrame->_private setProvisionalItem:childItem];
722 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
723 [childFrame->_private setCurrentItem:childItem];
727 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
729 [childFrame loadArchive:archive];
731 [[childFrame _frameLoader] loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
734 - (void)_setTitle:(NSString *)title forURL:(NSURL *)URL
736 [[[WebHistory optionalSharedHistory] itemForURL:URL] setTitle:title];
737 [_private->currentItem setTitle:title];
740 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
743 NSView <WebDocumentView> *docView = [[self frameView] documentView];
744 NSView *parent = [docView superview];
745 // we might already be detached when this is called from detachFromParent, in which
746 // case we don't want to override real data earlier gathered with (0,0)
749 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
750 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
751 // ScrollView instead of using the one provided by the WebFrame
752 point = [(id <_WebDocumentViewState>)docView scrollPoint];
753 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
755 // Parent is the clipview of the DynamicScrollView the WebFrame installs
756 ASSERT([parent isKindOfClass:[NSClipView class]]);
757 point = [parent bounds].origin;
759 [item setScrollPoint:point];
764 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
766 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
767 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
770 - (void)_viewDidMoveToHostWindow
772 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
773 [[[frame frameView] documentView] viewDidMoveToHostWindow];
776 - (void)_addChild:(WebFrame *)child
778 [[self _bridge] appendChild:[child _bridge]];
779 [[[child dataSource] _documentLoader] setOverrideEncoding:[[[self dataSource] _documentLoader] overrideEncoding]];
782 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
783 // item, because we optimistically move it right away at the start of the operation. But when
784 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
785 // Return the item that we would reset to, so we can decide later whether to actually reset.
786 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
788 if (isBackForwardLoadType([[self _frameLoader] loadType]) && self == [[self webView] mainFrame])
789 return _private->currentItem;
793 - (WebHistoryItem *)_itemForSavingDocState
795 // For a standard page load, we will have a previous item set, which will be used to
796 // store the form state. However, in some cases we will have no previous item, and
797 // the current item is the right place to save the state. One example is when we
798 // detach a bunch of frames because we are navigating from a site with frames to
799 // another site. Another is when saving the frame state of a frame that is not the
800 // target of the current navigation (if we even decide to save with that granularity).
802 // Because of previousItem's "masking" of currentItem for this purpose, it's important
803 // that previousItem be cleared at the end of a page transition. We leverage the
804 // checkLoadComplete recursion to achieve this goal.
806 return _private->previousItem ? _private->previousItem : _private->currentItem;
809 - (WebHistoryItem *)_itemForRestoringDocState
811 switch ([[self _frameLoader] loadType]) {
812 case FrameLoadTypeReload:
813 case FrameLoadTypeReloadAllowingStaleData:
814 case FrameLoadTypeSame:
815 case FrameLoadTypeReplace:
816 // Don't restore any form state on reload or loadSame
818 case FrameLoadTypeBack:
819 case FrameLoadTypeForward:
820 case FrameLoadTypeIndexedBackForward:
821 case FrameLoadTypeInternal:
822 case FrameLoadTypeStandard:
823 return _private->currentItem;
825 ASSERT_NOT_REACHED();
829 // Walk the frame tree, telling all frames to save their form state into their current
831 - (void)_saveDocumentAndScrollState
833 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
834 [[frame _bridge] saveDocumentState];
835 [frame _saveScrollPositionAndViewStateToItem:frame->_private->currentItem];
839 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
841 WebHistoryItem *item = _private->currentItem;
842 NSString* URLString = [URL _web_originalDataAsString];
843 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
846 // Return next frame to be traversed, visiting children after parent
847 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
849 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
852 // Return previous frame to be traversed, exact reverse order of _nextFrame
853 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
855 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
858 - (BOOL)_shouldCreateRenderers
860 return [_private->bridge shouldCreateRenderers];
863 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
866 return [[self _bridge] numPendingOrLoadingRequests];
869 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
870 num += [[frame _bridge] numPendingOrLoadingRequests];
875 - (void)_reloadForPluginChanges
877 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
878 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
879 if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
884 - (void)_attachScriptDebugger
886 if (!_private->scriptDebugger)
887 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
890 - (void)_detachScriptDebugger
892 if (_private->scriptDebugger) {
893 id old = _private->scriptDebugger;
894 _private->scriptDebugger = nil;
899 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
901 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
902 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
903 if ([documentView isKindOfClass:[WebHTMLView class]])
904 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
908 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
910 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
911 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
912 if ([documentView isKindOfClass:[WebHTMLView class]])
913 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
917 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
923 _private = [[WebFramePrivate alloc] init];
925 _private->bridge = bridge;
928 [_private setWebFrameView:fv];
929 [fv _setWebFrame:self];
937 - (NSArray *)_documentViews
939 NSMutableArray *result = [NSMutableArray array];
940 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
941 id docView = [[frame frameView] documentView];
943 [result addObject:docView];
949 - (void)_updateBackground
951 BOOL drawsBackground = [[self webView] drawsBackground];
952 NSColor *backgroundColor = [[self webView] backgroundColor];
954 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
955 // Never call setDrawsBackground:YES here on the scroll view or the background color will
956 // flash between pages loads. setDrawsBackground:YES will be called in _frameLoadCompleted.
957 if (!drawsBackground)
958 [[[frame frameView] _scrollView] setDrawsBackground:NO];
959 [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
960 id documentView = [[frame frameView] documentView];
961 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
962 [documentView setDrawsBackground:drawsBackground];
963 if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
964 [documentView setBackgroundColor:backgroundColor];
965 [[frame _bridge] setDrawsBackground:drawsBackground];
966 [[frame _bridge] setBaseBackgroundColor:backgroundColor];
970 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
972 _private->internalLoadDelegate = internalLoadDelegate;
975 - (id)_internalLoadDelegate
977 return _private->internalLoadDelegate;
980 - (void)_unmarkAllMisspellings
982 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
983 [[frame _bridge] unmarkAllMisspellings];
986 - (BOOL)_hasSelection
988 id documentView = [[self frameView] documentView];
990 // optimization for common case to avoid creating potentially large selection string
991 if ([documentView isKindOfClass:[WebHTMLView class]]) {
992 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
993 return selectedDOMRange && ![selectedDOMRange collapsed];
996 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
997 return [[documentView selectedString] length] > 0;
1002 - (void)_clearSelection
1004 id documentView = [[self frameView] documentView];
1005 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1006 [documentView deselectAll];
1011 - (BOOL)_atMostOneFrameHasSelection;
1013 // FIXME: 4186050 is one known case that makes this debug check fail
1015 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1016 if ([frame _hasSelection]) {
1027 - (WebFrame *)_findFrameWithSelection
1029 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1030 if ([frame _hasSelection])
1036 - (void)_clearSelectionInOtherFrames
1038 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
1039 // responder. It would be nicer to just notice first responder changes here instead, but there's no
1040 // notification sent when the first responder changes in general (Radar 2573089).
1041 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
1042 if (frameWithSelection != self)
1043 [frameWithSelection _clearSelection];
1045 // While we're in the general area of selection and frames, check that there is only one now.
1046 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
1049 - (void)_addPlugInView:(NSView *)plugInView
1051 ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
1052 ASSERT(![_private->plugInViews containsObject:plugInView]);
1054 if (!_private->plugInViews)
1055 _private->plugInViews = [[NSMutableSet alloc] init];
1057 [plugInView setWebFrame:self];
1058 [_private->plugInViews addObject:plugInView];
1061 - (void)_removeAllPlugInViews
1063 if (!_private->plugInViews)
1066 [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
1067 [_private->plugInViews release];
1068 _private->plugInViews = nil;
1071 // This is called when leaving a page or closing the WebView
1072 - (void)_willCloseURL
1074 [self _removeAllPlugInViews];
1077 - (BOOL)_isMainFrame
1079 return self == [[self webView] mainFrame];
1082 - (void)_addInspector:(WebInspector *)inspector
1084 if (!_private->inspectors)
1085 _private->inspectors = [[NSMutableSet alloc] init];
1086 ASSERT(![_private->inspectors containsObject:inspector]);
1087 [_private->inspectors addObject:inspector];
1090 - (void)_removeInspector:(WebInspector *)inspector
1092 ASSERT([_private->inspectors containsObject:inspector]);
1093 [_private->inspectors removeObject:inspector];
1096 - (WebFrameLoader *)_frameLoader
1098 return [_private->bridge frameLoader];
1101 - (void)_prepareForDataSourceReplacement
1103 if (![[self _frameLoader] dataSource]) {
1104 ASSERT(![self _childFrameCount]);
1108 // Make sure that any work that is triggered by resigning first reponder can get done.
1109 // The main example where this came up is the textDidEndEditing that is sent to the
1110 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
1111 // remove the views as a side-effect of freeing the bridge, at which point we can't
1112 // post the FormDelegate messages.
1114 // Note that this can also take FirstResponder away from a child of our frameView that
1115 // is not in a child frame's view. This is OK because we are in the process
1116 // of loading new content, which will blow away all editors in this top frame, and if
1117 // a non-editor is firstReponder it will not be affected by endEditingFor:.
1118 // Potentially one day someone could write a DocView whose editors were not all
1119 // replaced by loading new content, but that does not apply currently.
1120 NSView *frameView = [self frameView];
1121 NSWindow *window = [frameView window];
1122 NSResponder *firstResp = [window firstResponder];
1123 if ([firstResp isKindOfClass:[NSView class]]
1124 && [(NSView *)firstResp isDescendantOf:frameView])
1126 [window endEditingFor:firstResp];
1129 [[self _frameLoader] detachChildren];
1132 - (void)_frameLoadCompleted
1134 // Note: Can be called multiple times.
1135 // Even if already complete, we might have set a previous item on a frame that
1136 // didn't do any data loading on the past transaction. Make sure to clear these out.
1137 NSScrollView *sv = [[self frameView] _scrollView];
1138 if ([[self webView] drawsBackground])
1139 [sv setDrawsBackground:YES];
1140 [_private setPreviousItem:nil];
1143 static inline WebDataSource *dataSource(WebDocumentLoader *loader)
1145 return [(WebDocumentLoaderMac *)loader dataSource];
1148 - (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader
1150 return dataSource(loader);
1153 - (WebDocumentLoader *)_createDocumentLoaderWithRequest:(NSURLRequest *)request
1155 WebDocumentLoaderMac *loader = [[WebDocumentLoaderMac alloc] initWithRequest:request];
1157 WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader];
1158 [loader setDataSource:dataSource];
1159 [dataSource release];
1165 There is a race condition between the layout and load completion that affects restoring the scroll position.
1166 We try to restore the scroll position at both the first layout and upon load completion.
1168 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1169 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1170 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
1171 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1172 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1173 fails. We then successfully restore it when the layout happens.
1176 - (void)_restoreScrollPositionAndViewState
1178 ASSERT(_private->currentItem);
1179 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1180 NSPoint point = [_private->currentItem scrollPoint];
1181 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1182 id state = [_private->currentItem viewState];
1184 [(id <_WebDocumentViewState>)docView setViewState:state];
1187 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1189 [docView scrollPoint:point];
1195 @implementation WebFrame (WebPrivate)
1197 // FIXME: this exists only as a convenience for Safari, consider moving there
1198 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
1200 return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
1203 - (void)_setShouldCreateRenderers:(BOOL)f
1205 [_private->bridge setShouldCreateRenderers:f];
1208 - (NSColor *)_bodyBackgroundColor
1210 return [_private->bridge bodyBackgroundColor];
1215 return [_private->bridge isFrameSet];
1218 - (BOOL)_firstLayoutDone
1220 return [[self _frameLoader] firstLayoutDone];
1223 - (WebFrameLoadType)_loadType
1225 return (WebFrameLoadType)[[self _frameLoader] loadType];
1230 @implementation WebFormState : NSObject
1232 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
1234 self = [super init];
1238 _form = [form retain];
1239 _values = [values copy];
1240 _sourceFrame = [sourceFrame retain];
1248 [_sourceFrame release];
1252 - (DOMElement *)form
1257 - (NSDictionary *)values
1262 - (WebFrame *)sourceFrame
1264 return _sourceFrame;
1269 @implementation WebFrame
1273 return [self initWithName:nil webFrameView:nil webView:nil];
1276 // FIXME: this method can't work any more and should be marked deprecated
1277 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
1279 return [self _initWithWebFrameView:fv webView:v bridge:nil];
1284 ASSERT(_private->bridge == nil);
1294 ASSERT(_private->bridge == nil);
1303 return [[self _bridge] name];
1306 - (WebFrameView *)frameView
1308 return _private->webFrameView;
1311 - (WebView *)webView
1313 return [[[self _bridge] page] webView];
1316 - (DOMDocument *)DOMDocument
1318 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
1321 - (DOMHTMLElement *)frameElement
1323 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
1326 - (WebDataSource *)provisionalDataSource
1328 return [[self _frameLoader] provisionalDataSource];
1331 - (WebDataSource *)dataSource
1333 return [[self _frameLoader] dataSource];
1336 - (void)loadRequest:(NSURLRequest *)request
1338 // FIXME: is this the right place to reset loadType? Perhaps this should be done
1339 // after loading is finished or aborted.
1340 [[self _frameLoader] setLoadType:FrameLoadTypeStandard];
1341 [[self _frameLoader] _loadRequest:request archive:nil];
1344 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1346 NSURLRequest *request = [self _webDataRequestForData:data
1348 textEncodingName:encodingName
1350 unreachableURL:unreachableURL];
1351 [self loadRequest:request];
1355 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
1357 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
1360 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1362 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1363 [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
1366 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
1368 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
1371 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
1373 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
1376 - (void)loadArchive:(WebArchive *)archive
1378 WebResource *mainResource = [archive mainResource];
1380 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
1381 MIMEType:[mainResource MIMEType]
1382 textEncodingName:[mainResource textEncodingName]
1383 baseURL:[mainResource URL]
1384 unreachableURL:nil];
1385 [[self _frameLoader] _loadRequest:request archive:archive];
1391 [[self _frameLoader] stopLoading];
1396 [[self _frameLoader] reload];
1399 - (WebFrame *)findFrameNamed:(NSString *)name
1401 return Frame([[self _bridge] findFrameNamed:name]);
1404 - (WebFrame *)parentFrame
1406 return [[Frame([[self _bridge] parent]) retain] autorelease];
1409 - (NSArray *)childFrames
1411 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
1412 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
1413 [children addObject:child];
1420 @implementation WebFrame (WebFrameLoaderClient)
1422 - (void)_resetBackForwardList
1424 // Note this doesn't verify the current load type as a b/f operation because it is called from
1425 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1426 ASSERT(self == [[self webView] mainFrame]);
1427 WebHistoryItem *resetItem = _private->currentItem;
1429 [[[self webView] backForwardList] goToItem:resetItem];
1432 - (void)_invalidateCurrentItemPageCache
1434 // When we are pre-commit, the currentItem is where the pageCache data resides
1435 NSDictionary *pageCache = [_private->currentItem pageCache];
1437 [[self _bridge] invalidatePageCache:pageCache];
1439 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
1440 [_private->currentItem setHasPageCache:NO];
1443 - (BOOL)_provisionalItemIsTarget
1445 return [_private->provisionalItem isTargetItem];
1448 - (BOOL)_loadProvisionalItemFromPageCache
1450 WebHistoryItem *item = _private->provisionalItem;
1451 if (![item hasPageCache])
1453 NSDictionary *pageCache = [item pageCache];
1454 if (![pageCache objectForKey:WebCorePageCacheStateKey])
1456 LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
1457 [[self provisionalDataSource] _loadFromPageCache:pageCache];
1461 - (BOOL)_privateBrowsingEnabled
1463 return [[[self webView] preferences] privateBrowsingEnabled];
1466 - (void)_makeDocumentView
1468 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[[self _frameLoader] dataSource]];
1472 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
1473 WebFrameView *v = _private->webFrameView;
1474 [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
1475 [self _updateBackground];
1476 [_private->bridge installInFrame:[v _scrollView]];
1478 // Call setDataSource on the document view after it has been placed in the view hierarchy.
1479 // This what we for the top-level view, so should do this for views in subframes as well.
1480 [documentView setDataSource:[[self _frameLoader] dataSource]];
1483 - (void)_forceLayout
1485 NSView <WebDocumentView> *view = [[self frameView] documentView];
1486 if ([view isKindOfClass:[WebHTMLView class]])
1487 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
1488 [view setNeedsLayout:YES];
1492 - (void)_updateHistoryForCommit
1494 WebFrameLoadType type = [[self _frameLoader] loadType];
1495 if (isBackForwardLoadType(type) ||
1496 (type == WebFrameLoadTypeReload && [[self provisionalDataSource] unreachableURL] != nil)) {
1497 // Once committed, we want to use current item for saving DocState, and
1498 // the provisional item for restoring state.
1499 // Note previousItem must be set before we close the URL, which will
1500 // happen when the data source is made non-provisional below
1501 [_private setPreviousItem:_private->currentItem];
1502 ASSERT(_private->provisionalItem);
1503 [_private setCurrentItem:_private->provisionalItem];
1504 [_private setProvisionalItem:nil];
1508 - (void)_updateHistoryForReload
1510 WebHistoryItem *currItem = _private->currentItem;
1511 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
1512 [currItem setHasPageCache:NO];
1513 if ([[self _frameLoader] loadType] == WebFrameLoadTypeReload)
1514 [self _saveScrollPositionAndViewStateToItem:currItem];
1515 WebDataSource *dataSource = [[self _frameLoader] dataSource];
1516 NSURLRequest *request = [dataSource request];
1517 // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
1518 if ([request _webDataRequestUnreachableURL] == nil)
1519 [currItem setURL:[request URL]];
1520 // Update the last visited time. Mostly interesting for URL autocompletion statistics.
1521 NSURL *URL = [[[[dataSource _documentLoader] originalRequestCopy] URL] _webkit_canonicalize];
1522 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
1523 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
1525 [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
1528 - (void)_updateHistoryForStandardLoad
1530 WebDataSource *dataSource = [[self _frameLoader] dataSource];
1531 if (![[dataSource _documentLoader] isClientRedirect]) {
1532 NSURL *URL = [dataSource _URLForHistory];
1533 if (URL && ![URL _web_isEmpty]) {
1534 ASSERT([self webView]);
1535 if (![[[self webView] preferences] privateBrowsingEnabled]) {
1536 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
1537 if ([dataSource pageTitle])
1538 [entry setTitle:[dataSource pageTitle]];
1540 [self _addBackForwardItemClippedAtTarget:YES];
1543 NSURLRequest *request = [dataSource request];
1545 // Update the URL in the BF list that we made before the redirect, unless
1546 // this is alternate content for an unreachable URL (we want the BF list
1547 // item to remember the unreachable URL in case it becomes reachable later).
1548 if ([request _webDataRequestUnreachableURL] == nil) {
1549 [_private->currentItem setURL:[request URL]];
1551 // clear out the form data so we don't repost it to the wrong place if we
1552 // ever go back/forward to this item
1553 [_private->currentItem _setFormInfoFromRequest:request];
1555 // We must also clear out form data so we don't try to restore it into the incoming page,
1561 - (void)_updateHistoryForBackForwardNavigation
1563 // Must grab the current scroll position before disturbing it
1564 [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
1567 - (void)_updateHistoryForInternalLoad
1569 // Add an item to the item tree for this frame
1570 ASSERT(![[[[self _frameLoader] dataSource] _documentLoader] isClientRedirect]);
1571 WebFrame *parentFrame = [self parentFrame];
1573 WebHistoryItem *parentItem = parentFrame->_private->currentItem;
1574 // The only case where parentItem==nil should be when a parent frame loaded an
1575 // empty URL, which doesn't set up a current item in that parent.
1577 [parentItem addChildItem:[self _createItem:YES]];
1579 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
1580 // for a top-level frame, but that was a likely explanation for those crashes,
1581 // so let's guard against it.
1582 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
1583 LOG_ERROR("no parent frame in transitionToCommitted:, WebFrameLoadTypeInternal");
1587 - (LoadErrorResetToken *)_tokenForLoadErrorReset
1589 return (LoadErrorResetToken*)[[self _currentBackForwardListItemToResetTo] retain];
1592 - (void)_resetAfterLoadError:(LoadErrorResetToken *)token
1594 WebHistoryItem *item = (WebHistoryItem *)token;
1596 [[[self webView] backForwardList] goToItem:item];
1600 - (void)_doNotResetAfterLoadError:(LoadErrorResetToken *)token
1602 WebHistoryItem *item = (WebHistoryItem *)token;
1606 - (void)_dispatchDidHandleOnloadEventsForFrame
1608 WebView *webView = [self webView];
1609 [[webView _frameLoadDelegateForwarder] webView:webView didHandleOnloadEventsForFrame:self];
1612 - (void)_dispatchDidReceiveServerRedirectForProvisionalLoadForFrame
1614 WebView *webView = [self webView];
1615 [[webView _frameLoadDelegateForwarder] webView:webView
1616 didReceiveServerRedirectForProvisionalLoadForFrame:self];
1619 - (id)_dispatchIdentifierForInitialRequest:(NSURLRequest *)clientRequest fromDocumentLoader:(WebDocumentLoader *)loader
1621 WebView *webView = [self webView];
1622 id resourceLoadDelegate = [webView resourceLoadDelegate];
1624 if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
1625 return [resourceLoadDelegate webView:webView identifierForInitialRequest:clientRequest fromDataSource:dataSource(loader)];
1627 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:dataSource(loader)];
1630 - (NSURLRequest *)_dispatchResource:(id)identifier willSendRequest:(NSURLRequest *)clientRequest redirectResponse:(NSURLResponse *)redirectResponse fromDocumentLoader:(WebDocumentLoader *)loader
1632 WebView *webView = [self webView];
1633 id resourceLoadDelegate = [webView resourceLoadDelegate];
1635 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
1636 return [resourceLoadDelegate webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:dataSource(loader)];
1638 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:dataSource(loader)];
1641 - (void)_dispatchDidReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier fromDocumentLoader:(WebDocumentLoader *)loader
1643 WebView *webView = [self webView];
1644 id resourceLoadDelegate = [webView resourceLoadDelegate];
1646 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
1647 [resourceLoadDelegate webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1649 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1652 - (void)_dispatchDidCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier fromDocumentLoader:(WebDocumentLoader *)loader
1654 WebView *webView = [self webView];
1655 id resourceLoadDelegate = [webView resourceLoadDelegate];
1657 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
1658 [resourceLoadDelegate webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1660 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1663 - (void)_dispatchResource:(id)identifier didReceiveResponse:(NSURLResponse *)r fromDocumentLoader:(WebDocumentLoader *)loader
1665 WebView *webView = [self webView];
1667 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
1668 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:dataSource(loader)];
1670 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:dataSource(loader)];
1673 - (void)_dispatchResource:(id)identifier didReceiveContentLength:(int)lengthReceived fromDocumentLoader:(WebDocumentLoader *)loader
1675 WebView *webView = [self webView];
1677 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
1678 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:dataSource(loader)];
1680 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:dataSource(loader)];
1683 - (void)_dispatchResource:(id)identifier didFinishLoadingFromDocumentLoader:(WebDocumentLoader *)loader
1685 WebView *webView = [self webView];
1687 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
1688 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:dataSource(loader)];
1690 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:dataSource(loader)];
1694 - (void)_dispatchResource:(id)identifier didFailLoadingWithError:error fromDocumentLoader:(WebDocumentLoader *)loader
1696 WebView *webView = [self webView];
1697 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:dataSource(loader)];
1700 - (void)_dispatchDidCancelClientRedirectForFrame
1702 WebView *webView = [self webView];
1703 [[webView _frameLoadDelegateForwarder] webView:webView didCancelClientRedirectForFrame:self];
1706 - (void)_dispatchWillPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date
1708 WebView *webView = [self webView];
1709 [[webView _frameLoadDelegateForwarder] webView:webView
1710 willPerformClientRedirectToURL:URL
1716 - (void)_dispatchDidChangeLocationWithinPageForFrame
1718 WebView *webView = [self webView];
1719 [[webView _frameLoadDelegateForwarder] webView:webView didChangeLocationWithinPageForFrame:self];
1722 - (void)_dispatchWillCloseFrame
1724 WebView *webView = [self webView];
1725 [[webView _frameLoadDelegateForwarder] webView:webView willCloseFrame:self];
1728 - (void)_dispatchDidReceiveIcon:(NSImage *)icon
1730 WebView *webView = [self webView];
1731 [[webView _frameLoadDelegateForwarder] webView:webView didReceiveIcon:icon forFrame:self];
1734 - (void)_dispatchDidStartProvisionalLoadForFrame
1736 WebView *webView = [self webView];
1737 [[webView _frameLoadDelegateForwarder] webView:webView didStartProvisionalLoadForFrame:self];
1740 - (void)_dispatchDidReceiveTitle:(NSString *)title
1742 WebView *webView = [self webView];
1743 [[webView _frameLoadDelegateForwarder] webView:webView didReceiveTitle:title forFrame:self];
1746 - (void)_dispatchDidCommitLoadForFrame
1748 WebView *webView = [self webView];
1749 [[webView _frameLoadDelegateForwarder] webView:webView didCommitLoadForFrame:self];
1752 - (void)_dispatchDidFailProvisionalLoadWithError:(NSError *)error
1754 WebView *webView = [self webView];
1755 [[webView _frameLoadDelegateForwarder] webView:webView didFailProvisionalLoadWithError:error forFrame:self];
1758 - (void)_dispatchDidFailLoadWithError:(NSError *)error
1760 WebView *webView = [self webView];
1761 [[webView _frameLoadDelegateForwarder] webView:webView didFailLoadWithError:error forFrame:self];
1764 - (void)_dispatchDidFinishLoadForFrame
1766 WebView *webView = [self webView];
1767 [[webView _frameLoadDelegateForwarder] webView:webView didFinishLoadForFrame:self];
1770 - (void)_dispatchDidFirstLayoutInFrame
1772 WebView *webView = [self webView];
1773 [[webView _frameLoadDelegateForwarder] webView:webView didFirstLayoutInFrame:self];
1776 - (WebFrame *)_dispatchCreateWebViewWithRequest:(NSURLRequest *)request
1778 WebView *currentWebView = [self webView];
1779 id wd = [currentWebView UIDelegate];
1780 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1781 return [[wd webView:currentWebView createWebViewWithRequest:request] mainFrame];
1783 return [[[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:request] mainFrame];
1786 - (void)_dispatchShow
1788 WebView *webView = [self webView];
1789 [[webView _UIDelegateForwarder] webViewShow:webView];
1792 - (void)_dispatchDecidePolicyForMIMEType:(NSString *)MIMEType request:(NSURLRequest *)request decisionListener:(WebPolicyDecisionListener *)decisionListener
1794 WebView *webView = [self webView];
1796 [[webView _policyDelegateForwarder] webView:webView decidePolicyForMIMEType:MIMEType request:request frame:self decisionListener:decisionListener];
1799 - (void)_dispatchDecidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(WebPolicyDecisionListener *)decisionListener
1801 WebView *webView = [self webView];
1802 [[webView _policyDelegateForwarder] webView:webView
1803 decidePolicyForNewWindowAction:action
1805 newFrameName:frameName
1806 decisionListener:decisionListener];
1809 - (void)_dispatchDecidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request decisionListener:(WebPolicyDecisionListener *)decisionListener
1811 WebView *webView = [self webView];
1812 [[webView _policyDelegateForwarder] webView:webView
1813 decidePolicyForNavigationAction:action
1816 decisionListener:decisionListener];
1819 - (void)_dispatchUnableToImplementPolicyWithError:(NSError *)error
1821 WebView *webView = [self webView];
1822 [[webView _policyDelegateForwarder] webView:webView unableToImplementPolicyWithError:error frame:self];
1825 - (void)_detachedFromParent1
1827 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
1830 - (void)_detachedFromParent2
1832 [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
1833 [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
1836 - (void)_detachedFromParent3
1838 [_private setWebFrameView:nil];
1841 - (void)_detachedFromParent4
1843 _private->bridge = nil;
1846 - (void)_updateHistoryAfterClientRedirect
1848 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
1849 // khtml has closed the URL and saved away the form state.
1850 WebHistoryItem *item = _private->currentItem;
1851 [item setDocumentState:nil];
1852 [item setScrollPoint:NSZeroPoint];
1855 - (void)_loadedFromPageCache
1857 // Release the resources kept in the page cache.
1858 // They will be reset when we leave this page.
1859 // The WebCore side of the page cache will have already been invalidated by
1860 // the bridge to prevent premature release.
1861 [_private->currentItem setHasPageCache:NO];
1864 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
1866 [WebDownload _downloadWithLoadingConnection:connection
1869 delegate:[[self webView] downloadDelegate]
1873 - (void)_setDocumentViewFromPageCache:(NSDictionary *)pageCache
1875 NSView <WebDocumentView> *cachedView = [pageCache objectForKey:WebPageCacheDocumentViewKey];
1876 ASSERT(cachedView != nil);
1877 [[self frameView] _setDocumentView:cachedView];
1880 - (void)_setCopiesOnScroll
1882 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];