Reviewed by Darin
[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 "WebDocumentLoadStateMac.h"
39 #import "WebFormDataStream.h"
40 #import "WebFrameBridge.h"
41 #import "WebFrameLoadDelegate.h"
42 #import "WebFrameLoader.h"
43 #import "WebFrameLoaderClient.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"
59 #import "WebPlugin.h"
60 #import "WebPluginController.h"
61 #import "WebPreferencesPrivate.h"
62 #import "WebResourceLoadDelegate.h"
63 #import "WebResourcePrivate.h"
64 #import "WebScriptDebugDelegatePrivate.h"
65 #import "WebUIDelegate.h"
66 #import "WebViewInternal.h"
67 #import <WebKit/DOM.h>
68 #import <WebKitSystemInterface.h>
69 #import <objc/objc-runtime.h>
70
71 /*
72 Here is the current behavior matrix for four types of navigations:
73
74 Standard Nav:
75
76  Restore form state:   YES
77  Restore scroll and focus state:  YES
78  WF Cache policy: NSURLRequestUseProtocolCachePolicy
79  Add to back/forward list: YES
80  
81 Back/Forward:
82
83  Restore form state:   YES
84  Restore scroll and focus state:  YES
85  WF Cache policy: NSURLRequestReturnCacheDataElseLoad
86  Add to back/forward list: NO
87
88 Reload (meaning only the reload button):
89
90  Restore form state:   NO
91  Restore scroll and focus state:  YES
92  WF Cache policy: NSURLRequestReloadIgnoringCacheData
93  Add to back/forward list: NO
94
95 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
96
97  Restore form state:   NO
98  Restore scroll and focus state:  NO, reset to initial conditions
99  WF Cache policy: NSURLRequestReloadIgnoringCacheData
100  Add to back/forward list: NO
101 */
102
103 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
104 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
105 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
106
107 @interface WebFrame (ForwardDecls)
108 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
109 - (NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
110
111 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
112
113 - (WebHistoryItem *)_createItem: (BOOL)useOriginal;
114 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
115 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
116 - (void)_stopLoadingSubframes;
117 @end
118
119 @interface WebFrame (FrameTraversal)
120 - (WebFrame *)_firstChildFrame;
121 - (WebFrame *)_lastChildFrame;
122 - (unsigned)_childFrameCount;
123 - (WebFrame *)_previousSiblingFrame;
124 - (WebFrame *)_nextSiblingFrame;
125 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
126 @end
127
128 @interface WebFrame (WebFrameLoaderClient) <WebFrameLoaderClient>
129 @end
130
131 @interface NSView (WebFramePluginHosting)
132 - (void)setWebFrame:(WebFrame *)webFrame;
133 @end
134
135 @interface WebFramePrivate : NSObject
136 {
137 @public
138     WebFrameView *webFrameView;
139     WebFrameLoader *frameLoader;
140
141     WebFrameBridge *bridge;
142     WebHistoryItem *currentItem;        // BF item for our current content
143     WebHistoryItem *provisionalItem;    // BF item for where we're trying to go
144                                         // (only known when navigating to a pre-existing BF item)
145     WebHistoryItem *previousItem;       // BF item for previous content, see _itemForSavingDocState
146
147     WebScriptDebugger *scriptDebugger;
148     id internalLoadDelegate;
149     
150     NSMutableSet *plugInViews;
151     NSMutableSet *inspectors;
152     
153     // things below here should be moved
154
155     BOOL quickRedirectComing;
156     BOOL sentRedirectNotification;
157     BOOL isStoppingLoad;
158 }
159
160 - (void)setWebFrameView:(WebFrameView *)v;
161 - (WebFrameView *)webFrameView;
162
163 - (void)setProvisionalItem:(WebHistoryItem *)item;
164 - (WebHistoryItem *)provisionalItem;
165 - (void)setPreviousItem:(WebHistoryItem *)item;
166 - (WebHistoryItem *)previousItem;
167 - (void)setCurrentItem:(WebHistoryItem *)item;
168 - (WebHistoryItem *)currentItem;
169
170 @end
171
172 @implementation WebFramePrivate
173
174 - (void)dealloc
175 {
176     [webFrameView release];
177     [frameLoader release];
178
179     [currentItem release];
180     [provisionalItem release];
181     [previousItem release];
182     
183     [scriptDebugger release];
184     
185     [inspectors release];
186
187     ASSERT(plugInViews == nil);
188     
189     [super dealloc];
190 }
191
192 - (WebFrameView *)webFrameView { return webFrameView; }
193 - (void)setWebFrameView: (WebFrameView *)v 
194
195     [v retain];
196     [webFrameView release];
197     webFrameView = v;
198 }
199
200 - (WebHistoryItem *)provisionalItem { return provisionalItem; }
201 - (void)setProvisionalItem: (WebHistoryItem *)item
202 {
203     [item retain];
204     [provisionalItem release];
205     provisionalItem = item;
206 }
207
208 - (WebHistoryItem *)previousItem { return previousItem; }
209 - (void)setPreviousItem:(WebHistoryItem *)item
210 {
211     [item retain];
212     [previousItem release];
213     previousItem = item;
214 }
215
216 - (WebHistoryItem *)currentItem { return currentItem; }
217 - (void)setCurrentItem:(WebHistoryItem *)item
218 {
219     [item retain];
220     [currentItem release];
221     currentItem = item;
222 }
223
224 @end
225 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
226 {
227     return [(WebFrameBridge *)bridge webFrame];
228 }
229
230 @implementation WebFrame (FrameTraversal)
231 - (WebFrame *)_firstChildFrame
232 {
233     return Frame([[self _bridge] firstChild]);
234 }
235
236 - (WebFrame *)_lastChildFrame
237 {
238     return Frame([[self _bridge] lastChild]);
239 }
240
241 - (unsigned)_childFrameCount
242 {
243     return [[self _bridge] childCount];
244 }
245
246 - (WebFrame *)_previousSiblingFrame;
247 {
248     return Frame([[self _bridge] previousSibling]);
249 }
250
251 - (WebFrame *)_nextSiblingFrame;
252 {
253     return Frame([[self _bridge] nextSibling]);
254 }
255
256 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
257 {
258     return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
259 }
260
261 @end
262
263 @implementation WebFrame (WebInternal)
264
265 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName: (NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
266 {
267     NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
268     NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
269     [request _webDataRequestSetData:data];
270     [request _webDataRequestSetEncoding:encodingName];
271     [request _webDataRequestSetBaseURL:URL];
272     [request _webDataRequestSetUnreachableURL:unreachableURL];
273     [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
274     return request;
275 }
276
277 // helper method used in various nav cases below
278 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
279 {
280     if ([[self dataSource] _URLForHistory] != nil) {
281         WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
282         LOG (BackForward, "for frame %@, adding item  %@\n", [self name], bfItem);
283         [[[self webView] backForwardList] addItem:bfItem];
284     }
285 }
286
287 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
288 {
289     WebDataSource *dataSrc = [self dataSource];
290     NSURLRequest *request;
291     NSURL *unreachableURL = [dataSrc unreachableURL];
292     NSURL *URL;
293     NSURL *originalURL;
294     WebHistoryItem *bfItem;
295
296     if (useOriginal)
297         request = [[dataSrc _documentLoadState] originalRequestCopy];
298     else
299         request = [dataSrc request];
300
301     if (unreachableURL != nil) {
302         URL = unreachableURL;
303         originalURL = unreachableURL;
304     } else {
305         URL = [request URL];
306         originalURL = [[[dataSrc _documentLoadState] originalRequestCopy] URL];
307     }
308
309     LOG (History, "creating item for %@", request);
310     
311     // Frames that have never successfully loaded any content
312     // may have no URL at all. Currently our history code can't
313     // deal with such things, so we nip that in the bud here.
314     // Later we may want to learn to live with nil for URL.
315     // See bug 3368236 and related bugs for more information.
316     if (URL == nil) {
317         URL = [NSURL URLWithString:@"about:blank"];
318     }
319     if (originalURL == nil) {
320         originalURL = [NSURL URLWithString:@"about:blank"];
321     }
322     
323     bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
324     [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
325
326     // save form state if this is a POST
327     [bfItem _setFormInfoFromRequest:request];
328
329     // Set the item for which we will save document state
330     [_private setPreviousItem:[_private currentItem]];
331     [_private setCurrentItem:bfItem];
332
333     return bfItem;
334 }
335
336 /*
337     In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.  
338     The item that was the target of the user's navigation is designated as the "targetItem".  
339     When this method is called with doClip=YES we're able to create the whole tree except for the target's children, 
340     which will be loaded in the future.  That part of the tree will be filled out as the child loads are committed.
341 */
342 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
343 {
344     WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
345
346     [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
347     if (!(doClip && self == targetFrame)) {
348         // save frame state for items that aren't loading (khtml doesn't save those)
349         [_private->bridge saveDocumentState];
350
351         for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
352             [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
353     }
354     if (self == targetFrame)
355         [bfItem setIsTargetItem:YES];
356
357     return bfItem;
358 }
359
360 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
361 {
362     return Frame([[self _bridge] childFrameNamed:name]);
363 }
364
365 - (void)_detachChildren
366 {
367     // FIXME: is it really necessary to do this in reverse order any more?
368     WebFrame *child = [self _lastChildFrame];
369     WebFrame *prev = [child _previousSiblingFrame];
370     for (; child; child = prev, prev = [child _previousSiblingFrame])
371         [child _detachFromParent];
372 }
373
374 - (void)_closeOldDataSources
375 {
376     // FIXME: is it important for this traversal to be postorder instead of preorder?
377     // FIXME: add helpers for postorder traversal?
378     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
379         [child _closeOldDataSources];
380
381     if ([_private->frameLoader dataSource])
382         [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] willCloseFrame:self];
383     [[self webView] setMainFrameDocumentReady:NO];  // stop giving out the actual DOMDocument to observers
384 }
385
386 - (void)_detachFromParent
387 {
388     WebFrameBridge *bridge = [_private->bridge retain];
389
390     [bridge closeURL];
391     [self stopLoading];
392
393     [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
394     [self _detachChildren];
395     [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
396
397     [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
398
399     [_private->frameLoader clearDataSource];
400     [_private setWebFrameView:nil];
401
402     [self retain]; // retain self temporarily because dealloc can re-enter this method
403
404     [[[self parentFrame] _bridge] removeChild:bridge];
405
406     [bridge close];
407     [bridge release];
408
409     bridge = nil;
410     _private->bridge = nil;
411
412     [self release];
413 }
414
415 - (void)_makeDocumentView
416 {
417     NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[_private->frameLoader dataSource]];
418     if (!documentView)
419         return;
420
421     // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
422     WebFrameView *v = _private->webFrameView;
423     [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
424     [self _updateBackground];
425     [_private->bridge installInFrame:[v _scrollView]];
426
427     // Call setDataSource on the document view after it has been placed in the view hierarchy.
428     // This what we for the top-level view, so should do this for views in subframes as well.
429     [documentView setDataSource:[_private->frameLoader dataSource]];
430 }
431
432 - (void)_receivedMainResourceError:(NSError *)error
433 {
434     if ([_private->frameLoader state] == WebFrameStateProvisional) {
435         NSURL *failedURL = [[[_private->frameLoader provisionalDocumentLoadState] originalRequestCopy] URL];
436         // When we are pre-commit, the currentItem is where the pageCache data resides
437         NSDictionary *pageCache = [[_private currentItem] pageCache];
438         [[self _bridge] didNotOpenURL:failedURL pageCache:pageCache];
439         // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
440         [[_private currentItem] setHasPageCache:NO];
441         
442         // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
443         // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
444         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are definitely
445         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
446         // has ended.
447         if (_private->sentRedirectNotification)
448             [self _clientRedirectCancelledOrFinished:NO];
449     }
450 }
451
452 - (void)_transitionToCommitted:(NSDictionary *)pageCache
453 {
454     ASSERT([self webView] != nil);
455     
456     switch ([_private->frameLoader state]) {
457         case WebFrameStateProvisional:
458         {
459             [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
460
461             WebFrameLoadType loadType = [_private->frameLoader loadType];
462             if (loadType == WebFrameLoadTypeForward ||
463                 loadType == WebFrameLoadTypeBack ||
464                 loadType == WebFrameLoadTypeIndexedBackForward ||
465                 (loadType == WebFrameLoadTypeReload && [[_private->frameLoader provisionalDataSource] unreachableURL] != nil))
466             {
467                 // Once committed, we want to use current item for saving DocState, and
468                 // the provisional item for restoring state.
469                 // Note previousItem must be set before we close the URL, which will
470                 // happen when the data source is made non-provisional below
471                 [_private setPreviousItem:[_private currentItem]];
472                 ASSERT([_private provisionalItem]);
473                 [_private setCurrentItem:[_private provisionalItem]];
474                 [_private setProvisionalItem:nil];
475             }
476
477             // The call to closeURL invokes the unload event handler, which can execute arbitrary
478             // JavaScript. If the script initiates a new load, we need to abandon the current load,
479             // or the two will stomp each other.
480             WebDataSource *pd = [_private->frameLoader provisionalDataSource];
481             [[self _bridge] closeURL];
482             if (pd != [_private->frameLoader provisionalDataSource])
483                 return;
484
485             [_private->frameLoader commitProvisionalLoad];
486
487             // Handle adding the URL to the back/forward list.
488             WebDataSource *ds = [self dataSource];
489             NSString *ptitle = [ds pageTitle];
490
491             switch (loadType) {
492             case WebFrameLoadTypeForward:
493             case WebFrameLoadTypeBack:
494             case WebFrameLoadTypeIndexedBackForward:
495                 if ([[self webView] backForwardList]) {
496                     // Must grab the current scroll position before disturbing it
497                     [self _saveScrollPositionAndViewStateToItem:[_private previousItem]];
498                     
499                     // Create a document view for this document, or used the cached view.
500                     if (pageCache){
501                         NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
502                         ASSERT(cachedView != nil);
503                         [[self frameView] _setDocumentView: cachedView];
504                     }
505                     else
506                         [self _makeDocumentView];
507                 }
508                 break;
509
510             case WebFrameLoadTypeReload:
511             case WebFrameLoadTypeSame:
512             case WebFrameLoadTypeReplace:
513             {
514                 WebHistoryItem *currItem = [_private currentItem];
515                 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
516                 [currItem setHasPageCache:NO];
517                 if (loadType == WebFrameLoadTypeReload) {
518                     [self _saveScrollPositionAndViewStateToItem:currItem];
519                 }
520                 NSURLRequest *request = [ds request];
521                 if ([request _webDataRequestUnreachableURL] == nil) {
522                     // Sometimes loading a page again leads to a different result because of cookies.  Bugzilla 4072
523                     [currItem setURL:[request URL]];
524                 }
525                 // Update the last visited time.  Mostly interesting for URL autocompletion
526                 // statistics.
527                 NSURL *URL = [[[[ds _documentLoadState] originalRequestCopy] URL] _webkit_canonicalize];
528                 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
529                 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
530                 if (oldItem)
531                     [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
532                 
533                 [self _makeDocumentView];
534                 break;
535             }
536
537             // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
538             case WebFrameLoadTypeReloadAllowingStaleData:
539                 [self _makeDocumentView];
540                 break;
541                 
542             case WebFrameLoadTypeStandard:
543                 if (![[ds _documentLoadState] isClientRedirect]) {
544                     // Add item to history and BF list
545                     NSURL *URL = [ds _URLForHistory];
546                     if (URL && ![URL _web_isEmpty]){
547                         ASSERT([self webView]);
548                         if (![[[self webView] preferences] privateBrowsingEnabled]) {
549                             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
550                             if (ptitle)
551                                 [entry setTitle: ptitle];                            
552                         }
553                         [self _addBackForwardItemClippedAtTarget:YES];
554                     }
555
556                 } else {
557                     NSURLRequest *request = [ds request];
558                     
559                     // update the URL in the BF list that we made before the redirect, unless
560                     // this is alternate content for an unreachable URL (we want the BF list
561                     // item to remember the unreachable URL in case it becomes reachable later)
562                     if ([request _webDataRequestUnreachableURL] == nil) {
563                         [[_private currentItem] setURL:[request URL]];
564
565                         // clear out the form data so we don't repost it to the wrong place if we
566                         // ever go back/forward to this item
567                         [[_private currentItem] _setFormInfoFromRequest:request];
568
569                         // We must also clear out form data so we don't try to restore it into the incoming page,
570                         // see -_opened
571                     }
572                 }
573                 [self _makeDocumentView];
574                 break;
575                 
576             case WebFrameLoadTypeInternal:
577                 // Add an item to the item tree for this frame
578                 ASSERT(![[ds _documentLoadState] isClientRedirect]);
579                 WebFrame *parentFrame = [self parentFrame];
580                 if (parentFrame) {
581                     WebHistoryItem *parentItem = [parentFrame->_private currentItem];
582                     // The only case where parentItem==nil should be when a parent frame loaded an
583                     // empty URL, which doesn't set up a current item in that parent.
584                     if (parentItem)
585                         [parentItem addChildItem:[self _createItem: YES]];
586                 } else {
587                     // See 3556159.  It's not clear if it's valid to be in WebFrameLoadTypeOnLoadEvent
588                     // for a top-level frame, but that was a likely explanation for those crashes,
589                     // so let's guard against it.
590                     // ...and all WebFrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
591                     LOG_ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
592                 }
593                 [self _makeDocumentView];
594                 break;
595
596             // FIXME Remove this check when dummy ds is removed.  An exception should be thrown
597             // if we're in the WebFrameLoadTypeUninitialized state.
598             default:
599                 ASSERT_NOT_REACHED();
600             }
601
602             
603             // Tell the client we've committed this URL.
604             ASSERT([[self frameView] documentView] != nil);
605             [[self webView] _didCommitLoadForFrame: self];
606             [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didCommitLoadForFrame:self];
607             
608             // If we have a title let the WebView know about it.
609             if (ptitle) {
610                 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
611                                                            didReceiveTitle:ptitle
612                                                                   forFrame:self];
613             }
614             break;
615         }
616         
617         case WebFrameStateCommittedPage:
618         case WebFrameStateComplete:
619         default:
620         {
621             ASSERT_NOT_REACHED();
622         }
623     }
624 }
625
626 - (void)_commitProvisionalLoad:(NSDictionary *)pageCache
627 {
628     WebFrameLoadType loadType = [_private->frameLoader loadType];
629     bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
630     
631     WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
632     NSURLResponse *response = [provisionalDataSource response];
633
634     NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
635         ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
636     
637     if (loadType != WebFrameLoadTypeReplace)
638         [self _closeOldDataSources];
639     
640     if (!pageCache)
641         [provisionalDataSource _makeRepresentation];
642     
643     [self _transitionToCommitted:pageCache];
644
645     // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
646     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
647     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
648     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
649     if (_private->sentRedirectNotification)
650         [self _clientRedirectCancelledOrFinished:NO];
651     
652     NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];        
653     NSURL *URL = baseURL ? baseURL : [response URL];
654
655     if (!URL || [URL _web_isEmpty])
656         URL = [NSURL URLWithString:@"about:blank"];    
657
658     [[self _bridge] openURL:URL
659                     reload:reload 
660                     contentType:[response MIMEType]
661                     refresh:[headers objectForKey:@"Refresh"]
662                     lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
663                     pageCache:pageCache];
664     
665     [self _opened];
666
667     [provisionalDataSource release];
668 }
669
670 - (BOOL)_canCachePage
671 {
672     return [[[self webView] backForwardList] _usesPageCache];
673 }
674
675 - (void)_purgePageCache
676 {
677     // This method implements the rule for purging the page cache.
678     unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
679     unsigned pagesCached = 0;
680     WebBackForwardList *backForwardList = [[self webView] backForwardList];
681     NSArray *backList = [backForwardList backListWithLimit: 999999];
682     WebHistoryItem *oldestNonSnapbackItem = nil;
683     
684     unsigned i;
685     for (i = 0; i < [backList count]; i++){
686         WebHistoryItem *item = [backList objectAtIndex: i];
687         if ([item hasPageCache]){
688             if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
689                 oldestNonSnapbackItem = item;
690             pagesCached++;
691         }
692     }
693
694     // Snapback items are never directly purged here.
695     if (pagesCached >= sizeLimit) {
696         LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
697         [oldestNonSnapbackItem setHasPageCache:NO];
698     }
699 }
700
701 + (CFAbsoluteTime)_timeOfLastCompletedLoad
702 {
703     return [WebFrameLoader timeOfLastCompletedLoad];
704 }
705
706 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
707 {
708     NSMutableDictionary *pageCache;
709
710     [item setHasPageCache: YES];
711
712     if (![_private->bridge saveDocumentToPageCache]){
713         [item setHasPageCache: NO];
714         return NO;
715     }
716     else {
717         pageCache = [item pageCache];
718         [pageCache setObject:[NSDate date]  forKey: WebPageCacheEntryDateKey];
719         [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
720         [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
721     }
722     return YES;
723 }
724
725 // Called after we send an openURL:... down to WebCore.
726 - (void)_opened
727 {
728     if ([_private->frameLoader loadType] == WebFrameLoadTypeStandard && [[[self dataSource] _documentLoadState] isClientRedirect]) {
729         // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
730         // khtml has closed the URL and saved away the form state.
731         WebHistoryItem *item = [_private currentItem];
732         [item setDocumentState:nil];
733         [item setScrollPoint:NSZeroPoint];
734     }
735
736     if ([[self dataSource] _loadingFromPageCache]){
737         // Force a layout to update view size and thereby update scrollbars.
738         NSView <WebDocumentView> *view = [[self frameView] documentView];
739         if ([view isKindOfClass:[WebHTMLView class]]) {
740             [(WebHTMLView *)view setNeedsToApplyStyles:YES];
741         }
742         [view setNeedsLayout: YES];
743         [view layout];
744
745         NSArray *responses = [[_private->frameLoader documentLoadState] responses];
746         NSURLResponse *response;
747         int i, count = [responses count];
748         for (i = 0; i < count; i++){
749             response = [responses objectAtIndex: i];
750             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
751             NSError *error;
752             id identifier;
753             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
754             [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
755             [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
756             [request release];
757         }
758         
759         // Release the resources kept in the page cache.  They will be
760         // reset when we leave this page.  The core side of the page cache
761         // will have already been invalidated by the bridge to prevent
762         // premature release.
763         [[_private currentItem] setHasPageCache:NO];
764
765         [[_private->frameLoader documentLoadState] setPrimaryLoadComplete:YES];
766         // why only this frame and not parent frames?
767         [self _checkLoadCompleteForThisFrame];
768     }
769 }
770
771 - (void)_checkLoadCompleteForThisFrame
772 {
773     ASSERT([self webView] != nil);
774
775     switch ([_private->frameLoader state]) {
776         case WebFrameStateProvisional:
777         {
778             if ([_private->frameLoader delegateIsHandlingProvisionalLoadError])
779                 return;
780
781             WebDataSource *pd = [self provisionalDataSource];
782             
783             LOG(Loading, "%@:  checking complete in WebFrameStateProvisional", [self name]);
784             // If we've received any errors we may be stuck in the provisional state and actually
785             // complete.
786             NSError *error = [pd _mainDocumentError];
787             if (error != nil) {
788                 // Check all children first.
789                 LOG(Loading, "%@:  checking complete, current state WebFrameStateProvisional", [self name]);
790                 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
791                 BOOL shouldReset = YES;
792                 if (![pd isLoading]) {
793                     LOG(Loading, "%@:  checking complete in WebFrameStateProvisional, load done", [self name]);
794                     [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
795                     [_private->frameLoader setDelegateIsHandlingProvisionalLoadError:YES];
796                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
797                                           didFailProvisionalLoadWithError:error
798                                                                  forFrame:self];
799                     [_private->frameLoader setDelegateIsHandlingProvisionalLoadError:NO];
800                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
801
802                     // FIXME: can stopping loading here possibly have
803                     // any effect, if isLoading is false, which it
804                     // must be, to be in this branch of the if? And is it ok to just do 
805                     // a full-on stopLoading?
806                     [self _stopLoadingSubframes];
807                     [[pd _documentLoadState] stopLoading];
808
809                     // Finish resetting the load state, but only if another load hasn't been started by the
810                     // delegate callback.
811                     if (pd == [_private->frameLoader provisionalDataSource])
812                         [_private->frameLoader clearProvisionalLoad];
813                     else {
814                         NSURL *unreachableURL = [[_private->frameLoader provisionalDataSource] unreachableURL];
815                         if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
816                             shouldReset = NO;
817                         }
818                     }
819                 }
820                 if (shouldReset && resetItem != nil) {
821                     [[[self webView] backForwardList] goToItem:resetItem];
822                 }
823             }
824             return;
825         }
826         
827         case WebFrameStateCommittedPage:
828         {
829             WebDataSource *ds = [self dataSource];
830             
831             //LOG(Loading, "%@:  checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
832             if (![ds isLoading]) {
833                 WebFrameView *thisView = [self frameView];
834                 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
835                 ASSERT(thisDocumentView != nil);
836
837                 [_private->frameLoader markLoadComplete];
838
839                 // FIXME: Is this subsequent work important if we already navigated away?
840                 // Maybe there are bugs because of that, or extra work we can skip because
841                 // the new page is ready.
842
843                 // Tell the just loaded document to layout.  This may be necessary
844                 // for non-html content that needs a layout message.
845                 if (!([[self dataSource] _isDocumentHTML])) {
846                     [thisDocumentView setNeedsLayout:YES];
847                     [thisDocumentView layout];
848                     [thisDocumentView setNeedsDisplay:YES];
849                 }
850                  
851                 // If the user had a scroll point scroll to it.  This will override
852                 // the anchor point.  After much discussion it was decided by folks
853                 // that the user scroll point should override the anchor point.
854                 if ([[self webView] backForwardList]) {
855                     switch ([_private->frameLoader loadType]) {
856                     case WebFrameLoadTypeForward:
857                     case WebFrameLoadTypeBack:
858                     case WebFrameLoadTypeIndexedBackForward:
859                     case WebFrameLoadTypeReload:
860                         [self _restoreScrollPositionAndViewState];
861                         break;
862
863                     case WebFrameLoadTypeStandard:
864                     case WebFrameLoadTypeInternal:
865                     case WebFrameLoadTypeReloadAllowingStaleData:
866                     case WebFrameLoadTypeSame:
867                     case WebFrameLoadTypeReplace:
868                         // Do nothing.
869                         break;
870
871                     default:
872                         ASSERT_NOT_REACHED();
873                         break;
874                     }
875                 }
876
877                 NSError *error = [ds _mainDocumentError];
878                 if (error != nil) {
879                     [[self webView] _didFailLoadWithError:error forFrame:self];
880                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
881                                                      didFailLoadWithError:error
882                                                                  forFrame:self];
883                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
884                 } else {
885                     [[self webView] _didFinishLoadForFrame:self];
886                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
887                                                     didFinishLoadForFrame:self];
888                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
889                 }
890                 
891                 [[self webView] _progressCompleted: self];
892  
893                 return;
894             }
895             return;
896         }
897         
898         case WebFrameStateComplete:
899         {
900             LOG(Loading, "%@:  checking complete, current state WebFrameStateComplete", [self name]);
901             // Even if already complete, we might have set a previous item on a frame that
902             // didn't do any data loading on the past transaction.  Make sure to clear these out.
903             [_private setPreviousItem:nil];
904             return;
905         }
906     }
907     
908     // Yikes!  Serious horkage.
909     ASSERT_NOT_REACHED();
910 }
911
912 - (void)_handledOnloadEvents
913 {
914     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
915 }
916
917 // Called every time a resource is completely loaded, or an error is received.
918 - (void)_checkLoadComplete
919 {
920     ASSERT([self webView] != nil);
921
922     WebFrame *parent;
923     for (WebFrame *frame = self; frame; frame = parent) {
924         [frame retain];
925         [frame _checkLoadCompleteForThisFrame];
926         parent = [frame parentFrame];
927         [frame release];
928     }
929 }
930
931 - (WebFrameBridge *)_bridge
932 {
933     return _private->bridge;
934 }
935
936 // helper method that determines whether the subframes described by the item's subitems
937 // match our own current frameset
938 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
939 {
940     NSArray *childItems = [item children];
941     int numChildItems = [childItems count];
942     int numChildFrames = [self _childFrameCount];
943     if (numChildFrames != numChildItems)
944         return NO;
945
946     int i;
947     for (i = 0; i < numChildItems; i++) {
948         NSString *itemTargetName = [[childItems objectAtIndex:i] target];
949         //Search recursive here?
950         if (![self _immediateChildFrameNamed:itemTargetName])
951             return NO; // couldn't match the i'th itemTarget
952     }
953
954     return YES; // found matches for all itemTargets
955 }
956
957 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
958 {
959     return !(([currentURL fragment] || [destinationURL fragment]) &&
960     [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
961 }
962
963 // Walk the frame tree and ensure that the URLs match the URLs in the item.
964 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
965 {
966     NSURL *currentURL = [[[self dataSource] request] URL];
967
968     if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
969         return NO;
970     
971     NSArray *childItems = [item children];
972     WebHistoryItem *childItem;
973     WebFrame *childFrame;
974     int i, count = [childItems count];
975     for (i = 0; i < count; i++){
976         childItem = [childItems objectAtIndex:i];
977         childFrame = [self _immediateChildFrameNamed:[childItem target]];
978         if (![childFrame _URLsMatchItem: childItem])
979             return NO;
980     }
981     
982     return YES;
983 }
984
985 // loads content into this frame, as specified by item
986 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
987 {
988     NSURL *itemURL = [item URL];
989     NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
990     NSURL *currentURL = [[[self dataSource] request] URL];
991     NSArray *formData = [item formData];
992
993     // Are we navigating to an anchor within the page?
994     // Note if we have child frames we do a real reload, since the child frames might not
995     // match our current frame structure, or they might not have the right content.  We could
996     // check for all that as an additional optimization.
997     // We also do not do anchor-style navigation if we're posting a form.
998     
999     // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1000     // Perhaps they should.
1001     if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1002     {
1003 #if 0
1004         // FIXME:  We need to normalize the code paths for anchor navigation.  Something
1005         // like the following line of code should be done, but also accounting for correct
1006         // updates to the back/forward list and scroll position.
1007         // rjw 4/9/03 See 3223929.
1008         [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1009 #endif
1010         // must do this maintenance here, since we don't go through a real page reload
1011         [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1012         // FIXME: form state might want to be saved here too
1013
1014         // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
1015         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
1016         [_private->bridge scrollToAnchorWithURL:[item URL]];
1017     
1018         // must do this maintenance here, since we don't go through a real page reload
1019         [_private setCurrentItem:item];
1020         [self _restoreScrollPositionAndViewState];
1021
1022         // Fake the URL change by updating the data source's request.  This will no longer
1023         // be necessary if we do the better fix described above.
1024         [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:itemURL];
1025         
1026         [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1027                                didChangeLocationWithinPageForFrame:self];
1028         [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1029     } else {
1030         // Remember this item so we can traverse any child items as child frames load
1031         [_private setProvisionalItem:item];
1032
1033         WebDataSource *newDataSource;
1034         BOOL inPageCache = NO;
1035         
1036         // Check if we'll be using the page cache.  We only use the page cache
1037         // if one exists and it is less than _backForwardCacheExpirationInterval
1038         // seconds old.  If the cache is expired it gets flushed here.
1039         if ([item hasPageCache]){
1040             NSDictionary *pageCache = [item pageCache];
1041             NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1042             NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1043
1044             if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1045                 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1046                 [_private->frameLoader loadDataSource:newDataSource withLoadType:loadType formState:nil];   
1047                 inPageCache = YES;
1048             }
1049             else {
1050                 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]);
1051                 [item setHasPageCache: NO];
1052             }
1053         }
1054         
1055         if (!inPageCache) {
1056             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1057             [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1058
1059             // If this was a repost that failed the page cache, we might try to repost the form.
1060             NSDictionary *action;
1061             if (formData) {
1062                 [request setHTTPMethod:@"POST"];
1063                 [request _web_setHTTPReferrer:[item formReferrer]];
1064                 webSetHTTPBody(request, formData);
1065                 [request _web_setHTTPContentType:[item formContentType]];
1066
1067                 // Slight hack to test if the WF cache contains the page we're going to.  We want
1068                 // to know this before talking to the policy delegate, since it affects whether we
1069                 // show the DoYouReallyWantToRepost nag.
1070                 //
1071                 // This trick has a small bug (3123893) where we might find a cache hit, but then
1072                 // have the item vanish when we try to use it in the ensuing nav.  This should be
1073                 // extremely rare, but in that case the user will get an error on the navigation.
1074                 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1075                 NSURLResponse *synchResponse = nil;
1076                 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1077                 if (synchResponse == nil) { 
1078                     // Not in WF cache
1079                     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1080                     action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1081                 } else {
1082                     // We can use the cache, don't use navType=resubmit
1083                     action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1084                 }
1085             } else {
1086                 switch (loadType) {
1087                     case WebFrameLoadTypeReload:
1088                         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1089                         break;
1090                     case WebFrameLoadTypeBack:
1091                     case WebFrameLoadTypeForward:
1092                     case WebFrameLoadTypeIndexedBackForward:
1093                         if (![[itemURL scheme] isEqual:@"https"]) {
1094                             [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1095                         }
1096                         break;
1097                     case WebFrameLoadTypeStandard:
1098                     case WebFrameLoadTypeInternal:
1099                         // no-op: leave as protocol default
1100                         // FIXME:  I wonder if we ever hit this case
1101                         break;
1102                     case WebFrameLoadTypeSame:
1103                     case WebFrameLoadTypeReloadAllowingStaleData:
1104                     default:
1105                         ASSERT_NOT_REACHED();
1106                 }
1107
1108                 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1109             }
1110
1111             [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1112             [request release];
1113         }
1114     }
1115 }
1116
1117 // The general idea here is to traverse the frame tree and the item tree in parallel,
1118 // tracking whether each frame already has the content the item requests.  If there is
1119 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
1120 // reload that frame, and all its kids.
1121 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1122 {
1123     NSURL *itemURL = [item URL];
1124     NSURL *currentURL = [[[self dataSource] request] URL];
1125
1126     // Always reload the target frame of the item we're going to.  This ensures that we will
1127     // do -some- load for the transition, which means a proper notification will be posted
1128     // to the app.
1129     // The exact URL has to match, including fragment.  We want to go through the _load
1130     // method, even if to do a within-page navigation.
1131     // The current frame tree and the frame tree snapshot in the item have to match.
1132     if (![item isTargetItem] &&
1133         [itemURL isEqual:currentURL] &&
1134         (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1135         [self _childFramesMatchItem:item])
1136     {
1137         // This content is good, so leave it alone and look for children that need reloading
1138
1139         // Save form state (works from currentItem, since prevItem is nil)
1140         ASSERT(![_private previousItem]);
1141         [_private->bridge saveDocumentState];
1142         [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1143         
1144         [_private setCurrentItem:item];
1145
1146         // Restore form state (works from currentItem)
1147         [_private->bridge restoreDocumentState];
1148         // Restore the scroll position (taken in favor of going back to the anchor)
1149         [self _restoreScrollPositionAndViewState];
1150         
1151         NSArray *childItems = [item children];
1152         int numChildItems = childItems ? [childItems count] : 0;
1153         int i;
1154         for (i = numChildItems - 1; i >= 0; i--) {
1155             WebHistoryItem *childItem = [childItems objectAtIndex:i];
1156             NSString *childName = [childItem target];
1157             WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1158             ASSERT(fromChildItem || [fromItem isTargetItem]);
1159             WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1160             ASSERT(childFrame);
1161             [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1162         }
1163     } else {
1164         // We need to reload the content
1165         [self _loadItem:item withLoadType:type];
1166     }
1167 }
1168
1169 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1170 // This includes recursion to handle loading into framesets properly
1171 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1172 {
1173     ASSERT(![self parentFrame]);
1174     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1175     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1176     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1177     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1178     if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {    
1179         WebBackForwardList *backForwardList = [[self webView] backForwardList];
1180         WebHistoryItem *currItem = [backForwardList currentItem];
1181         // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1182         // - plus, it only makes sense for the top level of the operation through the frametree,
1183         // as opposed to happening for some/one of the page commits that might happen soon
1184         [backForwardList goToItem:item];
1185         [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1186     }
1187 }
1188
1189 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1190 {
1191     switch ([event type]) {
1192         case NSLeftMouseDown:
1193         case NSRightMouseDown:
1194         case NSOtherMouseDown:
1195         case NSLeftMouseUp:
1196         case NSRightMouseUp:
1197         case NSOtherMouseUp:
1198         {
1199             NSView *topViewInEventWindow = [[event window] contentView];
1200             NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1201             while (viewContainingPoint != nil) {
1202                 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1203                     break;
1204                 }
1205                 viewContainingPoint = [viewContainingPoint superview];
1206             }
1207             if (viewContainingPoint != nil) {
1208                 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1209                 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1210         
1211                 return [NSDictionary dictionaryWithObjectsAndKeys:
1212                     [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1213                     elementInfo, WebActionElementKey,
1214                     [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1215                     [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1216                     URL, WebActionOriginalURLKey,
1217                     nil];
1218             }
1219         }
1220             
1221         // fall through
1222         
1223         default:
1224             return [NSDictionary dictionaryWithObjectsAndKeys:
1225                 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1226                 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1227                 URL, WebActionOriginalURLKey,
1228                 nil];
1229     }
1230 }
1231
1232 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1233 {
1234     WebNavigationType navType;
1235     if (isFormSubmission) {
1236         navType = WebNavigationTypeFormSubmitted;
1237     } else if (event == nil) {
1238         if (loadType == WebFrameLoadTypeReload) {
1239             navType = WebNavigationTypeReload;
1240         } else if (loadType == WebFrameLoadTypeForward
1241                    || loadType == WebFrameLoadTypeBack
1242                    || loadType == WebFrameLoadTypeIndexedBackForward) {
1243             navType = WebNavigationTypeBackForward;
1244         } else {
1245             navType = WebNavigationTypeOther;
1246         }
1247     } else {
1248         navType = WebNavigationTypeLinkClicked;
1249     }
1250     return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1251 }
1252
1253 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1254 {
1255     if (!request) {
1256         return;
1257     }
1258
1259     NSURL *URL = [request URL];
1260
1261     BOOL isRedirect = _private->quickRedirectComing;
1262     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1263     _private->quickRedirectComing = NO;
1264
1265     [[_private->frameLoader documentLoadState] replaceRequestURLForAnchorScrollWithURL:URL];
1266     if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1267         // NB: must happen after _setURL, since we add based on the current request.
1268         // Must also happen before we openURL and displace the scroll position, since
1269         // adding the BF item will save away scroll state.
1270
1271         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
1272         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1273         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
1274         // though its load is not yet done.  I think this all works out OK, for one because
1275         // we have already saved away the scroll and doc state for the long slow load,
1276         // but it's not an obvious case.
1277         [self _addBackForwardItemClippedAtTarget:NO];
1278     }
1279
1280     [_private->bridge scrollToAnchorWithURL:URL];
1281     
1282     if (!isRedirect) {
1283         // This will clear previousItem from the rest of the frame tree tree that didn't
1284         // doing any loading.  We need to make a pass on this now, since for anchor nav
1285         // we'll not go through a real load and reach Completed state
1286         [self _checkLoadComplete];
1287     }
1288
1289     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1290                       didChangeLocationWithinPageForFrame:self];
1291     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1292 }
1293
1294 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1295 {
1296     if (!request)
1297         return;
1298
1299     [self retain];
1300
1301     WebView *webView = nil;
1302     WebView *currentWebView = [self webView];
1303     id wd = [currentWebView UIDelegate];
1304     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1305         webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1306     else
1307         webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1308     if (!webView)
1309         goto exit;
1310
1311     WebFrame *frame = [webView mainFrame];
1312     if (!frame)
1313         goto exit;
1314
1315     [frame retain];
1316
1317     [[frame _bridge] setName:frameName];
1318
1319     [[webView _UIDelegateForwarder] webViewShow:webView];
1320
1321     [[frame _bridge] setOpener:[self _bridge]];
1322     [frame->_private->frameLoader _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1323
1324     [frame release];
1325
1326 exit:
1327     [self release];
1328 }
1329
1330 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1331 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1332 {
1333     BOOL isFormSubmission = (values != nil);
1334
1335     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1336     [request _web_setHTTPReferrer:referrer];
1337     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
1338     if (loadType == WebFrameLoadTypeReload) {
1339         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1340     }
1341
1342     // I believe this is never called with LoadSame.  If it is, we probably want to set the cache
1343     // policy of LoadFromOrigin, but I didn't test that.
1344     ASSERT(loadType != WebFrameLoadTypeSame);
1345
1346     NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1347     WebFormState *formState = nil;
1348     if (form && values) {
1349         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1350     }
1351
1352     if (target != nil) {
1353         WebFrame *targetFrame = [self findFrameNamed:target];
1354         if (targetFrame != nil) {
1355             [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1356         } else {
1357             [_private->frameLoader checkNewWindowPolicyForRequest:request
1358                                     action:action
1359                                  frameName:target
1360                                  formState:formState
1361                                    andCall:self
1362                               withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1363         }
1364         [request release];
1365         [formState release];
1366         return;
1367     }
1368
1369     WebDataSource *oldDataSource = [[self dataSource] retain];
1370
1371     BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1372
1373     // Make sure to do scroll to anchor processing even if the URL is
1374     // exactly the same so pages with '#' links and DHTML side effects
1375     // work properly.
1376     if (!isFormSubmission
1377         && loadType != WebFrameLoadTypeReload
1378         && loadType != WebFrameLoadTypeSame
1379         && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1380
1381         // We don't want to just scroll if a link from within a
1382         // frameset is trying to reload the frameset into _top.
1383         && ![_private->bridge isFrameSet]) {
1384         
1385         // Just do anchor navigation within the existing content.
1386         
1387         // We don't do this if we are submitting a form, explicitly reloading,
1388         // currently displaying a frameset, or if the new URL does not have a fragment.
1389         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1390
1391         // FIXME: What about load types other than Standard and Reload?
1392
1393         [[oldDataSource _documentLoadState] setTriggeringAction:action];
1394         [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1395         [_private->frameLoader checkNavigationPolicyForRequest:request
1396             dataSource:oldDataSource formState:formState
1397             andCall:self withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1398     } else {
1399         // must grab this now, since this load may stop the previous load and clear this flag
1400         BOOL isRedirect = _private->quickRedirectComing;
1401         [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1402         if (isRedirect) {
1403             LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1404             _private->quickRedirectComing = NO;
1405             [[[self provisionalDataSource] _documentLoadState] setIsClientRedirect:YES];
1406         } else if (sameURL) {
1407             // Example of this case are sites that reload the same URL with a different cookie
1408             // driving the generated content, or a master frame with links that drive a target
1409             // frame, where the user has clicked on the same link repeatedly.
1410             [_private->frameLoader setLoadType:WebFrameLoadTypeSame];
1411         }            
1412     }
1413
1414     [request release];
1415     [oldDataSource release];
1416     [formState release];
1417 }
1418
1419 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1420 {
1421     WebHistoryItem *parentItem = [_private currentItem];
1422     NSArray *childItems = [parentItem children];
1423     WebFrameLoadType loadType = [_private->frameLoader loadType];
1424     WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1425     WebHistoryItem *childItem = nil;
1426
1427     // If we're moving in the backforward list, we might want to replace the content
1428     // of this child frame with whatever was there at that point.
1429     // Reload will maintain the frame contents, LoadSame will not.
1430     if (childItems &&
1431         (loadType == WebFrameLoadTypeForward
1432          || loadType == WebFrameLoadTypeBack
1433          || loadType == WebFrameLoadTypeIndexedBackForward
1434          || loadType == WebFrameLoadTypeReload
1435          || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1436     {
1437         childItem = [parentItem childItemWithName:[childFrame name]];
1438         if (childItem) {
1439             // Use the original URL to ensure we get all the side-effects, such as
1440             // onLoad handlers, of any redirects that happened. An example of where
1441             // this is needed is Radar 3213556.
1442             URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1443             // These behaviors implied by these loadTypes should apply to the child frames
1444             childLoadType = loadType;
1445
1446             if (loadType == WebFrameLoadTypeForward
1447                 || loadType == WebFrameLoadTypeBack
1448                 || loadType == WebFrameLoadTypeIndexedBackForward)
1449             {
1450                 // For back/forward, remember this item so we can traverse any child items as child frames load
1451                 [childFrame->_private setProvisionalItem:childItem];
1452             } else {
1453                 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1454                 [childFrame->_private setCurrentItem:childItem];
1455             }
1456         }
1457     }
1458
1459     WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1460     if (archive) {
1461         [childFrame loadArchive:archive];
1462     } else {
1463         [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1464     }
1465 }
1466
1467 - (void)_postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target data:(NSArray *)postData contentType:(NSString *)contentType triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1468 {
1469     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1470     // This prevents a potential bug which may cause a page with a form that uses itself
1471     // as an action to be returned from the cache without submitting.
1472
1473     // FIXME: Where's the code that implements what the comment above says?
1474
1475     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1476     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1477     [request _web_setHTTPReferrer:referrer];
1478     [request setHTTPMethod:@"POST"];
1479     webSetHTTPBody(request, postData);
1480     [request _web_setHTTPContentType:contentType];
1481
1482     NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1483     WebFormState *formState = nil;
1484     if (form && values) {
1485         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1486     }
1487
1488     if (target != nil) {
1489         WebFrame *targetFrame = [self findFrameNamed:target];
1490
1491         if (targetFrame != nil) {
1492             [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1493         } else {
1494             [_private->frameLoader checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self
1495                 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1496         }
1497         [request release];
1498         [formState release];
1499         return;
1500     }
1501
1502     [_private->frameLoader _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1503
1504     [request release];
1505     [formState release];
1506 }
1507
1508 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
1509 {
1510     LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
1511
1512     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1513                                 willPerformClientRedirectToURL:URL
1514                                                          delay:seconds
1515                                                       fireDate:date
1516                                                       forFrame:self];
1517                                                       
1518     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1519     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1520     _private->sentRedirectNotification = YES;
1521     
1522     // If a "quick" redirect comes in an, we set a special mode so we treat the next
1523     // load as part of the same navigation.
1524
1525     if (![self dataSource] || isJavaScriptFormAction) {
1526         // If we don't have a dataSource, we have no "original" load on which to base a redirect,
1527         // so we better just treat the redirect as a normal load.
1528         _private->quickRedirectComing = NO;
1529         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1530     } else {
1531         _private->quickRedirectComing = lockHistory;
1532         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1533     }
1534 }
1535
1536 - (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
1537 {
1538     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1539     // the redirect succeeded.  We should either rename this API, or add a new method, like
1540     // -webView:didFinishClientRedirectForFrame:
1541     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1542                                didCancelClientRedirectForFrame:self];
1543     if (!cancelWithLoadInProgress)
1544         _private->quickRedirectComing = NO;
1545         
1546     _private->sentRedirectNotification = NO;
1547     
1548     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1549 }
1550
1551 - (void)_setTitle:(NSString *)title
1552 {
1553     [[_private currentItem] setTitle:title];
1554 }
1555
1556 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1557 {
1558     if (item) {
1559         NSView <WebDocumentView> *docView = [[self frameView] documentView];
1560         NSView *parent = [docView superview];
1561         // we might already be detached when this is called from detachFromParent, in which
1562         // case we don't want to override real data earlier gathered with (0,0)
1563         if (parent) {
1564             NSPoint point;
1565             if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1566                 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1567                 // ScrollView instead of using the one provided by the WebFrame
1568                 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1569                 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1570             } else {
1571                 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1572                 ASSERT([parent isKindOfClass:[NSClipView class]]);
1573                 point = [parent bounds].origin;
1574             }
1575             [item setScrollPoint:point];
1576         }
1577     }
1578 }
1579
1580 - (void)_defersCallbacksChanged
1581 {
1582     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1583         [frame->_private->frameLoader defersCallbacksChanged];
1584 }
1585
1586 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1587 {
1588     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1589         [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1590 }
1591
1592 - (void)_viewDidMoveToHostWindow
1593 {
1594     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1595         [[[frame frameView] documentView] viewDidMoveToHostWindow];
1596 }
1597
1598 - (void)_addChild:(WebFrame *)child
1599 {
1600     [[self _bridge] appendChild:[child _bridge]];
1601     [[[child dataSource] _documentLoadState] setOverrideEncoding:[[[self dataSource] _documentLoadState] overrideEncoding]];  
1602 }
1603
1604 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1605 // item, because we optimistically move it right away at the start of the operation. But when
1606 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1607 // Return the item that we would reset to, so we can decide later whether to actually reset.
1608 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1609 {
1610     WebFrameLoadType loadType = [_private->frameLoader loadType];
1611     if ((loadType == WebFrameLoadTypeForward
1612          || loadType == WebFrameLoadTypeBack
1613          || loadType == WebFrameLoadTypeIndexedBackForward)
1614         && self == [[self webView] mainFrame]) {
1615         return [_private currentItem];
1616     }
1617     return nil;
1618 }
1619
1620 - (WebHistoryItem *)_itemForSavingDocState
1621 {
1622     // For a standard page load, we will have a previous item set, which will be used to
1623     // store the form state.  However, in some cases we will have no previous item, and
1624     // the current item is the right place to save the state.  One example is when we
1625     // detach a bunch of frames because we are navigating from a site with frames to
1626     // another site.  Another is when saving the frame state of a frame that is not the
1627     // target of the current navigation (if we even decide to save with that granularity).
1628
1629     // Because of previousItem's "masking" of currentItem for this purpose, it's important
1630     // that previousItem be cleared at the end of a page transition.  We leverage the
1631     // checkLoadComplete recursion to achieve this goal.
1632
1633     WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
1634     return result;
1635 }
1636
1637 - (WebHistoryItem *)_itemForRestoringDocState
1638 {
1639     switch ([_private->frameLoader loadType]) {
1640         case WebFrameLoadTypeReload:
1641         case WebFrameLoadTypeReloadAllowingStaleData:
1642         case WebFrameLoadTypeSame:
1643         case WebFrameLoadTypeReplace:
1644             // Don't restore any form state on reload or loadSame
1645             return nil;
1646         case WebFrameLoadTypeBack:
1647         case WebFrameLoadTypeForward:
1648         case WebFrameLoadTypeIndexedBackForward:
1649         case WebFrameLoadTypeInternal:
1650         case WebFrameLoadTypeStandard:
1651             return [_private currentItem];
1652     }
1653     ASSERT_NOT_REACHED();
1654     return nil;
1655 }
1656
1657 // Walk the frame tree, telling all frames to save their form state into their current
1658 // history item.
1659 - (void)_saveDocumentAndScrollState
1660 {
1661     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1662         [[frame _bridge] saveDocumentState];
1663         [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
1664     }
1665 }
1666
1667 // used to decide to use loadType=Same
1668 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
1669 {
1670     WebHistoryItem *item = [_private currentItem];
1671     NSString* URLString = [URL _web_originalDataAsString];
1672     return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
1673 }    
1674
1675 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1676 {
1677     if (frameName == nil) {
1678         [self loadRequest:request];
1679         return;
1680     }
1681
1682     WebFrame *frame = [self findFrameNamed:frameName];
1683     
1684     if (frame != nil) {
1685         [frame loadRequest:request];
1686         return;
1687     }
1688
1689     NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1690     [_private->frameLoader checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1691 }
1692
1693 // Return next frame to be traversed, visiting children after parent
1694 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
1695 {
1696     return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
1697 }
1698
1699 // Return previous frame to be traversed, exact reverse order of _nextFrame
1700 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
1701 {
1702     return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
1703 }
1704
1705 - (BOOL)_shouldCreateRenderers
1706 {
1707     return [_private->bridge shouldCreateRenderers];
1708 }
1709
1710 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
1711 {
1712     if (!recurse)
1713         return [[self _bridge] numPendingOrLoadingRequests];
1714
1715     int num = 0;
1716     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1717         num += [[frame _bridge] numPendingOrLoadingRequests];
1718
1719     return num;
1720 }
1721
1722 - (void)_reloadForPluginChanges
1723 {
1724     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1725         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1726         if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
1727             [frame reload];
1728     }
1729 }
1730
1731 - (void)_attachScriptDebugger
1732 {
1733     if (!_private->scriptDebugger)
1734         _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
1735 }
1736
1737 - (void)_detachScriptDebugger
1738 {
1739     if (_private->scriptDebugger) {
1740         id old = _private->scriptDebugger;
1741         _private->scriptDebugger = nil;
1742         [old release];
1743     }
1744 }
1745
1746 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
1747 {
1748     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1749         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1750         if ([documentView isKindOfClass:[WebHTMLView class]])
1751             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1752     }
1753 }
1754
1755 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
1756 {
1757     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1758         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1759         if ([documentView isKindOfClass:[WebHTMLView class]])
1760             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1761     }
1762 }
1763
1764 - (void)_didReceiveServerRedirectForProvisionalLoadForFrame
1765 {
1766     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1767         didReceiveServerRedirectForProvisionalLoadForFrame:self];
1768 }
1769
1770 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
1771 {
1772     self = [super init];
1773     if (!self)
1774         return nil;
1775
1776     _private = [[WebFramePrivate alloc] init];
1777
1778     _private->bridge = bridge;
1779
1780     if (fv) {
1781         [_private setWebFrameView:fv];
1782         [fv _setWebFrame:self];
1783     }
1784     
1785     _private->frameLoader = [[WebFrameLoader alloc] initWithClient:self];
1786     
1787     ++WebFrameCount;
1788     
1789     return self;
1790 }
1791
1792 - (NSArray *)_documentViews
1793 {
1794     NSMutableArray *result = [NSMutableArray array];
1795     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1796         id docView = [[frame frameView] documentView];
1797         if (docView)
1798             [result addObject:docView];
1799     }
1800         
1801     return result;
1802 }
1803
1804 - (void)_updateBackground
1805 {
1806     BOOL drawsBackground = [[self webView] drawsBackground];
1807     NSColor *backgroundColor = [[self webView] backgroundColor];
1808
1809     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1810         // Never call setDrawsBackground:YES here on the scroll view or the background color will
1811         // flash between pages loads. setDrawsBackground:YES will be called in WebFrame's _frameLoadCompleted.
1812         if (!drawsBackground)
1813             [[[frame frameView] _scrollView] setDrawsBackground:NO];
1814         [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
1815         id documentView = [[frame frameView] documentView];
1816         if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
1817             [documentView setDrawsBackground:drawsBackground];
1818         if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
1819             [documentView setBackgroundColor:backgroundColor];
1820         [[frame _bridge] setDrawsBackground:drawsBackground];
1821         [[frame _bridge] setBaseBackgroundColor:backgroundColor];
1822     }
1823 }
1824
1825 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
1826 {
1827     _private->internalLoadDelegate = internalLoadDelegate;
1828 }
1829
1830 - (id)_internalLoadDelegate
1831 {
1832     return _private->internalLoadDelegate;
1833 }
1834
1835 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1836 {
1837     ASSERT(request != nil);
1838     
1839     WebView *wv = [self webView];
1840     id delegate = [wv resourceLoadDelegate];
1841     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1842     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1843     WebDataSource *dataSource = [self dataSource];
1844     
1845     if (implementations.delegateImplementsIdentifierForRequest) {
1846         *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1847     } else {
1848         *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1849     }
1850         
1851     NSURLRequest *newRequest;
1852     if (implementations.delegateImplementsWillSendRequest) {
1853         newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1854     } else {
1855         newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1856     }
1857     
1858     if (newRequest == nil) {
1859         *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1860     } else {
1861         *error = nil;
1862     }
1863     
1864     return newRequest;
1865 }
1866
1867 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error 
1868 {    
1869     WebView *wv = [self webView];
1870     id delegate = [wv resourceLoadDelegate];
1871     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1872     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1873     WebDataSource *dataSource = [self dataSource];
1874         
1875     if (response != nil) {
1876         if (implementations.delegateImplementsDidReceiveResponse) {
1877             [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1878         } else {
1879             [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1880         }
1881     }
1882     
1883     if (length > 0) {
1884         if (implementations.delegateImplementsDidReceiveContentLength) {
1885             [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1886         } else {
1887             [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1888         }
1889     }
1890     
1891     if (error == nil) {
1892         if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
1893             [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1894         } else {
1895             [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1896         }
1897         [self _checkLoadComplete];
1898     } else {
1899         [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
1900     }
1901 }
1902
1903 - (void)_safeLoadURL:(NSURL *)URL
1904 {
1905    // Call the bridge because this is where our security checks are made.
1906     [[self _bridge] loadURL:URL 
1907                     referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
1908                       reload:NO
1909                  userGesture:YES       
1910                       target:nil
1911              triggeringEvent:[NSApp currentEvent]
1912                         form:nil 
1913                   formValues:nil];
1914 }
1915
1916 - (void)_unmarkAllMisspellings
1917 {
1918     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1919         [[frame _bridge] unmarkAllMisspellings];
1920 }
1921
1922 - (BOOL)_hasSelection
1923 {
1924     id documentView = [[self frameView] documentView];    
1925     
1926     // optimization for common case to avoid creating potentially large selection string
1927     if ([documentView isKindOfClass:[WebHTMLView class]]) {
1928         DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
1929         return selectedDOMRange && ![selectedDOMRange collapsed];
1930     }
1931     
1932     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1933         return [[documentView selectedString] length] > 0;
1934     
1935     return NO;
1936 }
1937
1938 - (void)_clearSelection
1939 {
1940     id documentView = [[self frameView] documentView];    
1941     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1942         [documentView deselectAll];
1943 }
1944
1945 #ifndef NDEBUG
1946
1947 - (BOOL)_atMostOneFrameHasSelection;
1948 {
1949     // FIXME: 4186050 is one known case that makes this debug check fail
1950     BOOL found = NO;
1951     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1952         if ([frame _hasSelection]) {
1953             if (found)
1954                 return NO;
1955             found = YES;
1956         }
1957     }
1958
1959     return YES;
1960 }
1961 #endif
1962
1963 - (WebFrame *)_findFrameWithSelection
1964 {
1965     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1966         if ([frame _hasSelection])
1967             return frame;
1968
1969     return nil;
1970 }
1971
1972 - (void)_clearSelectionInOtherFrames
1973 {
1974     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
1975     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
1976     // notification sent when the first responder changes in general (Radar 2573089).
1977     WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
1978     if (frameWithSelection != self)
1979         [frameWithSelection _clearSelection];
1980
1981     // While we're in the general area of selection and frames, check that there is only one now.
1982     ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
1983 }
1984
1985 - (void)_stopLoadingSubframes
1986 {
1987     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
1988         [child stopLoading];
1989 }
1990
1991 - (BOOL)_subframeIsLoading
1992 {
1993     // It's most likely that the last added frame is the last to load so we walk backwards.
1994     for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1995         if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1996             return YES;
1997     return NO;
1998 }
1999
2000 - (void)_addPlugInView:(NSView *)plugInView
2001 {
2002     ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
2003     ASSERT(![_private->plugInViews containsObject:plugInView]);
2004     
2005     if (!_private->plugInViews)
2006         _private->plugInViews = [[NSMutableSet alloc] init];
2007         
2008     [plugInView setWebFrame:self];
2009     [_private->plugInViews addObject:plugInView];
2010 }
2011
2012 - (void)_removeAllPlugInViews
2013 {
2014     if (!_private->plugInViews)
2015         return;
2016     
2017     [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
2018     [_private->plugInViews release];
2019     _private->plugInViews = nil;
2020 }
2021
2022 // This is called when leaving a page or closing the WebView
2023 - (void)_willCloseURL
2024 {
2025     [self _removeAllPlugInViews];
2026 }
2027
2028 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2029 {
2030     [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
2031     
2032     if ([_private->frameLoader loadType] == WebFrameLoadTypeReload)
2033         [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2034     
2035     // Don't set the cookie policy URL if it's already been set.
2036     if ([request mainDocumentURL] == nil) {
2037         if (mainResource && (self == [[self webView] mainFrame] || f))
2038             [request setMainDocumentURL:[request URL]];
2039         else
2040             [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
2041     }
2042     
2043     if (mainResource)
2044         [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"];
2045 }
2046
2047 - (BOOL)_isMainFrame
2048 {
2049     return self == [[self webView] mainFrame];
2050 }
2051
2052 - (void)_addInspector:(WebInspector *)inspector
2053 {
2054     if (!_private->inspectors)
2055         _private->inspectors = [[NSMutableSet alloc] init];
2056     ASSERT(![_private->inspectors containsObject:inspector]);
2057     [_private->inspectors addObject:inspector];
2058 }
2059
2060 - (void)_removeInspector:(WebInspector *)inspector
2061 {
2062     ASSERT([_private->inspectors containsObject:inspector]);
2063     [_private->inspectors removeObject:inspector];
2064 }
2065
2066 - (WebFrameLoader *)_frameLoader
2067 {
2068     return _private->frameLoader;
2069 }
2070
2071 - (void)_provisionalLoadStarted
2072 {
2073     [_private->frameLoader provisionalLoadStarted];
2074     [_private->bridge provisionalLoadStarted];
2075     
2076     // FIXME: This is OK as long as no one resizes the window,
2077     // but in the case where someone does, it means garbage outside
2078     // the occupied part of the scroll view.
2079     [[[self frameView] _scrollView] setDrawsBackground:NO];
2080     
2081     // Cache the page, if possible.
2082     // Don't write to the cache if in the middle of a redirect, since we will want to
2083     // store the final page we end up on.
2084     // No point writing to the cache on a reload or loadSame, since we will just write
2085     // over it again when we leave that page.
2086     WebHistoryItem *item = [_private currentItem];
2087     WebFrameLoadType loadType = [_private->frameLoader loadType];
2088     if ([self _canCachePage]
2089             && [_private->bridge canCachePage]
2090             && item
2091             && !_private->quickRedirectComing
2092             && loadType != WebFrameLoadTypeReload 
2093             && loadType != WebFrameLoadTypeReloadAllowingStaleData
2094             && loadType != WebFrameLoadTypeSame
2095             && ![[self dataSource] isLoading]
2096             && ![[_private->frameLoader documentLoadState] isStopping]) {
2097         if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
2098             if (![item pageCache]){
2099                 // Add the items to this page's cache.
2100                 if ([self _createPageCacheForItem:item]) {
2101                     LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2102                     
2103                     // See if any page caches need to be purged after the addition of this
2104                     // new page cache.
2105                     [self _purgePageCache];
2106                 }
2107                 else
2108                     LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
2109             }
2110         } else
2111             // Put the document into a null state, so it can be restored correctly.
2112             [_private->bridge clear];
2113     } else
2114         LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2115 }
2116
2117 - (void)_prepareForDataSourceReplacement
2118 {
2119     if (![_private->frameLoader dataSource]) {
2120         ASSERT(![self _childFrameCount]);
2121         return;
2122     }
2123     
2124     // Make sure that any work that is triggered by resigning first reponder can get done.
2125     // The main example where this came up is the textDidEndEditing that is sent to the
2126     // FormsDelegate (3223413).  We need to do this before _detachChildren, since that will
2127     // remove the views as a side-effect of freeing the bridge, at which point we can't
2128     // post the FormDelegate messages.
2129     //
2130     // Note that this can also take FirstResponder away from a child of our frameView that
2131     // is not in a child frame's view.  This is OK because we are in the process
2132     // of loading new content, which will blow away all editors in this top frame, and if
2133     // a non-editor is firstReponder it will not be affected by endEditingFor:.
2134     // Potentially one day someone could write a DocView whose editors were not all
2135     // replaced by loading new content, but that does not apply currently.
2136     NSView *frameView = [self frameView];
2137     NSWindow *window = [frameView window];
2138     NSResponder *firstResp = [window firstResponder];
2139     if ([firstResp isKindOfClass:[NSView class]]
2140         && [(NSView *)firstResp isDescendantOf:frameView])
2141     {
2142         [window endEditingFor:firstResp];
2143     }
2144     
2145     [self _detachChildren];
2146 }
2147
2148 - (void)_frameLoadCompleted
2149 {
2150     NSScrollView *sv = [[self frameView] _scrollView];
2151     if ([[self webView] drawsBackground])
2152         [sv setDrawsBackground:YES];
2153     [_private setPreviousItem:nil];
2154     [_private->frameLoader frameLoadCompleted];
2155 }
2156
2157 - (WebDataSource *)_dataSourceForDocumentLoadState:(WebDocumentLoadState *)loadState
2158 {
2159     return [(WebDocumentLoadStateMac *)loadState dataSource];
2160 }
2161
2162 - (WebDocumentLoadState *)_createDocumentLoadStateWithRequest:(NSURLRequest *)request
2163 {
2164     WebDocumentLoadStateMac *loadState = [[WebDocumentLoadStateMac alloc] initWithRequest:request];
2165     
2166     WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoadState:loadState];
2167     [loadState setDataSource:dataSource];
2168     [dataSource release];
2169
2170     return loadState;
2171 }
2172
2173 /*
2174     There is a race condition between the layout and load completion that affects restoring the scroll position.
2175     We try to restore the scroll position at both the first layout and upon load completion.
2176
2177     1) If first layout happens before the load completes, we want to restore the scroll position then so that the
2178        first time we draw the page is already scrolled to the right place, instead of starting at the top and later
2179        jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
2180        which case the restore silent fails and we will fix it in when we try to restore on doc completion.
2181     2) If the layout happens after the load completes, the attempt to restore at load completion time silently
2182        fails.  We then successfully restore it when the layout happens.
2183  */
2184
2185 - (void)_restoreScrollPositionAndViewState
2186 {
2187     ASSERT([_private currentItem]);
2188     NSView <WebDocumentView> *docView = [[self frameView] documentView];
2189     NSPoint point = [[_private currentItem] scrollPoint];
2190     if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {        
2191         id state = [[_private currentItem] viewState];
2192         if (state) {
2193             [(id <_WebDocumentViewState>)docView setViewState:state];
2194         }
2195         
2196         [(id <_WebDocumentViewState>)docView setScrollPoint:point];
2197     } else {
2198         [docView scrollPoint:point];
2199     }
2200 }
2201
2202 @end
2203
2204 @implementation WebFrame (WebPrivate)
2205
2206 // FIXME: this exists only as a convenience for Safari, consider moving there
2207 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
2208 {
2209     return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
2210 }
2211
2212 - (void)_setShouldCreateRenderers:(BOOL)f
2213 {
2214     [_private->bridge setShouldCreateRenderers:f];
2215 }
2216
2217 - (NSColor *)_bodyBackgroundColor
2218 {
2219     return [_private->bridge bodyBackgroundColor];
2220 }
2221
2222 - (BOOL)_isFrameSet
2223 {
2224     return [_private->bridge isFrameSet];
2225 }
2226
2227 - (BOOL)_firstLayoutDone
2228 {
2229     return [_private->frameLoader firstLayoutDone];
2230 }
2231
2232 - (WebFrameLoadType)_loadType
2233 {
2234     return [_private->frameLoader loadType];
2235 }
2236
2237 @end
2238
2239 @implementation WebFormState : NSObject
2240
2241 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2242 {
2243     self = [super init];
2244     if (!self)
2245         return nil;
2246     
2247     _form = [form retain];
2248     _values = [values copy];
2249     _sourceFrame = [sourceFrame retain];
2250     return self;
2251 }
2252
2253 - (void)dealloc
2254 {
2255     [_form release];
2256     [_values release];
2257     [_sourceFrame release];
2258     [super dealloc];
2259 }
2260
2261 - (DOMElement *)form
2262 {
2263     return _form;
2264 }
2265
2266 - (NSDictionary *)values
2267 {
2268     return _values;
2269 }
2270
2271 - (WebFrame *)sourceFrame
2272 {
2273     return _sourceFrame;
2274 }
2275
2276 @end
2277
2278 @implementation WebFrame
2279
2280 - (id)init
2281 {
2282     return [self initWithName:nil webFrameView:nil webView:nil];
2283 }
2284
2285 // FIXME: this method can't work any more and should be marked deprecated
2286 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2287 {
2288     return [self _initWithWebFrameView:fv webView:v bridge:nil];
2289 }
2290
2291 - (void)dealloc
2292 {
2293     ASSERT(_private->bridge == nil);
2294     [_private release];
2295
2296     --WebFrameCount;
2297
2298     [super dealloc];
2299 }
2300
2301 - (void)finalize
2302 {
2303     ASSERT(_private->bridge == nil);
2304
2305     --WebFrameCount;
2306
2307     [super finalize];
2308 }
2309
2310 - (NSString *)name
2311 {
2312     return [[self _bridge] name];
2313 }
2314
2315 - (WebFrameView *)frameView
2316 {
2317     return [_private webFrameView];
2318 }
2319
2320 - (WebView *)webView
2321 {
2322     return [[[self _bridge] page] webView];
2323 }
2324
2325 - (DOMDocument *)DOMDocument
2326 {
2327     return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2328 }
2329
2330 - (DOMHTMLElement *)frameElement
2331 {
2332     return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2333 }
2334
2335 - (WebDataSource *)provisionalDataSource
2336 {
2337     return [_private->frameLoader provisionalDataSource];
2338 }
2339
2340 - (WebDataSource *)dataSource
2341 {
2342     return [_private->frameLoader dataSource];
2343 }
2344
2345 - (void)loadRequest:(NSURLRequest *)request
2346 {
2347     // FIXME: is this the right place to reset loadType? Perhaps this should be done
2348     // after loading is finished or aborted.
2349     [_private->frameLoader setLoadType:WebFrameLoadTypeStandard];
2350     [_private->frameLoader _loadRequest:request archive:nil];
2351 }
2352
2353 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2354 {
2355     NSURLRequest *request = [self _webDataRequestForData:data 
2356                                                 MIMEType:MIMEType 
2357                                         textEncodingName:encodingName 
2358                                                  baseURL:URL
2359                                           unreachableURL:unreachableURL];
2360     [self loadRequest:request];
2361 }
2362
2363
2364 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2365 {
2366     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2367 }
2368
2369 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2370 {
2371     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
2372     [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
2373 }
2374
2375 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2376 {
2377     [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2378 }
2379
2380 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2381 {
2382     [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2383 }
2384
2385 - (void)loadArchive:(WebArchive *)archive
2386 {
2387     WebResource *mainResource = [archive mainResource];
2388     if (mainResource) {
2389         NSURLRequest *request = [self _webDataRequestForData:[mainResource data] 
2390                                                     MIMEType:[mainResource MIMEType]
2391                                             textEncodingName:[mainResource textEncodingName]
2392                                                      baseURL:[mainResource URL]
2393                                               unreachableURL:nil];
2394         [_private->frameLoader _loadRequest:request archive:archive];
2395     }
2396 }
2397
2398 - (void)stopLoading
2399 {
2400     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2401     if (_private->isStoppingLoad)
2402         return;
2403
2404     _private->isStoppingLoad = YES;
2405     
2406     [_private->frameLoader invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2407
2408     [self _stopLoadingSubframes];
2409     [_private->frameLoader stopLoading];
2410
2411     _private->isStoppingLoad = NO;
2412 }
2413
2414 - (void)reload
2415 {
2416     [_private->frameLoader reload];
2417 }
2418
2419 - (WebFrame *)findFrameNamed:(NSString *)name
2420 {
2421     return Frame([[self _bridge] findFrameNamed:name]);
2422 }
2423
2424 - (WebFrame *)parentFrame
2425 {
2426     return [[Frame([[self _bridge] parent]) retain] autorelease];
2427 }
2428
2429 - (NSArray *)childFrames
2430 {
2431     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2432     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2433         [children addObject:child];
2434
2435     return children;
2436 }
2437
2438 @end
2439
2440 @implementation WebFrame (WebFrameLoaderClient)
2441
2442 - (void)_resetBackForwardList
2443 {
2444     // Note this doesn't verify the current load type as a b/f operation because it is called from
2445     // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
2446     ASSERT(self == [[self webView] mainFrame]);
2447     WebHistoryItem *resetItem = [_private currentItem];
2448     if (resetItem)
2449         [[[self webView] backForwardList] goToItem:resetItem];
2450 }
2451
2452 - (BOOL)_quickRedirectComing
2453 {
2454     return _private->quickRedirectComing;
2455 }
2456
2457 - (BOOL)_provisionalItemIsTarget
2458 {
2459     return [[_private provisionalItem] isTargetItem];
2460 }
2461
2462 - (BOOL)_loadProvisionalItemFromPageCache
2463 {
2464     WebHistoryItem *item = [_private provisionalItem];
2465     if (![item hasPageCache])
2466         return NO;
2467     NSDictionary *pageCache = [item pageCache];
2468     if (![pageCache objectForKey:WebCorePageCacheStateKey])
2469         return NO;
2470     LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
2471     [[self provisionalDataSource] _loadFromPageCache:pageCache];
2472     return YES;
2473 }
2474
2475 @end