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