d49adf0f59a2a29a9c721327a23d5cf7d4834ca0
[WebKit-https.git] / WebKit / WebView / WebFrame.m
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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. 
16  *
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.
27  */
28
29 #import "WebFrameInternal.h"
30
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 "WebFormDataStream.h"
40 #import "WebFrameBridge.h"
41 #import "WebFrameLoadDelegate.h"
42 #import "WebFrameLoader.h"
43 #import "WebFrameViewInternal.h"
44 #import "WebHTMLRepresentationPrivate.h"
45 #import "WebHTMLViewInternal.h"
46 #import "WebHTMLViewPrivate.h"
47 #import "WebHistoryItemPrivate.h"
48 #import "WebHistoryPrivate.h"
49 #import "WebKitErrorsPrivate.h"
50 #import "WebKitLogging.h"
51 #import "WebKitNSStringExtras.h"
52 #import "WebKitStatisticsPrivate.h"
53 #import "WebNSObjectExtras.h"
54 #import "WebNSURLExtras.h"
55 #import "WebNSURLRequestExtras.h"
56 #import "WebNetscapePluginEmbeddedView.h"
57 #import "WebNullPluginView.h"
58 #import "WebPlugin.h"
59 #import "WebPluginController.h"
60 #import "WebPreferencesPrivate.h"
61 #import "WebResourceLoadDelegate.h"
62 #import "WebResourcePrivate.h"
63 #import "WebScriptDebugDelegatePrivate.h"
64 #import "WebUIDelegate.h"
65 #import "WebViewInternal.h"
66 #import <WebKit/DOM.h>
67 #import <WebKitSystemInterface.h>
68 #import <objc/objc-runtime.h>
69
70 /*
71 Here is the current behavior matrix for four types of navigations:
72
73 Standard Nav:
74
75  Restore form state:   YES
76  Restore scroll and focus state:  YES
77  WF Cache policy: NSURLRequestUseProtocolCachePolicy
78  Add to back/forward list: YES
79  
80 Back/Forward:
81
82  Restore form state:   YES
83  Restore scroll and focus state:  YES
84  WF Cache policy: NSURLRequestReturnCacheDataElseLoad
85  Add to back/forward list: NO
86
87 Reload (meaning only the reload button):
88
89  Restore form state:   NO
90  Restore scroll and focus state:  YES
91  WF Cache policy: NSURLRequestReloadIgnoringCacheData
92  Add to back/forward list: NO
93
94 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
95
96  Restore form state:   NO
97  Restore scroll and focus state:  NO, reset to initial conditions
98  WF Cache policy: NSURLRequestReloadIgnoringCacheData
99  Add to back/forward list: NO
100 */
101
102 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
103 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
104 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
105
106 @interface WebFrame (ForwardDecls)
107 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
108 - (NSDictionary *)_actionInformationForLoadType:(FrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
109
110 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
111
112 - (WebHistoryItem *)_createItem:(BOOL)useOriginal;
113 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
114 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
115 @end
116
117 @interface WebFrame (FrameTraversal)
118 - (WebFrame *)_firstChildFrame;
119 - (WebFrame *)_lastChildFrame;
120 - (unsigned)_childFrameCount;
121 - (WebFrame *)_previousSiblingFrame;
122 - (WebFrame *)_nextSiblingFrame;
123 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
124 @end
125
126 @interface NSView (WebFramePluginHosting)
127 - (void)setWebFrame:(WebFrame *)webFrame;
128 @end
129
130 @interface WebFramePrivate : NSObject
131 {
132 @public
133     WebFrameView *webFrameView;
134
135     WebFrameBridge *bridge;
136     WebHistoryItem *currentItem;        // BF item for our current content
137     WebHistoryItem *provisionalItem;    // BF item for where we're trying to go
138                                         // (only known when navigating to a pre-existing BF item)
139     WebHistoryItem *previousItem;       // BF item for previous content, see _itemForSavingDocState
140
141     WebScriptDebugger *scriptDebugger;
142     id internalLoadDelegate;
143     
144     NSMutableSet *plugInViews;
145     NSMutableSet *inspectors;
146 }
147
148 - (void)setWebFrameView:(WebFrameView *)v;
149
150 - (void)setProvisionalItem:(WebHistoryItem *)item;
151 - (void)setPreviousItem:(WebHistoryItem *)item;
152 - (void)setCurrentItem:(WebHistoryItem *)item;
153
154 @end
155
156 @implementation WebFramePrivate
157
158 - (void)dealloc
159 {
160     [webFrameView release];
161
162     [currentItem release];
163     [provisionalItem release];
164     [previousItem release];
165     
166     [scriptDebugger release];
167     
168     [inspectors release];
169
170     ASSERT(plugInViews == nil);
171     
172     [super dealloc];
173 }
174
175 - (void)setWebFrameView:(WebFrameView *)v 
176
177     [v retain];
178     [webFrameView release];
179     webFrameView = v;
180 }
181
182 - (void)setProvisionalItem:(WebHistoryItem *)item
183 {
184     [item retain];
185     [provisionalItem release];
186     provisionalItem = item;
187 }
188
189 - (void)setPreviousItem:(WebHistoryItem *)item
190 {
191     [item retain];
192     [previousItem release];
193     previousItem = item;
194 }
195
196 - (void)setCurrentItem:(WebHistoryItem *)item
197 {
198     [item retain];
199     [currentItem release];
200     currentItem = item;
201 }
202
203 @end
204
205 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
206 {
207     return [(WebFrameBridge *)bridge webFrame];
208 }
209
210 @implementation WebFrame (FrameTraversal)
211
212 - (WebFrame *)_firstChildFrame
213 {
214     return Frame([[self _bridge] firstChild]);
215 }
216
217 - (WebFrame *)_lastChildFrame
218 {
219     return Frame([[self _bridge] lastChild]);
220 }
221
222 - (unsigned)_childFrameCount
223 {
224     return [[self _bridge] childCount];
225 }
226
227 - (WebFrame *)_previousSiblingFrame;
228 {
229     return Frame([[self _bridge] previousSibling]);
230 }
231
232 - (WebFrame *)_nextSiblingFrame;
233 {
234     return Frame([[self _bridge] nextSibling]);
235 }
236
237 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
238 {
239     return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
240 }
241
242 @end
243
244 @implementation WebFrame (WebInternal)
245
246 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
247 {
248     NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
249     NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
250     [request _webDataRequestSetData:data];
251     [request _webDataRequestSetEncoding:encodingName];
252     [request _webDataRequestSetBaseURL:URL];
253     [request _webDataRequestSetUnreachableURL:unreachableURL];
254     [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
255     return request;
256 }
257
258 // helper method used in various nav cases below
259 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
260 {
261     if ([[self dataSource] _URLForHistory] != nil) {
262         WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
263         LOG (BackForward, "for frame %@, adding item  %@\n", [self name], bfItem);
264         [[[self webView] backForwardList] addItem:bfItem];
265     }
266 }
267
268 - (void)_addHistoryItemForFragmentScroll
269 {
270     [self _addBackForwardItemClippedAtTarget:NO];
271 }
272
273 - (void)_didFinishLoad
274 {
275     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];    
276 }
277
278 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
279 {
280     WebDataSource *dataSrc = [self dataSource];
281     NSURLRequest *request;
282     NSURL *unreachableURL = [dataSrc unreachableURL];
283     NSURL *URL;
284     NSURL *originalURL;
285     WebHistoryItem *bfItem;
286
287     if (useOriginal)
288         request = [[dataSrc _documentLoader] originalRequestCopy];
289     else
290         request = [dataSrc request];
291
292     if (unreachableURL != nil) {
293         URL = unreachableURL;
294         originalURL = unreachableURL;
295     } else {
296         URL = [request URL];
297         originalURL = [[[dataSrc _documentLoader] originalRequestCopy] URL];
298     }
299
300     LOG (History, "creating item for %@", request);
301     
302     // Frames that have never successfully loaded any content
303     // may have no URL at all. Currently our history code can't
304     // deal with such things, so we nip that in the bud here.
305     // Later we may want to learn to live with nil for URL.
306     // See bug 3368236 and related bugs for more information.
307     if (URL == nil) {
308         URL = [NSURL URLWithString:@"about:blank"];
309     }
310     if (originalURL == nil) {
311         originalURL = [NSURL URLWithString:@"about:blank"];
312     }
313     
314     bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
315     [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
316
317     // save form state if this is a POST
318     [bfItem _setFormInfoFromRequest:request];
319
320     // Set the item for which we will save document state
321     [_private setPreviousItem:_private->currentItem];
322     [_private setCurrentItem:bfItem];
323
324     return bfItem;
325 }
326
327 /*
328     In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.  
329     The item that was the target of the user's navigation is designated as the "targetItem".  
330     When this method is called with doClip=YES we're able to create the whole tree except for the target's children, 
331     which will be loaded in the future.  That part of the tree will be filled out as the child loads are committed.
332 */
333 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
334 {
335     WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
336
337     [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
338     if (!(doClip && self == targetFrame)) {
339         // save frame state for items that aren't loading (khtml doesn't save those)
340         [_private->bridge saveDocumentState];
341
342         for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
343             [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
344     }
345     if (self == targetFrame)
346         [bfItem setIsTargetItem:YES];
347
348     return bfItem;
349 }
350
351 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
352 {
353     return Frame([[self _bridge] childFrameNamed:name]);
354 }
355
356 - (void)_detachChildren
357 {
358     // FIXME: is it really necessary to do this in reverse order any more?
359     WebFrame *child = [self _lastChildFrame];
360     WebFrame *prev = [child _previousSiblingFrame];
361     for (; child; child = prev, prev = [child _previousSiblingFrame])
362         [child _detachFromParent];
363 }
364
365 - (void)_detachFromParent
366 {
367     WebFrameBridge *bridge = [_private->bridge retain];
368
369     [bridge closeURL];
370     [self stopLoading];
371
372     [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
373     [self _detachChildren];
374     [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
375
376     [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
377
378     [[self _frameLoader] clearDataSource];
379     [_private setWebFrameView:nil];
380
381     [self retain]; // retain self temporarily because dealloc can re-enter this method
382
383     [[[self parentFrame] _bridge] removeChild:bridge];
384
385     [bridge close];
386     [bridge release];
387
388     bridge = nil;
389     _private->bridge = nil;
390
391     [self release];
392 }
393
394 - (BOOL)_canCachePage
395 {
396     return [[[self webView] backForwardList] _usesPageCache];
397 }
398
399 - (void)_purgePageCache
400 {
401     // This method implements the rule for purging the page cache.
402     unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
403     unsigned pagesCached = 0;
404     WebBackForwardList *backForwardList = [[self webView] backForwardList];
405     NSArray *backList = [backForwardList backListWithLimit: 999999];
406     WebHistoryItem *oldestNonSnapbackItem = nil;
407     
408     unsigned i;
409     for (i = 0; i < [backList count]; i++){
410         WebHistoryItem *item = [backList objectAtIndex: i];
411         if ([item hasPageCache]){
412             if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
413                 oldestNonSnapbackItem = item;
414             pagesCached++;
415         }
416     }
417
418     // Snapback items are never directly purged here.
419     if (pagesCached >= sizeLimit) {
420         LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
421         [oldestNonSnapbackItem setHasPageCache:NO];
422     }
423 }
424
425 + (CFAbsoluteTime)_timeOfLastCompletedLoad
426 {
427     return [WebFrameLoader timeOfLastCompletedLoad];
428 }
429
430 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
431 {
432     NSMutableDictionary *pageCache;
433
434     [item setHasPageCache: YES];
435
436     if (![_private->bridge saveDocumentToPageCache]){
437         [item setHasPageCache: NO];
438         return NO;
439     }
440     else {
441         pageCache = [item pageCache];
442         [pageCache setObject:[NSDate date]  forKey: WebPageCacheEntryDateKey];
443         [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
444         [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
445     }
446     return YES;
447 }
448
449 - (void)_provisionalLoadStarted
450 {
451     FrameLoadType loadType = [[self _frameLoader] loadType];
452     
453     // FIXME: This is OK as long as no one resizes the window,
454     // but in the case where someone does, it means garbage outside
455     // the occupied part of the scroll view.
456     [[[self frameView] _scrollView] setDrawsBackground:NO];
457     
458     // Cache the page, if possible.
459     // Don't write to the cache if in the middle of a redirect, since we will want to
460     // store the final page we end up on.
461     // No point writing to the cache on a reload or loadSame, since we will just write
462     // over it again when we leave that page.
463     WebHistoryItem *item = _private->currentItem;
464     if ([self _canCachePage]
465         && [_private->bridge canCachePage]
466         && item
467         && ![[self _frameLoader] isQuickRedirectComing]
468         && loadType != FrameLoadTypeReload 
469         && loadType != FrameLoadTypeReloadAllowingStaleData
470         && loadType != FrameLoadTypeSame
471         && ![[self dataSource] isLoading]
472         && ![[[self _frameLoader] documentLoader] isStopping]) {
473         if ([[[self dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]) {
474             if (![item pageCache]){
475                 // Add the items to this page's cache.
476                 if ([self _createPageCacheForItem:item]) {
477                     LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
478                     
479                     // See if any page caches need to be purged after the addition of this
480                     // new page cache.
481                     [self _purgePageCache];
482                 }
483                 else
484                     LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
485             }
486         } else
487             // Put the document into a null state, so it can be restored correctly.
488             [_private->bridge clear];
489     } else
490         LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
491 }
492
493 // Called after we send an openURL:... down to WebCore.
494 - (void)_opened
495 {
496     if ([[self _frameLoader] loadType] == FrameLoadTypeStandard && [[[self dataSource] _documentLoader] isClientRedirect]) {
497         // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
498         // khtml has closed the URL and saved away the form state.
499         WebHistoryItem *item = _private->currentItem;
500         [item setDocumentState:nil];
501         [item setScrollPoint:NSZeroPoint];
502     }
503
504     if ([[self dataSource] _loadingFromPageCache]){
505         // Force a layout to update view size and thereby update scrollbars.
506         NSView <WebDocumentView> *view = [[self frameView] documentView];
507         if ([view isKindOfClass:[WebHTMLView class]]) {
508             [(WebHTMLView *)view setNeedsToApplyStyles:YES];
509         }
510         [view setNeedsLayout: YES];
511         [view layout];
512
513         NSArray *responses = [[[self _frameLoader] documentLoader] responses];
514         NSURLResponse *response;
515         int i, count = [responses count];
516         for (i = 0; i < count; i++){
517             response = [responses objectAtIndex: i];
518             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
519             NSError *error;
520             id identifier;
521             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
522             [[self _frameLoader] requestFromDelegateForRequest:request identifier:&identifier error:&error];
523             [[self _frameLoader] sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
524             [request release];
525         }
526         
527         // Release the resources kept in the page cache.  They will be
528         // reset when we leave this page.  The core side of the page cache
529         // will have already been invalidated by the bridge to prevent
530         // premature release.
531         [_private->currentItem setHasPageCache:NO];
532
533         [[[self _frameLoader] documentLoader] setPrimaryLoadComplete:YES];
534         // why only this frame and not parent frames?
535         [[self _frameLoader] checkLoadCompleteForThisFrame];
536     }
537 }
538
539 - (void)_handledOnloadEvents
540 {
541     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
542 }
543
544 // Called every time a resource is completely loaded, or an error is received.
545 - (void)_checkLoadComplete
546 {
547     ASSERT([self webView] != nil);
548
549     WebFrame *parent;
550     for (WebFrame *frame = self; frame; frame = parent) {
551         [frame retain];
552         [[frame _frameLoader] checkLoadCompleteForThisFrame];
553         parent = [frame parentFrame];
554         [frame release];
555     }
556 }
557
558 - (WebFrameBridge *)_bridge
559 {
560     return _private->bridge;
561 }
562
563 // helper method that determines whether the subframes described by the item's subitems
564 // match our own current frameset
565 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
566 {
567     NSArray *childItems = [item children];
568     int numChildItems = [childItems count];
569     int numChildFrames = [self _childFrameCount];
570     if (numChildFrames != numChildItems)
571         return NO;
572
573     int i;
574     for (i = 0; i < numChildItems; i++) {
575         NSString *itemTargetName = [[childItems objectAtIndex:i] target];
576         //Search recursive here?
577         if (![self _immediateChildFrameNamed:itemTargetName])
578             return NO; // couldn't match the i'th itemTarget
579     }
580
581     return YES; // found matches for all itemTargets
582 }
583
584 // Walk the frame tree and ensure that the URLs match the URLs in the item.
585 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
586 {
587     NSURL *currentURL = [[[self dataSource] request] URL];
588
589     if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
590         return NO;
591     
592     NSArray *childItems = [item children];
593     WebHistoryItem *childItem;
594     WebFrame *childFrame;
595     int i, count = [childItems count];
596     for (i = 0; i < count; i++){
597         childItem = [childItems objectAtIndex:i];
598         childFrame = [self _immediateChildFrameNamed:[childItem target]];
599         if (![childFrame _URLsMatchItem: childItem])
600             return NO;
601     }
602     
603     return YES;
604 }
605
606 // loads content into this frame, as specified by item
607 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)loadType
608 {
609     NSURL *itemURL = [item URL];
610     NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
611     NSURL *currentURL = [[[self dataSource] request] URL];
612     NSArray *formData = [item formData];
613
614     // Are we navigating to an anchor within the page?
615     // Note if we have child frames we do a real reload, since the child frames might not
616     // match our current frame structure, or they might not have the right content.  We could
617     // check for all that as an additional optimization.
618     // We also do not do anchor-style navigation if we're posting a form.
619     
620     // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
621     // Perhaps they should.
622     if (!formData && ![[self _frameLoader] shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
623     {
624 #if 0
625         // FIXME:  We need to normalize the code paths for anchor navigation.  Something
626         // like the following line of code should be done, but also accounting for correct
627         // updates to the back/forward list and scroll position.
628         // rjw 4/9/03 See 3223929.
629         [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
630 #endif
631         // must do this maintenance here, since we don't go through a real page reload
632         [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
633         // FIXME: form state might want to be saved here too
634
635         // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
636         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
637         [_private->bridge scrollToAnchorWithURL:[item URL]];
638     
639         // must do this maintenance here, since we don't go through a real page reload
640         [_private setCurrentItem:item];
641         [self _restoreScrollPositionAndViewState];
642
643         // Fake the URL change by updating the data source's request.  This will no longer
644         // be necessary if we do the better fix described above.
645         [[[self _frameLoader] documentLoader] replaceRequestURLForAnchorScrollWithURL:itemURL];
646         
647         [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
648                                didChangeLocationWithinPageForFrame:self];
649         [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
650     } else {
651         // Remember this item so we can traverse any child items as child frames load
652         [_private setProvisionalItem:item];
653
654         WebDataSource *newDataSource;
655         BOOL inPageCache = NO;
656         
657         // Check if we'll be using the page cache.  We only use the page cache
658         // if one exists and it is less than _backForwardCacheExpirationInterval
659         // seconds old.  If the cache is expired it gets flushed here.
660         if ([item hasPageCache]){
661             NSDictionary *pageCache = [item pageCache];
662             NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
663             NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
664
665             if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
666                 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
667                 [[self _frameLoader] loadDataSource:newDataSource withLoadType:loadType formState:nil];   
668                 inPageCache = YES;
669             }
670             else {
671                 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]);
672                 [item setHasPageCache: NO];
673             }
674         }
675         
676         if (!inPageCache) {
677             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
678             [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
679
680             // If this was a repost that failed the page cache, we might try to repost the form.
681             NSDictionary *action;
682             if (formData) {
683                 [request setHTTPMethod:@"POST"];
684                 [request _web_setHTTPReferrer:[item formReferrer]];
685                 webSetHTTPBody(request, formData);
686                 [request _web_setHTTPContentType:[item formContentType]];
687
688                 // Slight hack to test if the WF cache contains the page we're going to.  We want
689                 // to know this before talking to the policy delegate, since it affects whether we
690                 // show the DoYouReallyWantToRepost nag.
691                 //
692                 // This trick has a small bug (3123893) where we might find a cache hit, but then
693                 // have the item vanish when we try to use it in the ensuing nav.  This should be
694                 // extremely rare, but in that case the user will get an error on the navigation.
695                 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
696                 NSURLResponse *synchResponse = nil;
697                 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
698                 if (synchResponse == nil) { 
699                     // Not in WF cache
700                     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
701                     action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
702                 } else {
703                     // We can use the cache, don't use navType=resubmit
704                     action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
705                 }
706             } else {
707                 switch (loadType) {
708                     case FrameLoadTypeReload:
709                         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
710                         break;
711                     case FrameLoadTypeBack:
712                     case FrameLoadTypeForward:
713                     case FrameLoadTypeIndexedBackForward:
714                         if (![[itemURL scheme] isEqual:@"https"])
715                             [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
716                         break;
717                     case FrameLoadTypeStandard:
718                     case FrameLoadTypeInternal:
719                         // no-op: leave as protocol default
720                         // FIXME:  I wonder if we ever hit this case
721                         break;
722                     case FrameLoadTypeSame:
723                     case FrameLoadTypeReloadAllowingStaleData:
724                     default:
725                         ASSERT_NOT_REACHED();
726                 }
727
728                 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
729             }
730
731             [[self _frameLoader] _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
732             [request release];
733         }
734     }
735 }
736
737 // The general idea here is to traverse the frame tree and the item tree in parallel,
738 // tracking whether each frame already has the content the item requests.  If there is
739 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
740 // reload that frame, and all its kids.
741 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(FrameLoadType)type
742 {
743     NSURL *itemURL = [item URL];
744     NSURL *currentURL = [[[self dataSource] request] URL];
745
746     // Always reload the target frame of the item we're going to.  This ensures that we will
747     // do -some- load for the transition, which means a proper notification will be posted
748     // to the app.
749     // The exact URL has to match, including fragment.  We want to go through the _load
750     // method, even if to do a within-page navigation.
751     // The current frame tree and the frame tree snapshot in the item have to match.
752     if (![item isTargetItem] &&
753         [itemURL isEqual:currentURL] &&
754         (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
755         [self _childFramesMatchItem:item])
756     {
757         // This content is good, so leave it alone and look for children that need reloading
758
759         // Save form state (works from currentItem, since prevItem is nil)
760         ASSERT(!_private->previousItem);
761         [_private->bridge saveDocumentState];
762         [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
763         
764         [_private setCurrentItem:item];
765
766         // Restore form state (works from currentItem)
767         [_private->bridge restoreDocumentState];
768         // Restore the scroll position (taken in favor of going back to the anchor)
769         [self _restoreScrollPositionAndViewState];
770         
771         NSArray *childItems = [item children];
772         int numChildItems = childItems ? [childItems count] : 0;
773         int i;
774         for (i = numChildItems - 1; i >= 0; i--) {
775             WebHistoryItem *childItem = [childItems objectAtIndex:i];
776             NSString *childName = [childItem target];
777             WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
778             ASSERT(fromChildItem || [fromItem isTargetItem]);
779             WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
780             ASSERT(childFrame);
781             [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
782         }
783     } else {
784         // We need to reload the content
785         [self _loadItem:item withLoadType:type];
786     }
787 }
788
789 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
790 // This includes recursion to handle loading into framesets properly
791 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)type
792 {
793     ASSERT(![self parentFrame]);
794     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
795     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
796     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
797     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
798     if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {    
799         WebBackForwardList *backForwardList = [[self webView] backForwardList];
800         WebHistoryItem *currItem = [backForwardList currentItem];
801         // Set the BF cursor before commit, which lets the user quickly click back/forward again.
802         // - plus, it only makes sense for the top level of the operation through the frametree,
803         // as opposed to happening for some/one of the page commits that might happen soon
804         [backForwardList goToItem:item];
805         [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
806     }
807 }
808
809 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
810 {
811     switch ([event type]) {
812         case NSLeftMouseDown:
813         case NSRightMouseDown:
814         case NSOtherMouseDown:
815         case NSLeftMouseUp:
816         case NSRightMouseUp:
817         case NSOtherMouseUp:
818         {
819             NSView *topViewInEventWindow = [[event window] contentView];
820             NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
821             while (viewContainingPoint != nil) {
822                 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
823                     break;
824                 }
825                 viewContainingPoint = [viewContainingPoint superview];
826             }
827             if (viewContainingPoint != nil) {
828                 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
829                 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
830         
831                 return [NSDictionary dictionaryWithObjectsAndKeys:
832                     [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
833                     elementInfo, WebActionElementKey,
834                     [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
835                     [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
836                     URL, WebActionOriginalURLKey,
837                     nil];
838             }
839         }
840             
841         // fall through
842         
843         default:
844             return [NSDictionary dictionaryWithObjectsAndKeys:
845                 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
846                 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
847                 URL, WebActionOriginalURLKey,
848                 nil];
849     }
850 }
851
852 -(NSDictionary *)_actionInformationForLoadType:(FrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
853 {
854     WebNavigationType navType;
855     if (isFormSubmission) {
856         navType = WebNavigationTypeFormSubmitted;
857     } else if (event == nil) {
858         if (loadType == FrameLoadTypeReload)
859             navType = WebNavigationTypeReload;
860         else if (isBackForwardLoadType(loadType))
861             navType = WebNavigationTypeBackForward;
862         else
863             navType = WebNavigationTypeOther;
864     } else {
865         navType = WebNavigationTypeLinkClicked;
866     }
867     return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
868 }
869
870 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
871 {
872     WebHistoryItem *parentItem = _private->currentItem;
873     NSArray *childItems = [parentItem children];
874     FrameLoadType loadType = [[self _frameLoader] loadType];
875     FrameLoadType childLoadType = FrameLoadTypeInternal;
876     WebHistoryItem *childItem = nil;
877
878     // If we're moving in the backforward list, we might want to replace the content
879     // of this child frame with whatever was there at that point.
880     // Reload will maintain the frame contents, LoadSame will not.
881     if (childItems &&
882         (isBackForwardLoadType(loadType)
883          || loadType == FrameLoadTypeReload
884          || loadType == FrameLoadTypeReloadAllowingStaleData))
885     {
886         childItem = [parentItem childItemWithName:[childFrame name]];
887         if (childItem) {
888             // Use the original URL to ensure we get all the side-effects, such as
889             // onLoad handlers, of any redirects that happened. An example of where
890             // this is needed is Radar 3213556.
891             URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
892             // These behaviors implied by these loadTypes should apply to the child frames
893             childLoadType = loadType;
894
895             if (isBackForwardLoadType(loadType))
896                 // For back/forward, remember this item so we can traverse any child items as child frames load
897                 [childFrame->_private setProvisionalItem:childItem];
898             else
899                 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
900                 [childFrame->_private setCurrentItem:childItem];
901         }
902     }
903
904     WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
905     if (archive) {
906         [childFrame loadArchive:archive];
907     } else {
908         [[childFrame _frameLoader] loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
909     }
910 }
911
912 - (void)_setTitle:(NSString *)title
913 {
914     [_private->currentItem setTitle:title];
915 }
916
917 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
918 {
919     if (item) {
920         NSView <WebDocumentView> *docView = [[self frameView] documentView];
921         NSView *parent = [docView superview];
922         // we might already be detached when this is called from detachFromParent, in which
923         // case we don't want to override real data earlier gathered with (0,0)
924         if (parent) {
925             NSPoint point;
926             if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
927                 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
928                 // ScrollView instead of using the one provided by the WebFrame
929                 point = [(id <_WebDocumentViewState>)docView scrollPoint];
930                 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
931             } else {
932                 // Parent is the clipview of the DynamicScrollView the WebFrame installs
933                 ASSERT([parent isKindOfClass:[NSClipView class]]);
934                 point = [parent bounds].origin;
935             }
936             [item setScrollPoint:point];
937         }
938     }
939 }
940
941 - (void)_defersCallbacksChanged
942 {
943     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
944         [[frame _frameLoader] defersCallbacksChanged];
945 }
946
947 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
948 {
949     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
950         [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
951 }
952
953 - (void)_viewDidMoveToHostWindow
954 {
955     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
956         [[[frame frameView] documentView] viewDidMoveToHostWindow];
957 }
958
959 - (void)_addChild:(WebFrame *)child
960 {
961     [[self _bridge] appendChild:[child _bridge]];
962     [[[child dataSource] _documentLoader] setOverrideEncoding:[[[self dataSource] _documentLoader] overrideEncoding]];  
963 }
964
965 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
966 // item, because we optimistically move it right away at the start of the operation. But when
967 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
968 // Return the item that we would reset to, so we can decide later whether to actually reset.
969 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
970 {
971     if (isBackForwardLoadType([[self _frameLoader] loadType]) && self == [[self webView] mainFrame])
972         return _private->currentItem;
973     return nil;
974 }
975
976 - (WebHistoryItem *)_itemForSavingDocState
977 {
978     // For a standard page load, we will have a previous item set, which will be used to
979     // store the form state.  However, in some cases we will have no previous item, and
980     // the current item is the right place to save the state.  One example is when we
981     // detach a bunch of frames because we are navigating from a site with frames to
982     // another site.  Another is when saving the frame state of a frame that is not the
983     // target of the current navigation (if we even decide to save with that granularity).
984
985     // Because of previousItem's "masking" of currentItem for this purpose, it's important
986     // that previousItem be cleared at the end of a page transition.  We leverage the
987     // checkLoadComplete recursion to achieve this goal.
988
989     return _private->previousItem ? _private->previousItem : _private->currentItem;
990 }
991
992 - (WebHistoryItem *)_itemForRestoringDocState
993 {
994     switch ([[self _frameLoader] loadType]) {
995         case FrameLoadTypeReload:
996         case FrameLoadTypeReloadAllowingStaleData:
997         case FrameLoadTypeSame:
998         case FrameLoadTypeReplace:
999             // Don't restore any form state on reload or loadSame
1000             return nil;
1001         case FrameLoadTypeBack:
1002         case FrameLoadTypeForward:
1003         case FrameLoadTypeIndexedBackForward:
1004         case FrameLoadTypeInternal:
1005         case FrameLoadTypeStandard:
1006             return _private->currentItem;
1007     }
1008     ASSERT_NOT_REACHED();
1009     return nil;
1010 }
1011
1012 // Walk the frame tree, telling all frames to save their form state into their current
1013 // history item.
1014 - (void)_saveDocumentAndScrollState
1015 {
1016     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1017         [[frame _bridge] saveDocumentState];
1018         [frame _saveScrollPositionAndViewStateToItem:frame->_private->currentItem];
1019     }
1020 }
1021
1022 // used to decide to use loadType=Same
1023 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
1024 {
1025     WebHistoryItem *item = _private->currentItem;
1026     NSString* URLString = [URL _web_originalDataAsString];
1027     return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
1028 }    
1029
1030 // Return next frame to be traversed, visiting children after parent
1031 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
1032 {
1033     return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
1034 }
1035
1036 // Return previous frame to be traversed, exact reverse order of _nextFrame
1037 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
1038 {
1039     return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
1040 }
1041
1042 - (BOOL)_shouldCreateRenderers
1043 {
1044     return [_private->bridge shouldCreateRenderers];
1045 }
1046
1047 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
1048 {
1049     if (!recurse)
1050         return [[self _bridge] numPendingOrLoadingRequests];
1051
1052     int num = 0;
1053     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1054         num += [[frame _bridge] numPendingOrLoadingRequests];
1055
1056     return num;
1057 }
1058
1059 - (void)_reloadForPluginChanges
1060 {
1061     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1062         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1063         if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
1064             [frame reload];
1065     }
1066 }
1067
1068 - (void)_attachScriptDebugger
1069 {
1070     if (!_private->scriptDebugger)
1071         _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
1072 }
1073
1074 - (void)_detachScriptDebugger
1075 {
1076     if (_private->scriptDebugger) {
1077         id old = _private->scriptDebugger;
1078         _private->scriptDebugger = nil;
1079         [old release];
1080     }
1081 }
1082
1083 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
1084 {
1085     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1086         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1087         if ([documentView isKindOfClass:[WebHTMLView class]])
1088             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1089     }
1090 }
1091
1092 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
1093 {
1094     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1095         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1096         if ([documentView isKindOfClass:[WebHTMLView class]])
1097             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1098     }
1099 }
1100
1101 - (void)_didReceiveServerRedirectForProvisionalLoadForFrame
1102 {
1103     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1104         didReceiveServerRedirectForProvisionalLoadForFrame:self];
1105 }
1106
1107 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
1108 {
1109     self = [super init];
1110     if (!self)
1111         return nil;
1112
1113     _private = [[WebFramePrivate alloc] init];
1114
1115     _private->bridge = bridge;
1116
1117     if (fv) {
1118         [_private setWebFrameView:fv];
1119         [fv _setWebFrame:self];
1120     }
1121     
1122     ++WebFrameCount;
1123     
1124     return self;
1125 }
1126
1127 - (NSArray *)_documentViews
1128 {
1129     NSMutableArray *result = [NSMutableArray array];
1130     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1131         id docView = [[frame frameView] documentView];
1132         if (docView)
1133             [result addObject:docView];
1134     }
1135         
1136     return result;
1137 }
1138
1139 - (void)_updateBackground
1140 {
1141     BOOL drawsBackground = [[self webView] drawsBackground];
1142     NSColor *backgroundColor = [[self webView] backgroundColor];
1143
1144     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1145         // Never call setDrawsBackground:YES here on the scroll view or the background color will
1146         // flash between pages loads. setDrawsBackground:YES will be called in _frameLoadCompleted.
1147         if (!drawsBackground)
1148             [[[frame frameView] _scrollView] setDrawsBackground:NO];
1149         [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
1150         id documentView = [[frame frameView] documentView];
1151         if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
1152             [documentView setDrawsBackground:drawsBackground];
1153         if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
1154             [documentView setBackgroundColor:backgroundColor];
1155         [[frame _bridge] setDrawsBackground:drawsBackground];
1156         [[frame _bridge] setBaseBackgroundColor:backgroundColor];
1157     }
1158 }
1159
1160 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
1161 {
1162     _private->internalLoadDelegate = internalLoadDelegate;
1163 }
1164
1165 - (id)_internalLoadDelegate
1166 {
1167     return _private->internalLoadDelegate;
1168 }
1169
1170 - (void)_safeLoadURL:(NSURL *)URL
1171 {
1172    // Call the bridge because this is where our security checks are made.
1173     [[self _bridge] loadURL:URL 
1174                     referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
1175                       reload:NO
1176                  userGesture:YES       
1177                       target:nil
1178              triggeringEvent:[NSApp currentEvent]
1179                         form:nil 
1180                   formValues:nil];
1181 }
1182
1183 - (void)_unmarkAllMisspellings
1184 {
1185     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1186         [[frame _bridge] unmarkAllMisspellings];
1187 }
1188
1189 - (BOOL)_hasSelection
1190 {
1191     id documentView = [[self frameView] documentView];    
1192     
1193     // optimization for common case to avoid creating potentially large selection string
1194     if ([documentView isKindOfClass:[WebHTMLView class]]) {
1195         DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
1196         return selectedDOMRange && ![selectedDOMRange collapsed];
1197     }
1198     
1199     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1200         return [[documentView selectedString] length] > 0;
1201     
1202     return NO;
1203 }
1204
1205 - (void)_clearSelection
1206 {
1207     id documentView = [[self frameView] documentView];    
1208     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1209         [documentView deselectAll];
1210 }
1211
1212 #ifndef NDEBUG
1213
1214 - (BOOL)_atMostOneFrameHasSelection;
1215 {
1216     // FIXME: 4186050 is one known case that makes this debug check fail
1217     BOOL found = NO;
1218     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1219         if ([frame _hasSelection]) {
1220             if (found)
1221                 return NO;
1222             found = YES;
1223         }
1224     }
1225
1226     return YES;
1227 }
1228 #endif
1229
1230 - (WebFrame *)_findFrameWithSelection
1231 {
1232     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1233         if ([frame _hasSelection])
1234             return frame;
1235
1236     return nil;
1237 }
1238
1239 - (void)_clearSelectionInOtherFrames
1240 {
1241     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
1242     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
1243     // notification sent when the first responder changes in general (Radar 2573089).
1244     WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
1245     if (frameWithSelection != self)
1246         [frameWithSelection _clearSelection];
1247
1248     // While we're in the general area of selection and frames, check that there is only one now.
1249     ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
1250 }
1251
1252 - (BOOL)_subframeIsLoading
1253 {
1254     // It's most likely that the last added frame is the last to load so we walk backwards.
1255     for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1256         if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1257             return YES;
1258     return NO;
1259 }
1260
1261 - (void)_addPlugInView:(NSView *)plugInView
1262 {
1263     ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
1264     ASSERT(![_private->plugInViews containsObject:plugInView]);
1265     
1266     if (!_private->plugInViews)
1267         _private->plugInViews = [[NSMutableSet alloc] init];
1268         
1269     [plugInView setWebFrame:self];
1270     [_private->plugInViews addObject:plugInView];
1271 }
1272
1273 - (void)_removeAllPlugInViews
1274 {
1275     if (!_private->plugInViews)
1276         return;
1277     
1278     [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
1279     [_private->plugInViews release];
1280     _private->plugInViews = nil;
1281 }
1282
1283 // This is called when leaving a page or closing the WebView
1284 - (void)_willCloseURL
1285 {
1286     [self _removeAllPlugInViews];
1287 }
1288
1289 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1290 {
1291     [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
1292     
1293     if ([[self _frameLoader] loadType] == FrameLoadTypeReload)
1294         [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1295     
1296     // Don't set the cookie policy URL if it's already been set.
1297     if ([request mainDocumentURL] == nil) {
1298         if (mainResource && (self == [[self webView] mainFrame] || f))
1299             [request setMainDocumentURL:[request URL]];
1300         else
1301             [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
1302     }
1303     
1304     if (mainResource)
1305         [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
1306 }
1307
1308 - (BOOL)_isMainFrame
1309 {
1310     return self == [[self webView] mainFrame];
1311 }
1312
1313 - (void)_addInspector:(WebInspector *)inspector
1314 {
1315     if (!_private->inspectors)
1316         _private->inspectors = [[NSMutableSet alloc] init];
1317     ASSERT(![_private->inspectors containsObject:inspector]);
1318     [_private->inspectors addObject:inspector];
1319 }
1320
1321 - (void)_removeInspector:(WebInspector *)inspector
1322 {
1323     ASSERT([_private->inspectors containsObject:inspector]);
1324     [_private->inspectors removeObject:inspector];
1325 }
1326
1327 - (WebFrameLoader *)_frameLoader
1328 {
1329     return [_private->bridge frameLoader];
1330 }
1331
1332 - (void)_prepareForDataSourceReplacement
1333 {
1334     if (![[self _frameLoader] dataSource]) {
1335         ASSERT(![self _childFrameCount]);
1336         return;
1337     }
1338     
1339     // Make sure that any work that is triggered by resigning first reponder can get done.
1340     // The main example where this came up is the textDidEndEditing that is sent to the
1341     // FormsDelegate (3223413).  We need to do this before _detachChildren, since that will
1342     // remove the views as a side-effect of freeing the bridge, at which point we can't
1343     // post the FormDelegate messages.
1344     //
1345     // Note that this can also take FirstResponder away from a child of our frameView that
1346     // is not in a child frame's view.  This is OK because we are in the process
1347     // of loading new content, which will blow away all editors in this top frame, and if
1348     // a non-editor is firstReponder it will not be affected by endEditingFor:.
1349     // Potentially one day someone could write a DocView whose editors were not all
1350     // replaced by loading new content, but that does not apply currently.
1351     NSView *frameView = [self frameView];
1352     NSWindow *window = [frameView window];
1353     NSResponder *firstResp = [window firstResponder];
1354     if ([firstResp isKindOfClass:[NSView class]]
1355         && [(NSView *)firstResp isDescendantOf:frameView])
1356     {
1357         [window endEditingFor:firstResp];
1358     }
1359     
1360     [self _detachChildren];
1361 }
1362
1363 - (void)_frameLoadCompleted
1364 {
1365     // Note: Can be called multiple times.
1366     // Even if already complete, we might have set a previous item on a frame that
1367     // didn't do any data loading on the past transaction. Make sure to clear these out.
1368     NSScrollView *sv = [[self frameView] _scrollView];
1369     if ([[self webView] drawsBackground])
1370         [sv setDrawsBackground:YES];
1371     [_private setPreviousItem:nil];
1372 }
1373
1374 - (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader
1375 {
1376     return [(WebDocumentLoaderMac *)loader dataSource];
1377 }
1378
1379 - (WebDocumentLoader *)_createDocumentLoaderWithRequest:(NSURLRequest *)request
1380 {
1381     WebDocumentLoaderMac *loader = [[WebDocumentLoaderMac alloc] initWithRequest:request];
1382     
1383     WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader];
1384     [loader setDataSource:dataSource];
1385     [dataSource release];
1386
1387     return loader;
1388 }
1389
1390 /*
1391     There is a race condition between the layout and load completion that affects restoring the scroll position.
1392     We try to restore the scroll position at both the first layout and upon load completion.
1393
1394     1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1395        first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1396        jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
1397        which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1398     2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1399        fails.  We then successfully restore it when the layout happens.
1400  */
1401
1402 - (void)_restoreScrollPositionAndViewState
1403 {
1404     ASSERT(_private->currentItem);
1405     NSView <WebDocumentView> *docView = [[self frameView] documentView];
1406     NSPoint point = [_private->currentItem scrollPoint];
1407     if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {        
1408         id state = [_private->currentItem viewState];
1409         if (state) {
1410             [(id <_WebDocumentViewState>)docView setViewState:state];
1411         }
1412         
1413         [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1414     } else {
1415         [docView scrollPoint:point];
1416     }
1417 }
1418
1419 @end
1420
1421 @implementation WebFrame (WebPrivate)
1422
1423 // FIXME: this exists only as a convenience for Safari, consider moving there
1424 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
1425 {
1426     return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
1427 }
1428
1429 - (void)_setShouldCreateRenderers:(BOOL)f
1430 {
1431     [_private->bridge setShouldCreateRenderers:f];
1432 }
1433
1434 - (NSColor *)_bodyBackgroundColor
1435 {
1436     return [_private->bridge bodyBackgroundColor];
1437 }
1438
1439 - (BOOL)_isFrameSet
1440 {
1441     return [_private->bridge isFrameSet];
1442 }
1443
1444 - (BOOL)_firstLayoutDone
1445 {
1446     return [[self _frameLoader] firstLayoutDone];
1447 }
1448
1449 - (WebFrameLoadType)_loadType
1450 {
1451     return (WebFrameLoadType)[[self _frameLoader] loadType];
1452 }
1453
1454 @end
1455
1456 @implementation WebFormState : NSObject
1457
1458 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
1459 {
1460     self = [super init];
1461     if (!self)
1462         return nil;
1463     
1464     _form = [form retain];
1465     _values = [values copy];
1466     _sourceFrame = [sourceFrame retain];
1467     return self;
1468 }
1469
1470 - (void)dealloc
1471 {
1472     [_form release];
1473     [_values release];
1474     [_sourceFrame release];
1475     [super dealloc];
1476 }
1477
1478 - (DOMElement *)form
1479 {
1480     return _form;
1481 }
1482
1483 - (NSDictionary *)values
1484 {
1485     return _values;
1486 }
1487
1488 - (WebFrame *)sourceFrame
1489 {
1490     return _sourceFrame;
1491 }
1492
1493 @end
1494
1495 @implementation WebFrame
1496
1497 - (id)init
1498 {
1499     return [self initWithName:nil webFrameView:nil webView:nil];
1500 }
1501
1502 // FIXME: this method can't work any more and should be marked deprecated
1503 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
1504 {
1505     return [self _initWithWebFrameView:fv webView:v bridge:nil];
1506 }
1507
1508 - (void)dealloc
1509 {
1510     ASSERT(_private->bridge == nil);
1511     [_private release];
1512
1513     --WebFrameCount;
1514
1515     [super dealloc];
1516 }
1517
1518 - (void)finalize
1519 {
1520     ASSERT(_private->bridge == nil);
1521
1522     --WebFrameCount;
1523
1524     [super finalize];
1525 }
1526
1527 - (NSString *)name
1528 {
1529     return [[self _bridge] name];
1530 }
1531
1532 - (WebFrameView *)frameView
1533 {
1534     return _private->webFrameView;
1535 }
1536
1537 - (WebView *)webView
1538 {
1539     return [[[self _bridge] page] webView];
1540 }
1541
1542 - (DOMDocument *)DOMDocument
1543 {
1544     return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
1545 }
1546
1547 - (DOMHTMLElement *)frameElement
1548 {
1549     return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
1550 }
1551
1552 - (WebDataSource *)provisionalDataSource
1553 {
1554     return [[self _frameLoader] provisionalDataSource];
1555 }
1556
1557 - (WebDataSource *)dataSource
1558 {
1559     return [[self _frameLoader] dataSource];
1560 }
1561
1562 - (void)loadRequest:(NSURLRequest *)request
1563 {
1564     // FIXME: is this the right place to reset loadType? Perhaps this should be done
1565     // after loading is finished or aborted.
1566     [[self _frameLoader] setLoadType:FrameLoadTypeStandard];
1567     [[self _frameLoader] _loadRequest:request archive:nil];
1568 }
1569
1570 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1571 {
1572     NSURLRequest *request = [self _webDataRequestForData:data 
1573                                                 MIMEType:MIMEType 
1574                                         textEncodingName:encodingName 
1575                                                  baseURL:URL
1576                                           unreachableURL:unreachableURL];
1577     [self loadRequest:request];
1578 }
1579
1580
1581 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
1582 {
1583     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
1584 }
1585
1586 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
1587 {
1588     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
1589     [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
1590 }
1591
1592 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
1593 {
1594     [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
1595 }
1596
1597 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
1598 {
1599     [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
1600 }
1601
1602 - (void)loadArchive:(WebArchive *)archive
1603 {
1604     WebResource *mainResource = [archive mainResource];
1605     if (mainResource) {
1606         NSURLRequest *request = [self _webDataRequestForData:[mainResource data] 
1607                                                     MIMEType:[mainResource MIMEType]
1608                                             textEncodingName:[mainResource textEncodingName]
1609                                                      baseURL:[mainResource URL]
1610                                               unreachableURL:nil];
1611         [[self _frameLoader] _loadRequest:request archive:archive];
1612     }
1613 }
1614
1615 - (void)stopLoading
1616 {
1617     [[self _frameLoader] stopLoading];
1618 }
1619
1620 - (void)reload
1621 {
1622     [[self _frameLoader] reload];
1623 }
1624
1625 - (WebFrame *)findFrameNamed:(NSString *)name
1626 {
1627     return Frame([[self _bridge] findFrameNamed:name]);
1628 }
1629
1630 - (WebFrame *)parentFrame
1631 {
1632     return [[Frame([[self _bridge] parent]) retain] autorelease];
1633 }
1634
1635 - (NSArray *)childFrames
1636 {
1637     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
1638     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
1639         [children addObject:child];
1640
1641     return children;
1642 }
1643
1644 @end
1645
1646 @implementation WebFrame (WebFrameLoaderClient)
1647
1648 - (void)_resetBackForwardList
1649 {
1650     // Note this doesn't verify the current load type as a b/f operation because it is called from
1651     // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1652     ASSERT(self == [[self webView] mainFrame]);
1653     WebHistoryItem *resetItem = _private->currentItem;
1654     if (resetItem)
1655         [[[self webView] backForwardList] goToItem:resetItem];
1656 }
1657
1658 - (void)_invalidateCurrentItemPageCache
1659 {
1660     // When we are pre-commit, the currentItem is where the pageCache data resides
1661     NSDictionary *pageCache = [_private->currentItem pageCache];
1662
1663     [[self _bridge] invalidatePageCache:pageCache];
1664     
1665     // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
1666     [_private->currentItem setHasPageCache:NO];
1667 }
1668
1669 - (BOOL)_provisionalItemIsTarget
1670 {
1671     return [_private->provisionalItem isTargetItem];
1672 }
1673
1674 - (BOOL)_loadProvisionalItemFromPageCache
1675 {
1676     WebHistoryItem *item = _private->provisionalItem;
1677     if (![item hasPageCache])
1678         return NO;
1679     NSDictionary *pageCache = [item pageCache];
1680     if (![pageCache objectForKey:WebCorePageCacheStateKey])
1681         return NO;
1682     LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
1683     [[self provisionalDataSource] _loadFromPageCache:pageCache];
1684     return YES;
1685 }
1686
1687 - (BOOL)_privateBrowsingEnabled
1688 {
1689     return [[[self webView] preferences] privateBrowsingEnabled];
1690 }
1691
1692 - (void)_makeDocumentView
1693 {
1694     NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[[self _frameLoader] dataSource]];
1695     if (!documentView)
1696         return;
1697
1698     // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
1699     WebFrameView *v = _private->webFrameView;
1700     [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
1701     [self _updateBackground];
1702     [_private->bridge installInFrame:[v _scrollView]];
1703
1704     // Call setDataSource on the document view after it has been placed in the view hierarchy.
1705     // This what we for the top-level view, so should do this for views in subframes as well.
1706     [documentView setDataSource:[[self _frameLoader] dataSource]];
1707 }
1708
1709 - (void)_updateHistoryForCommit
1710 {
1711     WebFrameLoadType type = [[self _frameLoader] loadType];
1712     if (isBackForwardLoadType(type) ||
1713         (type == WebFrameLoadTypeReload && [[self provisionalDataSource] unreachableURL] != nil)) {
1714         // Once committed, we want to use current item for saving DocState, and
1715         // the provisional item for restoring state.
1716         // Note previousItem must be set before we close the URL, which will
1717         // happen when the data source is made non-provisional below
1718         [_private setPreviousItem:_private->currentItem];
1719         ASSERT(_private->provisionalItem);
1720         [_private setCurrentItem:_private->provisionalItem];
1721         [_private setProvisionalItem:nil];
1722     }
1723 }
1724
1725 - (void)_updateHistoryForReload
1726 {
1727     WebHistoryItem *currItem = _private->currentItem;
1728     LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
1729     [currItem setHasPageCache:NO];
1730     if ([[self _frameLoader] loadType] == WebFrameLoadTypeReload)
1731         [self _saveScrollPositionAndViewStateToItem:currItem];
1732     WebDataSource *dataSource = [[self _frameLoader] dataSource];
1733     NSURLRequest *request = [dataSource request];
1734     // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
1735     if ([request _webDataRequestUnreachableURL] == nil)
1736         [currItem setURL:[request URL]];
1737     // Update the last visited time. Mostly interesting for URL autocompletion statistics.
1738     NSURL *URL = [[[[dataSource _documentLoader] originalRequestCopy] URL] _webkit_canonicalize];
1739     WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
1740     WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
1741     if (oldItem)
1742         [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
1743 }
1744
1745 - (void)_updateHistoryForStandardLoad
1746 {
1747     WebDataSource *dataSource = [[self _frameLoader] dataSource];
1748     if (![[dataSource _documentLoader] isClientRedirect]) {
1749         NSURL *URL = [dataSource _URLForHistory];
1750         if (URL && ![URL _web_isEmpty]) {
1751             ASSERT([self webView]);
1752             if (![[[self webView] preferences] privateBrowsingEnabled]) {
1753                 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
1754                 if ([dataSource pageTitle])
1755                     [entry setTitle:[dataSource pageTitle]];                            
1756             }
1757             [self _addBackForwardItemClippedAtTarget:YES];
1758         }
1759     } else {
1760         NSURLRequest *request = [dataSource request];
1761         
1762         // Update the URL in the BF list that we made before the redirect, unless
1763         // this is alternate content for an unreachable URL (we want the BF list
1764         // item to remember the unreachable URL in case it becomes reachable later).
1765         if ([request _webDataRequestUnreachableURL] == nil) {
1766             [_private->currentItem setURL:[request URL]];
1767
1768             // clear out the form data so we don't repost it to the wrong place if we
1769             // ever go back/forward to this item
1770             [_private->currentItem _setFormInfoFromRequest:request];
1771
1772             // We must also clear out form data so we don't try to restore it into the incoming page,
1773             // see -_opened
1774         }
1775     }
1776 }
1777
1778 - (void)_updateHistoryForBackForwardNavigation
1779 {
1780     // Must grab the current scroll position before disturbing it
1781     [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
1782 }
1783
1784 - (void)_updateHistoryForInternalLoad
1785 {
1786     WebDataSource *dataSource = [[self _frameLoader] dataSource];
1787
1788     // Add an item to the item tree for this frame
1789     ASSERT(![[dataSource _documentLoader] isClientRedirect]);
1790     WebFrame *parentFrame = [self parentFrame];
1791     if (parentFrame) {
1792         WebHistoryItem *parentItem = parentFrame->_private->currentItem;
1793         // The only case where parentItem==nil should be when a parent frame loaded an
1794         // empty URL, which doesn't set up a current item in that parent.
1795         if (parentItem)
1796             [parentItem addChildItem:[self _createItem:YES]];
1797     } else {
1798         // See 3556159. It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
1799         // for a top-level frame, but that was a likely explanation for those crashes,
1800         // so let's guard against it.
1801         // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
1802         LOG_ERROR("no parent frame in transitionToCommitted:, WebFrameLoadTypeInternal");
1803     }
1804 }
1805
1806 - (LoadErrorResetToken *)_tokenForLoadErrorReset
1807 {
1808     return (LoadErrorResetToken*)[[self _currentBackForwardListItemToResetTo] retain];
1809 }
1810
1811 - (void)_resetAfterLoadError:(LoadErrorResetToken *)token
1812 {
1813     WebHistoryItem *item = (WebHistoryItem *)token;
1814     if (item)
1815         [[[self webView] backForwardList] goToItem:item];
1816     [item release];
1817 }
1818
1819 - (void)_doNotResetAfterLoadError:(LoadErrorResetToken *)token
1820 {
1821     WebHistoryItem *item = (WebHistoryItem *)token;
1822     [item release];
1823 }
1824
1825 @end