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