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 "WebScriptDebugServerPrivate.h"
66 #import "WebUIDelegate.h"
67 #import "WebViewInternal.h"
68 #import <WebKit/DOM.h>
69 #import <WebKitSystemInterface.h>
70 #import <objc/objc-runtime.h>
73 Here is the current behavior matrix for four types of navigations:
77 Restore form state: YES
78 Restore scroll and focus state: YES
79 WF Cache policy: NSURLRequestUseProtocolCachePolicy
80 Add to back/forward list: YES
84 Restore form state: YES
85 Restore scroll and focus state: YES
86 WF Cache policy: NSURLRequestReturnCacheDataElseLoad
87 Add to back/forward list: NO
89 Reload (meaning only the reload button):
91 Restore form state: NO
92 Restore scroll and focus state: YES
93 WF Cache policy: NSURLRequestReloadIgnoringCacheData
94 Add to back/forward list: NO
96 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
98 Restore form state: NO
99 Restore scroll and focus state: NO, reset to initial conditions
100 WF Cache policy: NSURLRequestReloadIgnoringCacheData
101 Add to back/forward list: NO
104 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
105 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
106 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
108 @interface WebFrame (ForwardDecls)
109 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
110 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
111 - (WebHistoryItem *)_createItem:(BOOL)useOriginal;
112 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
113 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
116 @interface NSView (WebFramePluginHosting)
117 - (void)setWebFrame:(WebFrame *)webFrame;
120 @interface WebFramePrivate : NSObject
123 WebFrameView *webFrameView;
125 WebFrameBridge *bridge;
126 WebHistoryItem *currentItem; // BF item for our current content
127 WebHistoryItem *provisionalItem; // BF item for where we're trying to go
128 // (only known when navigating to a pre-existing BF item)
129 WebHistoryItem *previousItem; // BF item for previous content, see _itemForSavingDocState
131 WebScriptDebugger *scriptDebugger;
132 id internalLoadDelegate;
134 NSMutableSet *plugInViews;
135 NSMutableSet *inspectors;
138 - (void)setWebFrameView:(WebFrameView *)v;
140 - (void)setProvisionalItem:(WebHistoryItem *)item;
141 - (void)setPreviousItem:(WebHistoryItem *)item;
142 - (void)setCurrentItem:(WebHistoryItem *)item;
146 @implementation WebFramePrivate
150 [webFrameView release];
152 [currentItem release];
153 [provisionalItem release];
154 [previousItem release];
156 [scriptDebugger release];
158 [inspectors release];
160 ASSERT(plugInViews == nil);
165 - (void)setWebFrameView:(WebFrameView *)v
168 [webFrameView release];
172 - (void)setProvisionalItem:(WebHistoryItem *)item
175 [provisionalItem release];
176 provisionalItem = item;
179 - (void)setPreviousItem:(WebHistoryItem *)item
182 [previousItem release];
186 - (void)setCurrentItem:(WebHistoryItem *)item
189 [currentItem release];
195 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
197 return [(WebFrameBridge *)bridge webFrame];
200 @implementation WebFrame (FrameTraversal)
202 - (WebFrame *)_firstChildFrame
204 return Frame([[self _bridge] firstChild]);
207 - (WebFrame *)_lastChildFrame
209 return Frame([[self _bridge] lastChild]);
212 - (unsigned)_childFrameCount
214 return [[self _bridge] childCount];
217 - (WebFrame *)_previousSiblingFrame;
219 return Frame([[self _bridge] previousSibling]);
222 - (WebFrame *)_nextSiblingFrame;
224 return Frame([[self _bridge] nextSibling]);
227 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
229 return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
234 @implementation WebFrame (WebInternal)
236 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
238 NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
239 NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
240 [request _webDataRequestSetData:data];
241 [request _webDataRequestSetEncoding:encodingName];
242 [request _webDataRequestSetBaseURL:URL];
243 [request _webDataRequestSetUnreachableURL:unreachableURL];
244 [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
248 // helper method used in various nav cases below
249 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
251 if ([[self dataSource] _URLForHistory] != nil) {
252 WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
253 LOG (BackForward, "for frame %@, adding item %@\n", [self name], bfItem);
254 [[[self webView] backForwardList] addItem:bfItem];
258 - (void)_addHistoryItemForFragmentScroll
260 [self _addBackForwardItemClippedAtTarget:NO];
263 - (void)_didFinishLoad
265 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
268 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
270 WebDataSource *dataSrc = [self dataSource];
271 NSURLRequest *request;
272 NSURL *unreachableURL = [dataSrc unreachableURL];
275 WebHistoryItem *bfItem;
278 request = [[dataSrc _documentLoader] originalRequestCopy];
280 request = [dataSrc request];
282 if (unreachableURL != nil) {
283 URL = unreachableURL;
284 originalURL = unreachableURL;
287 originalURL = [[[dataSrc _documentLoader] originalRequestCopy] URL];
290 LOG (History, "creating item for %@", request);
292 // Frames that have never successfully loaded any content
293 // may have no URL at all. Currently our history code can't
294 // deal with such things, so we nip that in the bud here.
295 // Later we may want to learn to live with nil for URL.
296 // See bug 3368236 and related bugs for more information.
298 URL = [NSURL URLWithString:@"about:blank"];
300 if (originalURL == nil) {
301 originalURL = [NSURL URLWithString:@"about:blank"];
304 bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
305 [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
307 // save form state if this is a POST
308 [bfItem _setFormInfoFromRequest:request];
310 // Set the item for which we will save document state
311 [_private setPreviousItem:_private->currentItem];
312 [_private setCurrentItem:bfItem];
318 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
319 The item that was the target of the user's navigation is designated as the "targetItem".
320 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
321 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
323 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
325 WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
327 [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
328 if (!(doClip && self == targetFrame)) {
329 // save frame state for items that aren't loading (khtml doesn't save those)
330 [_private->bridge saveDocumentState];
332 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
333 [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
335 if (self == targetFrame)
336 [bfItem setIsTargetItem:YES];
341 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
343 return Frame([[self _bridge] childFrameNamed:name]);
346 - (BOOL)_canCachePage
348 return [[[self webView] backForwardList] _usesPageCache];
351 - (void)_purgePageCache
353 // This method implements the rule for purging the page cache.
354 unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
355 unsigned pagesCached = 0;
356 WebBackForwardList *backForwardList = [[self webView] backForwardList];
357 NSArray *backList = [backForwardList backListWithLimit: 999999];
358 WebHistoryItem *oldestNonSnapbackItem = nil;
361 for (i = 0; i < [backList count]; i++){
362 WebHistoryItem *item = [backList objectAtIndex: i];
363 if ([item hasPageCache]){
364 if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
365 oldestNonSnapbackItem = item;
370 // Snapback items are never directly purged here.
371 if (pagesCached >= sizeLimit) {
372 LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
373 [oldestNonSnapbackItem setHasPageCache:NO];
377 + (CFAbsoluteTime)_timeOfLastCompletedLoad
379 return [WebFrameLoader timeOfLastCompletedLoad];
382 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
384 NSMutableDictionary *pageCache;
386 [item setHasPageCache: YES];
388 if (![_private->bridge saveDocumentToPageCache]){
389 [item setHasPageCache: NO];
393 pageCache = [item pageCache];
394 [pageCache setObject:[NSDate date] forKey: WebPageCacheEntryDateKey];
395 [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
396 [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
401 - (void)_provisionalLoadStarted
403 FrameLoadType loadType = [[self _frameLoader] loadType];
405 // FIXME: This is OK as long as no one resizes the window,
406 // but in the case where someone does, it means garbage outside
407 // the occupied part of the scroll view.
408 [[[self frameView] _scrollView] setDrawsBackground:NO];
410 // Cache the page, if possible.
411 // Don't write to the cache if in the middle of a redirect, since we will want to
412 // store the final page we end up on.
413 // No point writing to the cache on a reload or loadSame, since we will just write
414 // over it again when we leave that page.
415 WebHistoryItem *item = _private->currentItem;
416 if ([self _canCachePage]
417 && [_private->bridge canCachePage]
419 && ![[self _frameLoader] isQuickRedirectComing]
420 && loadType != FrameLoadTypeReload
421 && loadType != FrameLoadTypeReloadAllowingStaleData
422 && loadType != FrameLoadTypeSame
423 && ![[self dataSource] isLoading]
424 && ![[[self _frameLoader] documentLoader] isStopping]) {
425 if ([[[self dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]) {
426 if (![item pageCache]){
427 // Add the items to this page's cache.
428 if ([self _createPageCacheForItem:item]) {
429 LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
431 // See if any page caches need to be purged after the addition of this
433 [self _purgePageCache];
436 LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
439 // Put the document into a null state, so it can be restored correctly.
440 [_private->bridge clear];
442 LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
445 - (WebFrameBridge *)_bridge
447 return _private->bridge;
450 // helper method that determines whether the subframes described by the item's subitems
451 // match our own current frameset
452 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
454 NSArray *childItems = [item children];
455 int numChildItems = [childItems count];
456 int numChildFrames = [self _childFrameCount];
457 if (numChildFrames != numChildItems)
461 for (i = 0; i < numChildItems; i++) {
462 NSString *itemTargetName = [[childItems objectAtIndex:i] target];
463 //Search recursive here?
464 if (![self _immediateChildFrameNamed:itemTargetName])
465 return NO; // couldn't match the i'th itemTarget
468 return YES; // found matches for all itemTargets
471 // Walk the frame tree and ensure that the URLs match the URLs in the item.
472 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
474 NSURL *currentURL = [[[self dataSource] request] URL];
476 if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
479 NSArray *childItems = [item children];
480 WebHistoryItem *childItem;
481 WebFrame *childFrame;
482 int i, count = [childItems count];
483 for (i = 0; i < count; i++){
484 childItem = [childItems objectAtIndex:i];
485 childFrame = [self _immediateChildFrameNamed:[childItem target]];
486 if (![childFrame _URLsMatchItem: childItem])
493 // loads content into this frame, as specified by item
494 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)loadType
496 NSURL *itemURL = [item URL];
497 NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
498 NSURL *currentURL = [[[self dataSource] request] URL];
499 NSArray *formData = [item formData];
501 // Are we navigating to an anchor within the page?
502 // Note if we have child frames we do a real reload, since the child frames might not
503 // match our current frame structure, or they might not have the right content. We could
504 // check for all that as an additional optimization.
505 // We also do not do anchor-style navigation if we're posting a form.
507 // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
508 // Perhaps they should.
509 if (!formData && ![[self _frameLoader] shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
512 // FIXME: We need to normalize the code paths for anchor navigation. Something
513 // like the following line of code should be done, but also accounting for correct
514 // updates to the back/forward list and scroll position.
515 // rjw 4/9/03 See 3223929.
516 [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
518 // must do this maintenance here, since we don't go through a real page reload
519 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
520 // FIXME: form state might want to be saved here too
522 // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
523 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
524 [_private->bridge scrollToAnchorWithURL:[item URL]];
526 // must do this maintenance here, since we don't go through a real page reload
527 [_private setCurrentItem:item];
528 [self _restoreScrollPositionAndViewState];
530 // Fake the URL change by updating the data source's request. This will no longer
531 // be necessary if we do the better fix described above.
532 [[[self _frameLoader] documentLoader] replaceRequestURLForAnchorScrollWithURL:itemURL];
534 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
535 didChangeLocationWithinPageForFrame:self];
536 [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
538 // Remember this item so we can traverse any child items as child frames load
539 [_private setProvisionalItem:item];
541 WebDataSource *newDataSource;
542 BOOL inPageCache = NO;
544 // Check if we'll be using the page cache. We only use the page cache
545 // if one exists and it is less than _backForwardCacheExpirationInterval
546 // seconds old. If the cache is expired it gets flushed here.
547 if ([item hasPageCache]){
548 NSDictionary *pageCache = [item pageCache];
549 NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
550 NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
551 if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]) {
552 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
553 [[self _frameLoader] loadDocumentLoader:[newDataSource _documentLoader] withLoadType:loadType formState:nil];
556 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]);
557 [item setHasPageCache: NO];
562 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
563 [[self _frameLoader] addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
565 // If this was a repost that failed the page cache, we might try to repost the form.
566 NSDictionary *action;
568 [request setHTTPMethod:@"POST"];
569 [request _web_setHTTPReferrer:[item formReferrer]];
570 webSetHTTPBody(request, formData);
571 [request _web_setHTTPContentType:[item formContentType]];
573 // Slight hack to test if the WF cache contains the page we're going to. We want
574 // to know this before talking to the policy delegate, since it affects whether we
575 // show the DoYouReallyWantToRepost nag.
577 // This trick has a small bug (3123893) where we might find a cache hit, but then
578 // have the item vanish when we try to use it in the ensuing nav. This should be
579 // extremely rare, but in that case the user will get an error on the navigation.
580 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
581 NSURLResponse *synchResponse = nil;
582 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
583 if (synchResponse == nil) {
585 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
586 action = [[self _frameLoader] actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
588 // We can use the cache, don't use navType=resubmit
589 action = [[self _frameLoader] actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
593 case FrameLoadTypeReload:
594 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
596 case FrameLoadTypeBack:
597 case FrameLoadTypeForward:
598 case FrameLoadTypeIndexedBackForward:
599 if (![[itemURL scheme] isEqual:@"https"])
600 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
602 case FrameLoadTypeStandard:
603 case FrameLoadTypeInternal:
604 // no-op: leave as protocol default
605 // FIXME: I wonder if we ever hit this case
607 case FrameLoadTypeSame:
608 case FrameLoadTypeReloadAllowingStaleData:
610 ASSERT_NOT_REACHED();
613 action = [[self _frameLoader] actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
616 [[self _frameLoader] _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
622 // The general idea here is to traverse the frame tree and the item tree in parallel,
623 // tracking whether each frame already has the content the item requests. If there is
624 // a match (by URL), we just restore scroll position and recurse. Otherwise we must
625 // reload that frame, and all its kids.
626 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(FrameLoadType)type
628 NSURL *itemURL = [item URL];
629 NSURL *currentURL = [[[self dataSource] request] URL];
631 // Always reload the target frame of the item we're going to. This ensures that we will
632 // do -some- load for the transition, which means a proper notification will be posted
634 // The exact URL has to match, including fragment. We want to go through the _load
635 // method, even if to do a within-page navigation.
636 // The current frame tree and the frame tree snapshot in the item have to match.
637 if (![item isTargetItem] &&
638 [itemURL isEqual:currentURL] &&
639 (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
640 [self _childFramesMatchItem:item])
642 // This content is good, so leave it alone and look for children that need reloading
644 // Save form state (works from currentItem, since prevItem is nil)
645 ASSERT(!_private->previousItem);
646 [_private->bridge saveDocumentState];
647 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
649 [_private setCurrentItem:item];
651 // Restore form state (works from currentItem)
652 [_private->bridge restoreDocumentState];
653 // Restore the scroll position (taken in favor of going back to the anchor)
654 [self _restoreScrollPositionAndViewState];
656 NSArray *childItems = [item children];
657 int numChildItems = childItems ? [childItems count] : 0;
659 for (i = numChildItems - 1; i >= 0; i--) {
660 WebHistoryItem *childItem = [childItems objectAtIndex:i];
661 NSString *childName = [childItem target];
662 WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
663 ASSERT(fromChildItem || [fromItem isTargetItem]);
664 WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
666 [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
669 // We need to reload the content
670 [self _loadItem:item withLoadType:type];
674 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
675 // This includes recursion to handle loading into framesets properly
676 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)type
678 ASSERT(![self parentFrame]);
679 // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
680 // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
681 // Ultimately, history item navigations should go through the policy delegate. That's covered in:
682 // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
683 if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {
684 WebBackForwardList *backForwardList = [[self webView] backForwardList];
685 WebHistoryItem *currItem = [backForwardList currentItem];
686 // Set the BF cursor before commit, which lets the user quickly click back/forward again.
687 // - plus, it only makes sense for the top level of the operation through the frametree,
688 // as opposed to happening for some/one of the page commits that might happen soon
689 [backForwardList goToItem:item];
690 [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
694 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
696 WebHistoryItem *parentItem = _private->currentItem;
697 NSArray *childItems = [parentItem children];
698 FrameLoadType loadType = [[self _frameLoader] loadType];
699 FrameLoadType childLoadType = FrameLoadTypeInternal;
700 WebHistoryItem *childItem = nil;
702 // If we're moving in the backforward list, we might want to replace the content
703 // of this child frame with whatever was there at that point.
704 // Reload will maintain the frame contents, LoadSame will not.
706 (isBackForwardLoadType(loadType)
707 || loadType == FrameLoadTypeReload
708 || loadType == FrameLoadTypeReloadAllowingStaleData))
710 childItem = [parentItem childItemWithName:[childFrame name]];
712 // Use the original URL to ensure we get all the side-effects, such as
713 // onLoad handlers, of any redirects that happened. An example of where
714 // this is needed is Radar 3213556.
715 URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
716 // These behaviors implied by these loadTypes should apply to the child frames
717 childLoadType = loadType;
719 if (isBackForwardLoadType(loadType))
720 // For back/forward, remember this item so we can traverse any child items as child frames load
721 [childFrame->_private setProvisionalItem:childItem];
723 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
724 [childFrame->_private setCurrentItem:childItem];
728 WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
730 [childFrame loadArchive:archive];
732 [[childFrame _frameLoader] loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
735 - (void)_setTitle:(NSString *)title forURL:(NSURL *)URL
737 [[[WebHistory optionalSharedHistory] itemForURL:URL] setTitle:title];
738 [_private->currentItem setTitle:title];
741 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
744 NSView <WebDocumentView> *docView = [[self frameView] documentView];
745 NSView *parent = [docView superview];
746 // we might already be detached when this is called from detachFromParent, in which
747 // case we don't want to override real data earlier gathered with (0,0)
750 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
751 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
752 // ScrollView instead of using the one provided by the WebFrame
753 point = [(id <_WebDocumentViewState>)docView scrollPoint];
754 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
756 // Parent is the clipview of the DynamicScrollView the WebFrame installs
757 ASSERT([parent isKindOfClass:[NSClipView class]]);
758 point = [parent bounds].origin;
760 [item setScrollPoint:point];
765 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
767 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
768 [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
771 - (void)_viewDidMoveToHostWindow
773 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
774 [[[frame frameView] documentView] viewDidMoveToHostWindow];
777 - (void)_addChild:(WebFrame *)child
779 [[self _bridge] appendChild:[child _bridge]];
780 [[[child dataSource] _documentLoader] setOverrideEncoding:[[[self dataSource] _documentLoader] overrideEncoding]];
783 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
784 // item, because we optimistically move it right away at the start of the operation. But when
785 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
786 // Return the item that we would reset to, so we can decide later whether to actually reset.
787 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
789 if (isBackForwardLoadType([[self _frameLoader] loadType]) && self == [[self webView] mainFrame])
790 return _private->currentItem;
794 - (WebHistoryItem *)_itemForSavingDocState
796 // For a standard page load, we will have a previous item set, which will be used to
797 // store the form state. However, in some cases we will have no previous item, and
798 // the current item is the right place to save the state. One example is when we
799 // detach a bunch of frames because we are navigating from a site with frames to
800 // another site. Another is when saving the frame state of a frame that is not the
801 // target of the current navigation (if we even decide to save with that granularity).
803 // Because of previousItem's "masking" of currentItem for this purpose, it's important
804 // that previousItem be cleared at the end of a page transition. We leverage the
805 // checkLoadComplete recursion to achieve this goal.
807 return _private->previousItem ? _private->previousItem : _private->currentItem;
810 - (WebHistoryItem *)_itemForRestoringDocState
812 switch ([[self _frameLoader] loadType]) {
813 case FrameLoadTypeReload:
814 case FrameLoadTypeReloadAllowingStaleData:
815 case FrameLoadTypeSame:
816 case FrameLoadTypeReplace:
817 // Don't restore any form state on reload or loadSame
819 case FrameLoadTypeBack:
820 case FrameLoadTypeForward:
821 case FrameLoadTypeIndexedBackForward:
822 case FrameLoadTypeInternal:
823 case FrameLoadTypeStandard:
824 return _private->currentItem;
826 ASSERT_NOT_REACHED();
830 // Walk the frame tree, telling all frames to save their form state into their current
832 - (void)_saveDocumentAndScrollState
834 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
835 [[frame _bridge] saveDocumentState];
836 [frame _saveScrollPositionAndViewStateToItem:frame->_private->currentItem];
840 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
842 WebHistoryItem *item = _private->currentItem;
843 NSString* URLString = [URL _web_originalDataAsString];
844 return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
847 // Return next frame to be traversed, visiting children after parent
848 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
850 return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
853 // Return previous frame to be traversed, exact reverse order of _nextFrame
854 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
856 return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
859 - (BOOL)_shouldCreateRenderers
861 return [_private->bridge shouldCreateRenderers];
864 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
867 return [[self _bridge] numPendingOrLoadingRequests];
870 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
871 num += [[frame _bridge] numPendingOrLoadingRequests];
876 - (void)_reloadForPluginChanges
878 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
879 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
880 if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
885 - (void)_attachScriptDebugger
887 if (!_private->scriptDebugger)
888 _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
891 - (void)_detachScriptDebugger
893 if (_private->scriptDebugger) {
894 id old = _private->scriptDebugger;
895 _private->scriptDebugger = nil;
900 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
902 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
903 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
904 if ([documentView isKindOfClass:[WebHTMLView class]])
905 [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
909 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
911 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
912 NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
913 if ([documentView isKindOfClass:[WebHTMLView class]])
914 [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
918 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
924 _private = [[WebFramePrivate alloc] init];
926 _private->bridge = bridge;
929 [_private setWebFrameView:fv];
930 [fv _setWebFrame:self];
938 - (NSArray *)_documentViews
940 NSMutableArray *result = [NSMutableArray array];
941 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
942 id docView = [[frame frameView] documentView];
944 [result addObject:docView];
950 - (void)_updateBackground
952 BOOL drawsBackground = [[self webView] drawsBackground];
953 NSColor *backgroundColor = [[self webView] backgroundColor];
955 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
956 // Never call setDrawsBackground:YES here on the scroll view or the background color will
957 // flash between pages loads. setDrawsBackground:YES will be called in _frameLoadCompleted.
958 if (!drawsBackground)
959 [[[frame frameView] _scrollView] setDrawsBackground:NO];
960 [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
961 id documentView = [[frame frameView] documentView];
962 if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
963 [documentView setDrawsBackground:drawsBackground];
964 if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
965 [documentView setBackgroundColor:backgroundColor];
966 [[frame _bridge] setDrawsBackground:drawsBackground];
967 [[frame _bridge] setBaseBackgroundColor:backgroundColor];
971 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
973 _private->internalLoadDelegate = internalLoadDelegate;
976 - (id)_internalLoadDelegate
978 return _private->internalLoadDelegate;
981 - (void)_unmarkAllMisspellings
983 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
984 [[frame _bridge] unmarkAllMisspellings];
987 - (BOOL)_hasSelection
989 id documentView = [[self frameView] documentView];
991 // optimization for common case to avoid creating potentially large selection string
992 if ([documentView isKindOfClass:[WebHTMLView class]]) {
993 DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
994 return selectedDOMRange && ![selectedDOMRange collapsed];
997 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
998 return [[documentView selectedString] length] > 0;
1003 - (void)_clearSelection
1005 id documentView = [[self frameView] documentView];
1006 if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1007 [documentView deselectAll];
1012 - (BOOL)_atMostOneFrameHasSelection;
1014 // FIXME: 4186050 is one known case that makes this debug check fail
1016 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1017 if ([frame _hasSelection]) {
1028 - (WebFrame *)_findFrameWithSelection
1030 for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1031 if ([frame _hasSelection])
1037 - (void)_clearSelectionInOtherFrames
1039 // We rely on WebDocumentSelection protocol implementors to call this method when they become first
1040 // responder. It would be nicer to just notice first responder changes here instead, but there's no
1041 // notification sent when the first responder changes in general (Radar 2573089).
1042 WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
1043 if (frameWithSelection != self)
1044 [frameWithSelection _clearSelection];
1046 // While we're in the general area of selection and frames, check that there is only one now.
1047 ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
1050 - (void)_addPlugInView:(NSView *)plugInView
1052 ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
1053 ASSERT(![_private->plugInViews containsObject:plugInView]);
1055 if (!_private->plugInViews)
1056 _private->plugInViews = [[NSMutableSet alloc] init];
1058 [plugInView setWebFrame:self];
1059 [_private->plugInViews addObject:plugInView];
1062 - (void)_removeAllPlugInViews
1064 if (!_private->plugInViews)
1067 [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
1068 [_private->plugInViews release];
1069 _private->plugInViews = nil;
1072 // This is called when leaving a page or closing the WebView
1073 - (void)_willCloseURL
1075 [self _removeAllPlugInViews];
1078 - (BOOL)_isMainFrame
1080 return self == [[self webView] mainFrame];
1083 - (void)_addInspector:(WebInspector *)inspector
1085 if (!_private->inspectors)
1086 _private->inspectors = [[NSMutableSet alloc] init];
1087 ASSERT(![_private->inspectors containsObject:inspector]);
1088 [_private->inspectors addObject:inspector];
1091 - (void)_removeInspector:(WebInspector *)inspector
1093 ASSERT([_private->inspectors containsObject:inspector]);
1094 [_private->inspectors removeObject:inspector];
1097 - (WebFrameLoader *)_frameLoader
1099 return [_private->bridge frameLoader];
1102 - (void)_prepareForDataSourceReplacement
1104 if (![self dataSource]) {
1105 ASSERT(![self _childFrameCount]);
1109 // Make sure that any work that is triggered by resigning first reponder can get done.
1110 // The main example where this came up is the textDidEndEditing that is sent to the
1111 // FormsDelegate (3223413). We need to do this before _detachChildren, since that will
1112 // remove the views as a side-effect of freeing the bridge, at which point we can't
1113 // post the FormDelegate messages.
1115 // Note that this can also take FirstResponder away from a child of our frameView that
1116 // is not in a child frame's view. This is OK because we are in the process
1117 // of loading new content, which will blow away all editors in this top frame, and if
1118 // a non-editor is firstReponder it will not be affected by endEditingFor:.
1119 // Potentially one day someone could write a DocView whose editors were not all
1120 // replaced by loading new content, but that does not apply currently.
1121 NSView *frameView = [self frameView];
1122 NSWindow *window = [frameView window];
1123 NSResponder *firstResp = [window firstResponder];
1124 if ([firstResp isKindOfClass:[NSView class]]
1125 && [(NSView *)firstResp isDescendantOf:frameView])
1127 [window endEditingFor:firstResp];
1130 [[self _frameLoader] detachChildren];
1133 - (void)_frameLoadCompleted
1135 // Note: Can be called multiple times.
1136 // Even if already complete, we might have set a previous item on a frame that
1137 // didn't do any data loading on the past transaction. Make sure to clear these out.
1138 NSScrollView *sv = [[self frameView] _scrollView];
1139 if ([[self webView] drawsBackground])
1140 [sv setDrawsBackground:YES];
1141 [_private setPreviousItem:nil];
1144 static inline WebDataSource *dataSource(WebDocumentLoader *loader)
1146 return [(WebDocumentLoaderMac *)loader dataSource];
1149 - (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader
1151 return dataSource(loader);
1154 - (WebDocumentLoader *)_createDocumentLoaderWithRequest:(NSURLRequest *)request
1156 WebDocumentLoaderMac *loader = [[WebDocumentLoaderMac alloc] initWithRequest:request];
1158 WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader];
1159 [loader setDataSource:dataSource];
1160 [dataSource release];
1166 There is a race condition between the layout and load completion that affects restoring the scroll position.
1167 We try to restore the scroll position at both the first layout and upon load completion.
1169 1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1170 first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1171 jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in
1172 which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1173 2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1174 fails. We then successfully restore it when the layout happens.
1177 - (void)_restoreScrollPositionAndViewState
1179 ASSERT(_private->currentItem);
1180 NSView <WebDocumentView> *docView = [[self frameView] documentView];
1181 NSPoint point = [_private->currentItem scrollPoint];
1182 if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1183 id state = [_private->currentItem viewState];
1185 [(id <_WebDocumentViewState>)docView setViewState:state];
1188 [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1190 [docView scrollPoint:point];
1196 @implementation WebFrame (WebPrivate)
1198 // FIXME: this exists only as a convenience for Safari, consider moving there
1199 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
1201 return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
1204 - (void)_setShouldCreateRenderers:(BOOL)f
1206 [_private->bridge setShouldCreateRenderers:f];
1209 - (NSColor *)_bodyBackgroundColor
1211 return [_private->bridge bodyBackgroundColor];
1216 return [_private->bridge isFrameSet];
1219 - (BOOL)_firstLayoutDone
1221 return [[self _frameLoader] firstLayoutDone];
1224 - (WebFrameLoadType)_loadType
1226 return (WebFrameLoadType)[[self _frameLoader] loadType];
1231 @implementation WebFormState : NSObject
1233 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
1235 self = [super init];
1239 _form = [form retain];
1240 _values = [values copy];
1241 _sourceFrame = [sourceFrame retain];
1249 [_sourceFrame release];
1253 - (DOMElement *)form
1258 - (NSDictionary *)values
1263 - (WebFrame *)sourceFrame
1265 return _sourceFrame;
1270 @implementation WebFrame
1274 return [self initWithName:nil webFrameView:nil webView:nil];
1277 // FIXME: this method can't work any more and should be marked deprecated
1278 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
1280 return [self _initWithWebFrameView:fv webView:v bridge:nil];
1285 ASSERT(_private->bridge == nil);
1295 ASSERT(_private->bridge == nil);
1304 return [[self _bridge] name];
1307 - (WebFrameView *)frameView
1309 return _private->webFrameView;
1312 - (WebView *)webView
1314 return [[[self _bridge] page] webView];
1317 - (DOMDocument *)DOMDocument
1319 return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
1322 - (DOMHTMLElement *)frameElement
1324 return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
1327 - (WebDataSource *)provisionalDataSource
1329 return dataSource([[self _frameLoader] provisionalDocumentLoader]);
1332 - (WebDataSource *)dataSource
1334 return dataSource([[self _frameLoader] documentLoader]);
1337 - (void)loadRequest:(NSURLRequest *)request
1339 // FIXME: is this the right place to reset loadType? Perhaps this should be done
1340 // after loading is finished or aborted.
1341 [[self _frameLoader] setLoadType:FrameLoadTypeStandard];
1342 [[self _frameLoader] _loadRequest:request archive:nil];
1345 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1347 NSURLRequest *request = [self _webDataRequestForData:data
1349 textEncodingName:encodingName
1351 unreachableURL:unreachableURL];
1352 [self loadRequest:request];
1356 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
1358 [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
1361 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1363 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1364 [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
1367 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
1369 [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
1372 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
1374 [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
1377 - (void)loadArchive:(WebArchive *)archive
1379 WebResource *mainResource = [archive mainResource];
1381 NSURLRequest *request = [self _webDataRequestForData:[mainResource data]
1382 MIMEType:[mainResource MIMEType]
1383 textEncodingName:[mainResource textEncodingName]
1384 baseURL:[mainResource URL]
1385 unreachableURL:nil];
1386 [[self _frameLoader] _loadRequest:request archive:archive];
1392 [[self _frameLoader] stopLoading];
1397 [[self _frameLoader] reload];
1400 - (WebFrame *)findFrameNamed:(NSString *)name
1402 return Frame([[self _bridge] findFrameNamed:name]);
1405 - (WebFrame *)parentFrame
1407 return [[Frame([[self _bridge] parent]) retain] autorelease];
1410 - (NSArray *)childFrames
1412 NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
1413 for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
1414 [children addObject:child];
1421 @implementation WebFrame (WebFrameLoaderClient)
1423 - (void)_resetBackForwardList
1425 // Note this doesn't verify the current load type as a b/f operation because it is called from
1426 // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1427 ASSERT(self == [[self webView] mainFrame]);
1428 WebHistoryItem *resetItem = _private->currentItem;
1430 [[[self webView] backForwardList] goToItem:resetItem];
1433 - (void)_invalidateCurrentItemPageCache
1435 // When we are pre-commit, the currentItem is where the pageCache data resides
1436 NSDictionary *pageCache = [_private->currentItem pageCache];
1438 [[self _bridge] invalidatePageCache:pageCache];
1440 // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
1441 [_private->currentItem setHasPageCache:NO];
1444 - (BOOL)_provisionalItemIsTarget
1446 return [_private->provisionalItem isTargetItem];
1449 - (BOOL)_loadProvisionalItemFromPageCache
1451 WebHistoryItem *item = _private->provisionalItem;
1452 if (![item hasPageCache])
1454 NSDictionary *pageCache = [item pageCache];
1455 if (![pageCache objectForKey:WebCorePageCacheStateKey])
1457 LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
1458 [[self provisionalDataSource] _loadFromPageCache:pageCache];
1462 - (BOOL)_privateBrowsingEnabled
1464 return [[[self webView] preferences] privateBrowsingEnabled];
1467 - (void)_makeDocumentView
1469 NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[self dataSource]];
1473 // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
1474 WebFrameView *v = _private->webFrameView;
1475 [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
1476 [self _updateBackground];
1477 [_private->bridge installInFrame:[v _scrollView]];
1479 // Call setDataSource on the document view after it has been placed in the view hierarchy.
1480 // This what we for the top-level view, so should do this for views in subframes as well.
1481 [documentView setDataSource:[self dataSource]];
1484 - (void)_forceLayout
1486 NSView <WebDocumentView> *view = [[self frameView] documentView];
1487 if ([view isKindOfClass:[WebHTMLView class]])
1488 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
1489 [view setNeedsLayout:YES];
1493 - (void)_updateHistoryForCommit
1495 WebFrameLoadType type = [[self _frameLoader] loadType];
1496 if (isBackForwardLoadType(type) ||
1497 (type == WebFrameLoadTypeReload && [[self provisionalDataSource] unreachableURL] != nil)) {
1498 // Once committed, we want to use current item for saving DocState, and
1499 // the provisional item for restoring state.
1500 // Note previousItem must be set before we close the URL, which will
1501 // happen when the data source is made non-provisional below
1502 [_private setPreviousItem:_private->currentItem];
1503 ASSERT(_private->provisionalItem);
1504 [_private setCurrentItem:_private->provisionalItem];
1505 [_private setProvisionalItem:nil];
1509 - (void)_updateHistoryForReload
1511 WebHistoryItem *currItem = _private->currentItem;
1512 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
1513 [currItem setHasPageCache:NO];
1514 if ([[self _frameLoader] loadType] == WebFrameLoadTypeReload)
1515 [self _saveScrollPositionAndViewStateToItem:currItem];
1516 WebDataSource *dataSource = [self dataSource];
1517 NSURLRequest *request = [dataSource request];
1518 // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
1519 if ([request _webDataRequestUnreachableURL] == nil)
1520 [currItem setURL:[request URL]];
1521 // Update the last visited time. Mostly interesting for URL autocompletion statistics.
1522 NSURL *URL = [[[[dataSource _documentLoader] originalRequestCopy] URL] _webkit_canonicalize];
1523 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
1524 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
1526 [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
1529 - (void)_updateHistoryForStandardLoad
1531 WebDataSource *dataSource = [self dataSource];
1532 if (![[dataSource _documentLoader] isClientRedirect]) {
1533 NSURL *URL = [dataSource _URLForHistory];
1534 if (URL && ![URL _web_isEmpty]) {
1535 ASSERT([self webView]);
1536 if (![[[self webView] preferences] privateBrowsingEnabled]) {
1537 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
1538 if ([dataSource pageTitle])
1539 [entry setTitle:[dataSource pageTitle]];
1541 [self _addBackForwardItemClippedAtTarget:YES];
1544 NSURLRequest *request = [dataSource request];
1546 // Update the URL in the BF list that we made before the redirect, unless
1547 // this is alternate content for an unreachable URL (we want the BF list
1548 // item to remember the unreachable URL in case it becomes reachable later).
1549 if ([request _webDataRequestUnreachableURL] == nil) {
1550 [_private->currentItem setURL:[request URL]];
1552 // clear out the form data so we don't repost it to the wrong place if we
1553 // ever go back/forward to this item
1554 [_private->currentItem _setFormInfoFromRequest:request];
1556 // We must also clear out form data so we don't try to restore it into the incoming page,
1562 - (void)_updateHistoryForBackForwardNavigation
1564 // Must grab the current scroll position before disturbing it
1565 [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
1568 - (void)_updateHistoryForInternalLoad
1570 // Add an item to the item tree for this frame
1571 ASSERT(![[[self _frameLoader] documentLoader] isClientRedirect]);
1572 WebFrame *parentFrame = [self parentFrame];
1574 WebHistoryItem *parentItem = parentFrame->_private->currentItem;
1575 // The only case where parentItem==nil should be when a parent frame loaded an
1576 // empty URL, which doesn't set up a current item in that parent.
1578 [parentItem addChildItem:[self _createItem:YES]];
1580 // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
1581 // for a top-level frame, but that was a likely explanation for those crashes,
1582 // so let's guard against it.
1583 // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
1584 LOG_ERROR("no parent frame in transitionToCommitted:, WebFrameLoadTypeInternal");
1588 - (LoadErrorResetToken *)_tokenForLoadErrorReset
1590 return (LoadErrorResetToken*)[[self _currentBackForwardListItemToResetTo] retain];
1593 - (void)_resetAfterLoadError:(LoadErrorResetToken *)token
1595 WebHistoryItem *item = (WebHistoryItem *)token;
1597 [[[self webView] backForwardList] goToItem:item];
1601 - (void)_doNotResetAfterLoadError:(LoadErrorResetToken *)token
1603 WebHistoryItem *item = (WebHistoryItem *)token;
1607 - (void)_dispatchDidHandleOnloadEventsForFrame
1609 WebView *webView = [self webView];
1610 [[webView _frameLoadDelegateForwarder] webView:webView didHandleOnloadEventsForFrame:self];
1613 - (void)_dispatchDidReceiveServerRedirectForProvisionalLoadForFrame
1615 WebView *webView = [self webView];
1616 [[webView _frameLoadDelegateForwarder] webView:webView
1617 didReceiveServerRedirectForProvisionalLoadForFrame:self];
1620 - (id)_dispatchIdentifierForInitialRequest:(NSURLRequest *)clientRequest fromDocumentLoader:(WebDocumentLoader *)loader
1622 WebView *webView = [self webView];
1623 id resourceLoadDelegate = [webView resourceLoadDelegate];
1625 if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
1626 return [resourceLoadDelegate webView:webView identifierForInitialRequest:clientRequest fromDataSource:dataSource(loader)];
1628 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:dataSource(loader)];
1631 - (NSURLRequest *)_dispatchResource:(id)identifier willSendRequest:(NSURLRequest *)clientRequest redirectResponse:(NSURLResponse *)redirectResponse fromDocumentLoader:(WebDocumentLoader *)loader
1633 WebView *webView = [self webView];
1634 id resourceLoadDelegate = [webView resourceLoadDelegate];
1636 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
1637 return [resourceLoadDelegate webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:dataSource(loader)];
1639 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:dataSource(loader)];
1642 - (void)_dispatchDidReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier fromDocumentLoader:(WebDocumentLoader *)loader
1644 WebView *webView = [self webView];
1645 id resourceLoadDelegate = [webView resourceLoadDelegate];
1647 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
1648 [resourceLoadDelegate webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1650 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1653 - (void)_dispatchDidCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier fromDocumentLoader:(WebDocumentLoader *)loader
1655 WebView *webView = [self webView];
1656 id resourceLoadDelegate = [webView resourceLoadDelegate];
1658 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
1659 [resourceLoadDelegate webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1661 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:dataSource(loader)];
1664 - (void)_dispatchResource:(id)identifier didReceiveResponse:(NSURLResponse *)r fromDocumentLoader:(WebDocumentLoader *)loader
1666 WebView *webView = [self webView];
1668 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
1669 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:dataSource(loader)];
1671 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:dataSource(loader)];
1674 - (void)_dispatchResource:(id)identifier didReceiveContentLength:(int)lengthReceived fromDocumentLoader:(WebDocumentLoader *)loader
1676 WebView *webView = [self webView];
1678 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
1679 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:dataSource(loader)];
1681 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:dataSource(loader)];
1684 - (void)_dispatchResource:(id)identifier didFinishLoadingFromDocumentLoader:(WebDocumentLoader *)loader
1686 WebView *webView = [self webView];
1688 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
1689 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:dataSource(loader)];
1691 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:dataSource(loader)];
1695 - (void)_dispatchResource:(id)identifier didFailLoadingWithError:error fromDocumentLoader:(WebDocumentLoader *)loader
1697 WebView *webView = [self webView];
1698 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:dataSource(loader)];
1701 - (void)_dispatchDidCancelClientRedirectForFrame
1703 WebView *webView = [self webView];
1704 [[webView _frameLoadDelegateForwarder] webView:webView didCancelClientRedirectForFrame:self];
1707 - (void)_dispatchWillPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date
1709 WebView *webView = [self webView];
1710 [[webView _frameLoadDelegateForwarder] webView:webView
1711 willPerformClientRedirectToURL:URL
1717 - (void)_dispatchDidChangeLocationWithinPageForFrame
1719 WebView *webView = [self webView];
1720 [[webView _frameLoadDelegateForwarder] webView:webView didChangeLocationWithinPageForFrame:self];
1723 - (void)_dispatchWillCloseFrame
1725 WebView *webView = [self webView];
1726 [[webView _frameLoadDelegateForwarder] webView:webView willCloseFrame:self];
1729 - (void)_dispatchDidReceiveIcon:(NSImage *)icon
1731 WebView *webView = [self webView];
1732 [[webView _frameLoadDelegateForwarder] webView:webView didReceiveIcon:icon forFrame:self];
1735 - (void)_dispatchDidStartProvisionalLoadForFrame
1737 WebView *webView = [self webView];
1738 [[webView _frameLoadDelegateForwarder] webView:webView didStartProvisionalLoadForFrame:self];
1741 - (void)_dispatchDidReceiveTitle:(NSString *)title
1743 WebView *webView = [self webView];
1744 [[webView _frameLoadDelegateForwarder] webView:webView didReceiveTitle:title forFrame:self];
1747 - (void)_dispatchDidCommitLoadForFrame
1749 WebView *webView = [self webView];
1750 [[webView _frameLoadDelegateForwarder] webView:webView didCommitLoadForFrame:self];
1753 - (void)_dispatchDidFailProvisionalLoadWithError:(NSError *)error
1755 WebView *webView = [self webView];
1756 [[webView _frameLoadDelegateForwarder] webView:webView didFailProvisionalLoadWithError:error forFrame:self];
1759 - (void)_dispatchDidFailLoadWithError:(NSError *)error
1761 WebView *webView = [self webView];
1762 [[webView _frameLoadDelegateForwarder] webView:webView didFailLoadWithError:error forFrame:self];
1765 - (void)_dispatchDidFinishLoadForFrame
1767 WebView *webView = [self webView];
1768 [[webView _frameLoadDelegateForwarder] webView:webView didFinishLoadForFrame:self];
1771 - (void)_dispatchDidFirstLayoutInFrame
1773 WebView *webView = [self webView];
1774 [[webView _frameLoadDelegateForwarder] webView:webView didFirstLayoutInFrame:self];
1777 - (WebFrame *)_dispatchCreateWebViewWithRequest:(NSURLRequest *)request
1779 WebView *currentWebView = [self webView];
1780 id wd = [currentWebView UIDelegate];
1781 if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1782 return [[wd webView:currentWebView createWebViewWithRequest:request] mainFrame];
1784 return [[[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:request] mainFrame];
1787 - (void)_dispatchShow
1789 WebView *webView = [self webView];
1790 [[webView _UIDelegateForwarder] webViewShow:webView];
1793 - (void)_dispatchDecidePolicyForMIMEType:(NSString *)MIMEType request:(NSURLRequest *)request decisionListener:(WebPolicyDecisionListener *)decisionListener
1795 WebView *webView = [self webView];
1797 [[webView _policyDelegateForwarder] webView:webView decidePolicyForMIMEType:MIMEType request:request frame:self decisionListener:decisionListener];
1800 - (void)_dispatchDecidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(WebPolicyDecisionListener *)decisionListener
1802 WebView *webView = [self webView];
1803 [[webView _policyDelegateForwarder] webView:webView
1804 decidePolicyForNewWindowAction:action
1806 newFrameName:frameName
1807 decisionListener:decisionListener];
1810 - (void)_dispatchDecidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request decisionListener:(WebPolicyDecisionListener *)decisionListener
1812 WebView *webView = [self webView];
1813 [[webView _policyDelegateForwarder] webView:webView
1814 decidePolicyForNavigationAction:action
1817 decisionListener:decisionListener];
1820 - (void)_dispatchUnableToImplementPolicyWithError:(NSError *)error
1822 WebView *webView = [self webView];
1823 [[webView _policyDelegateForwarder] webView:webView unableToImplementPolicyWithError:error frame:self];
1826 - (void)_detachedFromParent1
1828 [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
1831 - (void)_detachedFromParent2
1833 [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
1834 [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
1837 - (void)_detachedFromParent3
1839 [_private setWebFrameView:nil];
1842 - (void)_detachedFromParent4
1844 _private->bridge = nil;
1847 - (void)_updateHistoryAfterClientRedirect
1849 // Clear out form data so we don't try to restore it into the incoming page. Must happen after
1850 // khtml has closed the URL and saved away the form state.
1851 WebHistoryItem *item = _private->currentItem;
1852 [item setDocumentState:nil];
1853 [item setScrollPoint:NSZeroPoint];
1856 - (void)_loadedFromPageCache
1858 // Release the resources kept in the page cache.
1859 // They will be reset when we leave this page.
1860 // The WebCore side of the page cache will have already been invalidated by
1861 // the bridge to prevent premature release.
1862 [_private->currentItem setHasPageCache:NO];
1865 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
1867 [WebDownload _downloadWithLoadingConnection:connection
1870 delegate:[[self webView] downloadDelegate]
1874 - (void)_setDocumentViewFromPageCache:(NSDictionary *)pageCache
1876 NSView <WebDocumentView> *cachedView = [pageCache objectForKey:WebPageCacheDocumentViewKey];
1877 ASSERT(cachedView != nil);
1878 [[self frameView] _setDocumentView:cachedView];
1881 - (void)_setCopiesOnScroll
1883 [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
1886 - (void)_dispatchDidLoadMainResourceForDocumentLoader:(WebDocumentLoader *)loader
1888 if ([WebScriptDebugServer listenerCount])
1889 [[WebScriptDebugServer sharedScriptDebugServer] webView:[self webView]
1890 didLoadMainResourceForDataSource:dataSource(loader)];
1893 - (void)_forceLayoutForNonHTML
1895 WebFrameView *thisView = [self frameView];
1896 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1897 ASSERT(thisDocumentView != nil);
1899 // Tell the just loaded document to layout. This may be necessary
1900 // for non-html content that needs a layout message.
1901 if (!([[self dataSource] _isDocumentHTML])) {
1902 [thisDocumentView setNeedsLayout:YES];
1903 [thisDocumentView layout];
1904 [thisDocumentView setNeedsDisplay:YES];
1908 - (void)_clearLoadingFromPageCacheForDocumentLoader:(WebDocumentLoader *)loader
1910 [dataSource(loader) _setLoadingFromPageCache:NO];
1913 - (BOOL)_isDocumentLoaderLoadingFromPageCache:(WebDocumentLoader *)loader
1915 return [dataSource(loader) _loadingFromPageCache];
1918 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL fromDocumentLoader:(WebDocumentLoader *)loader
1920 return [dataSource(loader) _archivedSubresourceForURL:URL];
1923 - (void)_makeRepresentationForDocumentLoader:(WebDocumentLoader *)loader
1925 [dataSource(loader) _makeRepresentation];