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