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