WebCore:
[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     for (WebFrame *frame = self; frame; frame = [frame parentFrame])
1014         [frame _checkLoadCompleteForThisFrame];
1015 }
1016
1017 - (WebFrameBridge *)_bridge
1018 {
1019     return _private->bridge;
1020 }
1021
1022 - (void)_handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1023 {
1024     NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1025     WebView *wv = [self webView];
1026     _private->delegateIsHandlingUnimplementablePolicy = YES;
1027     [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:self];    
1028     _private->delegateIsHandlingUnimplementablePolicy = NO;
1029 }
1030
1031 // helper method that determines whether the subframes described by the item's subitems
1032 // match our own current frameset
1033 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
1034 {
1035     NSArray *childItems = [item children];
1036     int numChildItems = [childItems count];
1037     int numChildFrames = [self _childFrameCount];
1038     if (numChildFrames != numChildItems)
1039         return NO;
1040
1041     int i;
1042     for (i = 0; i < numChildItems; i++) {
1043         NSString *itemTargetName = [[childItems objectAtIndex:i] target];
1044         //Search recursive here?
1045         if (![self _immediateChildFrameNamed:itemTargetName])
1046             return NO; // couldn't match the i'th itemTarget
1047     }
1048
1049     return YES; // found matches for all itemTargets
1050 }
1051
1052 - (BOOL)_shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
1053 {
1054     return !(([currentURL fragment] || [destinationURL fragment]) &&
1055     [[currentURL _webkit_URLByRemovingFragment] isEqual: [destinationURL _webkit_URLByRemovingFragment]]);
1056 }
1057
1058 // Walk the frame tree and ensure that the URLs match the URLs in the item.
1059 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
1060 {
1061     NSURL *currentURL = [[[self dataSource] request] URL];
1062
1063     if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
1064         return NO;
1065     
1066     NSArray *childItems = [item children];
1067     WebHistoryItem *childItem;
1068     WebFrame *childFrame;
1069     int i, count = [childItems count];
1070     for (i = 0; i < count; i++){
1071         childItem = [childItems objectAtIndex:i];
1072         childFrame = [self _immediateChildFrameNamed:[childItem target]];
1073         if (![childFrame _URLsMatchItem: childItem])
1074             return NO;
1075     }
1076     
1077     return YES;
1078 }
1079
1080 // loads content into this frame, as specified by item
1081 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)loadType
1082 {
1083     NSURL *itemURL = [item URL];
1084     NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
1085     NSURL *currentURL = [[[self dataSource] request] URL];
1086     NSArray *formData = [item formData];
1087
1088     // Are we navigating to an anchor within the page?
1089     // Note if we have child frames we do a real reload, since the child frames might not
1090     // match our current frame structure, or they might not have the right content.  We could
1091     // check for all that as an additional optimization.
1092     // We also do not do anchor-style navigation if we're posting a form.
1093     
1094     // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
1095     // Perhaps they should.
1096     if (!formData && ![self _shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
1097     {
1098 #if 0
1099         // FIXME:  We need to normalize the code paths for anchor navigation.  Something
1100         // like the following line of code should be done, but also accounting for correct
1101         // updates to the back/forward list and scroll position.
1102         // rjw 4/9/03 See 3223929.
1103         [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
1104 #endif
1105         // must do this maintenance here, since we don't go through a real page reload
1106         [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1107         // FIXME: form state might want to be saved here too
1108
1109         // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
1110         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
1111         [_private->bridge scrollToAnchorWithURL:[item URL]];
1112     
1113         // must do this maintenance here, since we don't go through a real page reload
1114         [_private setCurrentItem:item];
1115         [self _restoreScrollPositionAndViewState];
1116
1117         // Fake the URL change by updating the data source's request.  This will no longer
1118         // be necessary if we do the better fix described above.
1119         NSMutableURLRequest *hackedRequest = [[[self dataSource] request] mutableCopy];
1120         [hackedRequest setURL: itemURL];
1121         [[self dataSource] __adoptRequest:hackedRequest];
1122         [hackedRequest release];
1123         
1124         [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1125                                didChangeLocationWithinPageForFrame:self];
1126         [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1127     } else {
1128         // Remember this item so we can traverse any child items as child frames load
1129         [_private setProvisionalItem:item];
1130
1131         WebDataSource *newDataSource;
1132         BOOL inPageCache = NO;
1133         
1134         // Check if we'll be using the page cache.  We only use the page cache
1135         // if one exists and it is less than _backForwardCacheExpirationInterval
1136         // seconds old.  If the cache is expired it gets flushed here.
1137         if ([item hasPageCache]){
1138             NSDictionary *pageCache = [item pageCache];
1139             NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
1140             NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
1141
1142             if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
1143                 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
1144                 [self _loadDataSource:newDataSource withLoadType:loadType formState:nil];   
1145                 inPageCache = YES;
1146             }         
1147             else {
1148                 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]);
1149                 [item setHasPageCache: NO];
1150             }
1151         }
1152         
1153         if (!inPageCache) {
1154             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1155             [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1156
1157             // If this was a repost that failed the page cache, we might try to repost the form.
1158             NSDictionary *action;
1159             if (formData) {
1160                 [request setHTTPMethod:@"POST"];
1161                 [request _web_setHTTPReferrer:[item formReferrer]];
1162                 webSetHTTPBody(request, formData);
1163                 [request _web_setHTTPContentType:[item formContentType]];
1164
1165                 // Slight hack to test if the WF cache contains the page we're going to.  We want
1166                 // to know this before talking to the policy delegate, since it affects whether we
1167                 // show the DoYouReallyWantToRepost nag.
1168                 //
1169                 // This trick has a small bug (3123893) where we might find a cache hit, but then
1170                 // have the item vanish when we try to use it in the ensuing nav.  This should be
1171                 // extremely rare, but in that case the user will get an error on the navigation.
1172                 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1173                 NSURLResponse *synchResponse = nil;
1174                 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1175                 if (synchResponse == nil) { 
1176                     // Not in WF cache
1177                     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1178                     action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1179                 } else {
1180                     // We can use the cache, don't use navType=resubmit
1181                     action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1182                 }
1183             } else {
1184                 switch (loadType) {
1185                     case WebFrameLoadTypeReload:
1186                         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1187                         break;
1188                     case WebFrameLoadTypeBack:
1189                     case WebFrameLoadTypeForward:
1190                     case WebFrameLoadTypeIndexedBackForward:
1191                         if (![[itemURL scheme] isEqual:@"https"]) {
1192                             [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1193                         }
1194                         break;
1195                     case WebFrameLoadTypeStandard:
1196                     case WebFrameLoadTypeInternal:
1197                         // no-op: leave as protocol default
1198                         // FIXME:  I wonder if we ever hit this case
1199                         break;
1200                     case WebFrameLoadTypeSame:
1201                     case WebFrameLoadTypeReloadAllowingStaleData:
1202                     default:
1203                         ASSERT_NOT_REACHED();
1204                 }
1205
1206                 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1207             }
1208
1209             [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1210             [request release];
1211         }
1212     }
1213 }
1214
1215 // The general idea here is to traverse the frame tree and the item tree in parallel,
1216 // tracking whether each frame already has the content the item requests.  If there is
1217 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
1218 // reload that frame, and all its kids.
1219 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(WebFrameLoadType)type
1220 {
1221     NSURL *itemURL = [item URL];
1222     NSURL *currentURL = [[[self dataSource] request] URL];
1223
1224     // Always reload the target frame of the item we're going to.  This ensures that we will
1225     // do -some- load for the transition, which means a proper notification will be posted
1226     // to the app.
1227     // The exact URL has to match, including fragment.  We want to go through the _load
1228     // method, even if to do a within-page navigation.
1229     // The current frame tree and the frame tree snapshot in the item have to match.
1230     if (![item isTargetItem] &&
1231         [itemURL isEqual:currentURL] &&
1232         (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1233         [self _childFramesMatchItem:item])
1234     {
1235         // This content is good, so leave it alone and look for children that need reloading
1236
1237         // Save form state (works from currentItem, since prevItem is nil)
1238         ASSERT(![_private previousItem]);
1239         [_private->bridge saveDocumentState];
1240         [self _saveScrollPositionAndViewStateToItem:[_private currentItem]];
1241         
1242         [_private setCurrentItem:item];
1243
1244         // Restore form state (works from currentItem)
1245         [_private->bridge restoreDocumentState];
1246         // Restore the scroll position (taken in favor of going back to the anchor)
1247         [self _restoreScrollPositionAndViewState];
1248         
1249         NSArray *childItems = [item children];
1250         int numChildItems = childItems ? [childItems count] : 0;
1251         int i;
1252         for (i = numChildItems - 1; i >= 0; i--) {
1253             WebHistoryItem *childItem = [childItems objectAtIndex:i];
1254             NSString *childName = [childItem target];
1255             WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1256             ASSERT(fromChildItem || [fromItem isTargetItem]);
1257             WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1258             ASSERT(childFrame);
1259             [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1260         }
1261     } else {
1262         // We need to reload the content
1263         [self _loadItem:item withLoadType:type];
1264     }
1265 }
1266
1267 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1268 // This includes recursion to handle loading into framesets properly
1269 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(WebFrameLoadType)type
1270 {
1271     ASSERT(![self parentFrame]);
1272     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1273     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1274     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1275     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1276     if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {    
1277         WebBackForwardList *backForwardList = [[self webView] backForwardList];
1278         WebHistoryItem *currItem = [backForwardList currentItem];
1279         // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1280         // - plus, it only makes sense for the top level of the operation through the frametree,
1281         // as opposed to happening for some/one of the page commits that might happen soon
1282         [backForwardList goToItem:item];
1283         [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1284     }
1285 }
1286
1287 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1288 {
1289     switch ([event type]) {
1290         case NSLeftMouseDown:
1291         case NSRightMouseDown:
1292         case NSOtherMouseDown:
1293         case NSLeftMouseUp:
1294         case NSRightMouseUp:
1295         case NSOtherMouseUp:
1296         {
1297             NSView *topViewInEventWindow = [[event window] contentView];
1298             NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1299             while (viewContainingPoint != nil) {
1300                 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1301                     break;
1302                 }
1303                 viewContainingPoint = [viewContainingPoint superview];
1304             }
1305             if (viewContainingPoint != nil) {
1306                 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1307                 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1308         
1309                 return [NSDictionary dictionaryWithObjectsAndKeys:
1310                     [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1311                     elementInfo, WebActionElementKey,
1312                     [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1313                     [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1314                     URL, WebActionOriginalURLKey,
1315                     nil];
1316             }
1317         }
1318             
1319         // fall through
1320         
1321         default:
1322             return [NSDictionary dictionaryWithObjectsAndKeys:
1323                 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1324                 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1325                 URL, WebActionOriginalURLKey,
1326                 nil];
1327     }
1328 }
1329
1330 -(NSDictionary *)_actionInformationForLoadType:(WebFrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1331 {
1332     WebNavigationType navType;
1333     if (isFormSubmission) {
1334         navType = WebNavigationTypeFormSubmitted;
1335     } else if (event == nil) {
1336         if (loadType == WebFrameLoadTypeReload) {
1337             navType = WebNavigationTypeReload;
1338         } else if (loadType == WebFrameLoadTypeForward
1339                    || loadType == WebFrameLoadTypeBack
1340                    || loadType == WebFrameLoadTypeIndexedBackForward) {
1341             navType = WebNavigationTypeBackForward;
1342         } else {
1343             navType = WebNavigationTypeOther;
1344         }
1345     } else {
1346         navType = WebNavigationTypeLinkClicked;
1347     }
1348     return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1349 }
1350
1351 - (void)_invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1352 {
1353     [_private->listener _invalidate];
1354     [_private->listener release];
1355     _private->listener = nil;
1356
1357     NSURLRequest *request = _private->policyRequest;
1358     NSString *frameName = _private->policyFrameName;
1359     id target = _private->policyTarget;
1360     SEL selector = _private->policySelector;
1361     WebFormState *formState = _private->policyFormState;
1362
1363     _private->policyRequest = nil;
1364     _private->policyFrameName = nil;
1365     _private->policyTarget = nil;
1366     _private->policySelector = nil;
1367     _private->policyFormState = nil;
1368
1369     if (call) {
1370         if (frameName) {
1371             [target performSelector:selector withObject:nil withObject:nil withObject:nil];
1372         } else {
1373             [target performSelector:selector withObject:nil withObject:nil];
1374         }
1375     }
1376
1377     [request release];
1378     [frameName release];
1379     [target release];
1380     [formState release];
1381 }
1382
1383 - (void)_setPolicyDataSource:(WebDataSource *)dataSource
1384 {
1385     [dataSource retain];
1386     [_private->policyDataSource release];
1387     _private->policyDataSource = dataSource;
1388 }
1389
1390 - (void)_checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1391 {
1392     WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc]
1393         _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1394
1395     _private->policyRequest = [request retain];
1396     _private->policyTarget = [target retain];
1397     _private->policyFrameName = [frameName retain];
1398     _private->policySelector = selector;
1399     _private->listener = [listener retain];
1400     _private->policyFormState = [formState retain];
1401
1402     WebView *wv = [self webView];
1403     [[wv _policyDelegateForwarder] webView:wv
1404             decidePolicyForNewWindowAction:action
1405                                    request:request
1406                               newFrameName:frameName
1407                           decisionListener:listener];
1408     
1409     [listener release];
1410 }
1411
1412 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1413 {
1414     NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1415     NSString *frameName = [[_private->policyFrameName retain] autorelease];
1416     id target = [[_private->policyTarget retain] autorelease];
1417     SEL selector = _private->policySelector;
1418     WebFormState *formState = [[_private->policyFormState retain] autorelease];
1419
1420     // will release _private->policy* objects, hence the above retains
1421     [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1422
1423     BOOL shouldContinue = NO;
1424
1425     switch (policy) {
1426     case WebPolicyIgnore:
1427         break;
1428     case WebPolicyDownload:
1429         // FIXME: should download full request
1430         [[self webView] _downloadURL:[request URL]];
1431         break;
1432     case WebPolicyUse:
1433         shouldContinue = YES;
1434         break;
1435     default:
1436         ASSERT_NOT_REACHED();
1437     }
1438
1439     [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:frameName withObject:formState];
1440 }
1441
1442 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)request
1443                               dataSource:(WebDataSource *)dataSource
1444                                formState:(WebFormState *)formState
1445                                  andCall:(id)target
1446                             withSelector:(SEL)selector
1447 {    
1448     NSDictionary *action = [dataSource _triggeringAction];
1449     if (action == nil) {
1450         action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1451         [dataSource _setTriggeringAction:action];
1452     }
1453         
1454     // Don't ask more than once for the same request or if we are loading an empty URL.
1455     // This avoids confusion on the part of the client.
1456     if ([request isEqual:[dataSource _lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1457         [target performSelector:selector withObject:request withObject:nil];
1458         return;
1459     }
1460     
1461     // We are always willing to show alternate content for unreachable URLs;
1462     // treat it like a reload so it maintains the right state for b/f list.
1463     if ([request _webDataRequestUnreachableURL] != nil) {
1464         if (_private->policyLoadType == WebFrameLoadTypeForward
1465             || _private->policyLoadType == WebFrameLoadTypeBack
1466             || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1467             _private->policyLoadType = WebFrameLoadTypeReload;
1468         }
1469         [target performSelector:selector withObject:request withObject:nil];
1470         return;
1471     }
1472     
1473     [dataSource _setLastCheckedRequest:request];
1474
1475     WebPolicyDecisionListener *listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterNavigationPolicy:)];
1476     
1477     ASSERT(_private->policyRequest == nil);
1478     _private->policyRequest = [request retain];
1479     ASSERT(_private->policyTarget == nil);
1480     _private->policyTarget = [target retain];
1481     _private->policySelector = selector;
1482     ASSERT(_private->listener == nil);
1483     _private->listener = [listener retain];
1484     ASSERT(_private->policyFormState == nil);
1485     _private->policyFormState = [formState retain];
1486
1487     WebView *wv = [self webView];
1488     _private->delegateIsDecidingNavigationPolicy = YES;
1489     [[wv _policyDelegateForwarder] webView:wv
1490            decidePolicyForNavigationAction:action
1491                                    request:request
1492                                      frame:self
1493                           decisionListener:listener];
1494     _private->delegateIsDecidingNavigationPolicy = NO;
1495     
1496     [listener release];
1497 }
1498
1499 -(void)_continueAfterNavigationPolicy:(WebPolicyAction)policy
1500 {
1501     NSURLRequest *request = [[_private->policyRequest retain] autorelease];
1502     id target = [[_private->policyTarget retain] autorelease];
1503     SEL selector = _private->policySelector;
1504     WebFormState *formState = [[_private->policyFormState retain] autorelease];
1505     
1506     // will release _private->policy* objects, hence the above retains
1507     [self _invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1508
1509     BOOL shouldContinue = NO;
1510
1511     switch (policy) {
1512     case WebPolicyIgnore:
1513         break;
1514     case WebPolicyDownload:
1515         // FIXME: should download full request
1516         [[self webView] _downloadURL:[request URL]];
1517         break;
1518     case WebPolicyUse:
1519         if (![WebView _canHandleRequest:request]) {
1520             [self _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1521         } else {
1522             shouldContinue = YES;
1523         }
1524         break;
1525     default:
1526         ASSERT_NOT_REACHED();
1527     }
1528
1529     [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1530 }
1531
1532 -(void)_continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1533 {
1534     if (!request) {
1535         return;
1536     }
1537
1538     NSURL *URL = [request URL];
1539     WebDataSource *dataSrc = [self dataSource];
1540
1541     BOOL isRedirect = _private->quickRedirectComing;
1542     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1543     _private->quickRedirectComing = NO;
1544
1545     [dataSrc _setURL:URL];
1546     if (!isRedirect && ![self _shouldTreatURLAsSameAsCurrent:URL]) {
1547         // NB: must happen after _setURL, since we add based on the current request.
1548         // Must also happen before we openURL and displace the scroll position, since
1549         // adding the BF item will save away scroll state.
1550
1551         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
1552         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
1553         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
1554         // though its load is not yet done.  I think this all works out OK, for one because
1555         // we have already saved away the scroll and doc state for the long slow load,
1556         // but it's not an obvious case.
1557         [self _addBackForwardItemClippedAtTarget:NO];
1558     }
1559
1560     [_private->bridge scrollToAnchorWithURL:URL];
1561     
1562     if (!isRedirect) {
1563         // This will clear previousItem from the rest of the frame tree tree that didn't
1564         // doing any loading.  We need to make a pass on this now, since for anchor nav
1565         // we'll not go through a real load and reach Completed state
1566         [self _checkLoadComplete];
1567     }
1568
1569     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1570                       didChangeLocationWithinPageForFrame:self];
1571     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
1572 }
1573
1574 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1575 {
1576     if (!request) {
1577         return;
1578     }
1579     
1580     WebView *webView = nil;
1581     WebView *currentWebView = [self webView];
1582     id wd = [currentWebView UIDelegate];
1583     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1584         webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1585     else
1586         webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1587         
1588
1589     WebFrame *frame = [webView mainFrame];
1590     [[frame _bridge] setName:frameName];
1591
1592     [[webView _UIDelegateForwarder] webViewShow:webView];
1593
1594     [[self _bridge] setOpener:[frame _bridge]];
1595     [_private->frameLoader _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1596 }
1597
1598
1599 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
1600 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1601 {
1602     BOOL isFormSubmission = (values != nil);
1603
1604     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1605     [request _web_setHTTPReferrer:referrer];
1606     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
1607     if (loadType == WebFrameLoadTypeReload) {
1608         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1609     }
1610
1611     // I believe this is never called with LoadSame.  If it is, we probably want to set the cache
1612     // policy of LoadFromOrigin, but I didn't test that.
1613     ASSERT(loadType != WebFrameLoadTypeSame);
1614
1615     NSDictionary *action = [self _actionInformationForLoadType:loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
1616     WebFormState *formState = nil;
1617     if (form && values) {
1618         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1619     }
1620
1621     if (target != nil) {
1622         WebFrame *targetFrame = [self findFrameNamed:target];
1623         if (targetFrame != nil) {
1624             [targetFrame _loadURL:URL referrer:referrer loadType:loadType target:nil triggeringEvent:event form:form formValues:values];
1625         } else {
1626             [self _checkNewWindowPolicyForRequest:request
1627                                     action:action
1628                                  frameName:target
1629                                  formState:formState
1630                                    andCall:self
1631                               withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1632         }
1633         [request release];
1634         [formState release];
1635         return;
1636     }
1637
1638     WebDataSource *oldDataSource = [[self dataSource] retain];
1639
1640     BOOL sameURL = [self _shouldTreatURLAsSameAsCurrent:URL];
1641
1642     // Make sure to do scroll to anchor processing even if the URL is
1643     // exactly the same so pages with '#' links and DHTML side effects
1644     // work properly.
1645     if (!isFormSubmission
1646         && loadType != WebFrameLoadTypeReload
1647         && loadType != WebFrameLoadTypeSame
1648         && ![self _shouldReloadForCurrent:URL andDestination:[_private->bridge URL]]
1649
1650         // We don't want to just scroll if a link from within a
1651         // frameset is trying to reload the frameset into _top.
1652         && ![_private->bridge isFrameSet]) {
1653         
1654         // Just do anchor navigation within the existing content.
1655         
1656         // We don't do this if we are submitting a form, explicitly reloading,
1657         // currently displaying a frameset, or if the new URL does not have a fragment.
1658         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1659         
1660         
1661         // FIXME: What about load types other than Standard and Reload?
1662
1663         [oldDataSource _setTriggeringAction:action];
1664         [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1665         [self _checkNavigationPolicyForRequest:request
1666                                     dataSource:oldDataSource
1667                                      formState:formState
1668                                        andCall:self
1669                                   withSelector:@selector(_continueFragmentScrollAfterNavigationPolicy:formState:)];
1670     } else {
1671         // must grab this now, since this load may stop the previous load and clear this flag
1672         BOOL isRedirect = _private->quickRedirectComing;
1673         [_private->frameLoader _loadRequest:request triggeringAction:action loadType:loadType formState:formState];
1674         if (isRedirect) {
1675             LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [self name], self, (int)isRedirect);
1676             _private->quickRedirectComing = NO;
1677             [[self provisionalDataSource] _setIsClientRedirect:YES];
1678         } else if (sameURL) {
1679             // Example of this case are sites that reload the same URL with a different cookie
1680             // driving the generated content, or a master frame with links that drive a target
1681             // frame, where the user has clicked on the same link repeatedly.
1682             [self _setLoadType:WebFrameLoadTypeSame];
1683         }            
1684     }
1685
1686     [request release];
1687     [oldDataSource release];
1688     [formState release];
1689 }
1690
1691 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1692 {
1693     WebHistoryItem *parentItem = [_private currentItem];
1694     NSArray *childItems = [parentItem children];
1695     WebFrameLoadType loadType = [self _loadType];
1696     WebFrameLoadType childLoadType = WebFrameLoadTypeInternal;
1697     WebHistoryItem *childItem = nil;
1698
1699     // If we're moving in the backforward list, we might want to replace the content
1700     // of this child frame with whatever was there at that point.
1701     // Reload will maintain the frame contents, LoadSame will not.
1702     if (childItems &&
1703         (loadType == WebFrameLoadTypeForward
1704          || loadType == WebFrameLoadTypeBack
1705          || loadType == WebFrameLoadTypeIndexedBackForward
1706          || loadType == WebFrameLoadTypeReload
1707          || loadType == WebFrameLoadTypeReloadAllowingStaleData))
1708     {
1709         childItem = [parentItem childItemWithName:[childFrame name]];
1710         if (childItem) {
1711             // Use the original URL to ensure we get all the side-effects, such as
1712             // onLoad handlers, of any redirects that happened. An example of where
1713             // this is needed is Radar 3213556.
1714             URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1715             // These behaviors implied by these loadTypes should apply to the child frames
1716             childLoadType = loadType;
1717
1718             if (loadType == WebFrameLoadTypeForward
1719                 || loadType == WebFrameLoadTypeBack
1720                 || loadType == WebFrameLoadTypeIndexedBackForward)
1721             {
1722                 // For back/forward, remember this item so we can traverse any child items as child frames load
1723                 [childFrame->_private setProvisionalItem:childItem];
1724             } else {
1725                 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1726                 [childFrame->_private setCurrentItem:childItem];
1727             }
1728         }
1729     }
1730
1731     WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1732     if (archive) {
1733         [childFrame loadArchive:archive];
1734     } else {
1735         [childFrame _loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1736     }
1737 }
1738
1739 - (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
1740 {
1741     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1742     // This prevents a potential bug which may cause a page with a form that uses itself
1743     // as an action to be returned from the cache without submitting.
1744
1745     // FIXME: Where's the code that implements what the comment above says?
1746
1747     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1748     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1749     [request _web_setHTTPReferrer:referrer];
1750     [request setHTTPMethod:@"POST"];
1751     webSetHTTPBody(request, postData);
1752     [request _web_setHTTPContentType:contentType];
1753
1754     NSDictionary *action = [self _actionInformationForLoadType:WebFrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1755     WebFormState *formState = nil;
1756     if (form && values) {
1757         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1758     }
1759
1760     if (target != nil) {
1761         WebFrame *targetFrame = [self findFrameNamed:target];
1762
1763         if (targetFrame != nil) {
1764             [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1765         } else {
1766             [self _checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1767         }
1768         [request release];
1769         [formState release];
1770         return;
1771     }
1772
1773     [_private->frameLoader _loadRequest:request triggeringAction:action loadType:WebFrameLoadTypeStandard formState:formState];
1774
1775     [request release];
1776     [formState release];
1777 }
1778
1779 - (void)_clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
1780 {
1781     LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [self name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
1782
1783     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1784                                 willPerformClientRedirectToURL:URL
1785                                                          delay:seconds
1786                                                       fireDate:date
1787                                                       forFrame:self];
1788                                                       
1789     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
1790     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
1791     _private->sentRedirectNotification = YES;
1792     
1793     // If a "quick" redirect comes in an, we set a special mode so we treat the next
1794     // load as part of the same navigation.
1795
1796     if (![self dataSource] || isJavaScriptFormAction) {
1797         // If we don't have a dataSource, we have no "original" load on which to base a redirect,
1798         // so we better just treat the redirect as a normal load.
1799         _private->quickRedirectComing = NO;
1800         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1801     } else {
1802         _private->quickRedirectComing = lockHistory;
1803         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1804     }
1805 }
1806
1807 - (void)_clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
1808 {
1809     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
1810     // the redirect succeeded.  We should either rename this API, or add a new method, like
1811     // -webView:didFinishClientRedirectForFrame:
1812     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1813                                didCancelClientRedirectForFrame:self];
1814     if (!cancelWithLoadInProgress)
1815         _private->quickRedirectComing = NO;
1816         
1817     _private->sentRedirectNotification = NO;
1818     
1819     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [self name], self, (int)_private->quickRedirectComing);
1820 }
1821
1822 - (void)_setTitle:(NSString *)title
1823 {
1824     [[_private currentItem] setTitle:title];
1825 }
1826
1827 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1828 {
1829     if (item) {
1830         NSView <WebDocumentView> *docView = [[self frameView] documentView];
1831         NSView *parent = [docView superview];
1832         // we might already be detached when this is called from detachFromParent, in which
1833         // case we don't want to override real data earlier gathered with (0,0)
1834         if (parent) {
1835             NSPoint point;
1836             if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1837                 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1838                 // ScrollView instead of using the one provided by the WebFrame
1839                 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1840                 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1841             } else {
1842                 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1843                 ASSERT([parent isKindOfClass:[NSClipView class]]);
1844                 point = [parent bounds].origin;
1845             }
1846             [item setScrollPoint:point];
1847         }
1848     }
1849 }
1850
1851 /*
1852     There is a race condition between the layout and load completion that affects restoring the scroll position.
1853     We try to restore the scroll position at both the first layout and upon load completion.
1854
1855     1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1856        first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1857        jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
1858        which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1859     2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1860        fails.  We then successfully restore it when the layout happens.
1861  */
1862
1863 - (void)_restoreScrollPositionAndViewState
1864 {
1865     ASSERT([_private currentItem]);
1866     NSView <WebDocumentView> *docView = [[self frameView] documentView];
1867     NSPoint point = [[_private currentItem] scrollPoint];
1868     if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {        
1869         id state = [[_private currentItem] viewState];
1870         if (state) {
1871             [(id <_WebDocumentViewState>)docView setViewState:state];
1872         }
1873         
1874         [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1875     } else {
1876         [docView scrollPoint:point];
1877     }
1878 }
1879
1880 - (void)_defersCallbacksChanged
1881 {
1882     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1883         [[frame provisionalDataSource] _defersCallbacksChanged];
1884         [[frame dataSource] _defersCallbacksChanged];
1885     }
1886 }
1887
1888 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1889 {
1890     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1891         [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1892 }
1893
1894 - (void)_viewDidMoveToHostWindow
1895 {
1896     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1897         [[[frame frameView] documentView] viewDidMoveToHostWindow];
1898 }
1899
1900 - (void)_addChild:(WebFrame *)child
1901 {
1902     [[self _bridge] appendChild:[child _bridge]];
1903     [[child dataSource] _setOverrideEncoding:[[self dataSource] _overrideEncoding]];  
1904 }
1905
1906 - (void)_resetBackForwardList
1907 {
1908     // Note this doesn't verify the current load type as a b/f operation because it is called from
1909     // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
1910     ASSERT(self == [[self webView] mainFrame]);
1911     WebHistoryItem *resetItem = [_private currentItem];
1912     if (resetItem)
1913         [[[self webView] backForwardList] goToItem:resetItem];
1914 }
1915
1916 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1917 // item, because we optimistically move it right away at the start of the operation. But when
1918 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1919 // Return the item that we would reset to, so we can decide later whether to actually reset.
1920 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1921 {
1922     WebFrameLoadType loadType = [self _loadType];
1923     if ((loadType == WebFrameLoadTypeForward
1924          || loadType == WebFrameLoadTypeBack
1925          || loadType == WebFrameLoadTypeIndexedBackForward)
1926         && self == [[self webView] mainFrame]) {
1927         return [_private currentItem];
1928     }
1929     return nil;
1930 }
1931
1932 - (WebHistoryItem *)_itemForSavingDocState
1933 {
1934     // For a standard page load, we will have a previous item set, which will be used to
1935     // store the form state.  However, in some cases we will have no previous item, and
1936     // the current item is the right place to save the state.  One example is when we
1937     // detach a bunch of frames because we are navigating from a site with frames to
1938     // another site.  Another is when saving the frame state of a frame that is not the
1939     // target of the current navigation (if we even decide to save with that granularity).
1940
1941     // Because of previousItem's "masking" of currentItem for this purpose, it's important
1942     // that previousItem be cleared at the end of a page transition.  We leverage the
1943     // checkLoadComplete recursion to achieve this goal.
1944
1945     WebHistoryItem *result = [_private previousItem] ? [_private previousItem] : [_private currentItem];
1946     return result;
1947 }
1948
1949 - (WebHistoryItem *)_itemForRestoringDocState
1950 {
1951     switch ([self _loadType]) {
1952         case WebFrameLoadTypeReload:
1953         case WebFrameLoadTypeReloadAllowingStaleData:
1954         case WebFrameLoadTypeSame:
1955         case WebFrameLoadTypeReplace:
1956             // Don't restore any form state on reload or loadSame
1957             return nil;
1958         case WebFrameLoadTypeBack:
1959         case WebFrameLoadTypeForward:
1960         case WebFrameLoadTypeIndexedBackForward:
1961         case WebFrameLoadTypeInternal:
1962         case WebFrameLoadTypeStandard:
1963             return [_private currentItem];
1964     }
1965     ASSERT_NOT_REACHED();
1966     return nil;
1967 }
1968
1969 // Walk the frame tree, telling all frames to save their form state into their current
1970 // history item.
1971 - (void)_saveDocumentAndScrollState
1972 {
1973     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1974         [[frame _bridge] saveDocumentState];
1975         [frame _saveScrollPositionAndViewStateToItem:[frame->_private currentItem]];
1976     }
1977 }
1978
1979 // Called after the FormsDelegate is done processing willSubmitForm:
1980 -(void)_continueAfterWillSubmitForm:(WebPolicyAction)policy
1981 {
1982     if (_private->listener) {
1983         [_private->listener _invalidate];
1984         [_private->listener release];
1985         _private->listener = nil;
1986     }
1987     [_private->frameLoader startLoading];
1988 }
1989
1990 -(void)_continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1991 {
1992     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1993     // nil _private->policyDataSource because loading the alternate page will have passed
1994     // through this method already, nested; otherwise, _private->policyDataSource should still be set.
1995     ASSERT(_private->policyDataSource || [[self provisionalDataSource] unreachableURL] != nil);
1996
1997     WebHistoryItem *item = [_private provisionalItem];
1998
1999     // Two reasons we can't continue:
2000     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
2001     //       is the user responding Cancel to the form repost nag sheet.
2002     //    2) User responded Cancel to an alert popped up by the before unload event handler.
2003     // The "before unload" event handler runs only for the main frame.
2004     BOOL canContinue = request && ([[self webView] mainFrame] != self || [_private->bridge shouldClose]);
2005
2006     if (!canContinue) {
2007         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
2008         // need to report that the client redirect was cancelled.
2009         if (_private->quickRedirectComing)
2010             [self _clientRedirectCancelledOrFinished:NO];
2011
2012         [self _setPolicyDataSource:nil];
2013         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
2014         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
2015         // we only do this when punting a navigation for the target frame or top-level frame.  
2016         if (([item isTargetItem] || [[self webView] mainFrame] == self)
2017             && (_private->policyLoadType == WebFrameLoadTypeForward
2018                 || _private->policyLoadType == WebFrameLoadTypeBack
2019                 || _private->policyLoadType == WebFrameLoadTypeIndexedBackForward))
2020             [[[self webView] mainFrame] _resetBackForwardList];
2021         return;
2022     }
2023     
2024     WebFrameLoadType loadType = _private->policyLoadType;
2025     WebDataSource *dataSource = [_private->policyDataSource retain];
2026     
2027     [self stopLoading];
2028     [self _setLoadType:loadType];
2029
2030     [_private->frameLoader startProvisionalLoad:dataSource];
2031
2032     [dataSource release];
2033     [self _setPolicyDataSource:nil];
2034     
2035     
2036     if (self == [[self webView] mainFrame])
2037         LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
2038
2039     if ((loadType == WebFrameLoadTypeForward ||
2040         loadType == WebFrameLoadTypeBack ||
2041         loadType == WebFrameLoadTypeIndexedBackForward) &&
2042         [item hasPageCache]){
2043         NSDictionary *pageCache = [[_private provisionalItem] pageCache];
2044         if ([pageCache objectForKey:WebCorePageCacheStateKey]){
2045             LOG (PageCache, "Restoring page from back/forward cache, %@\n", [[_private provisionalItem] URL]);
2046             [[_private->frameLoader provisionalDataSource] _loadFromPageCache:pageCache];
2047             return;
2048         }
2049     }
2050
2051     if (formState) {
2052         // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
2053         // mechanism across the willSubmitForm callout.
2054         _private->listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueAfterWillSubmitForm:)];
2055         [[[self webView] _formDelegate] frame:self sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:_private->listener];
2056     } 
2057     else {
2058         [self _continueAfterWillSubmitForm:WebPolicyUse];
2059     }
2060 }
2061
2062 - (void)_loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)loadType formState:(WebFormState *)formState
2063 {
2064     ASSERT([self webView] != nil);
2065
2066     // Unfortunately the view must be non-nil, this is ultimately due
2067     // to parser requiring a FrameView.  We should fix this dependency.
2068
2069     ASSERT([self frameView] != nil);
2070
2071     _private->policyLoadType = loadType;
2072
2073     WebFrame *parentFrame = [self parentFrame];
2074     if (parentFrame)
2075         [newDataSource _setOverrideEncoding:[[parentFrame dataSource] _overrideEncoding]];
2076     [newDataSource _setWebFrame:self];
2077
2078     [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2079
2080     [self _setPolicyDataSource:newDataSource];
2081
2082     [self _checkNavigationPolicyForRequest:[newDataSource request]
2083                                 dataSource:newDataSource
2084                                  formState:formState
2085                                    andCall:self
2086                               withSelector:@selector(_continueLoadRequestAfterNavigationPolicy:formState:)];
2087 }
2088
2089 // used to decide to use loadType=Same
2090 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
2091 {
2092     WebHistoryItem *item = [_private currentItem];
2093     NSString* URLString = [URL _web_originalDataAsString];
2094     return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
2095 }    
2096
2097 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
2098 {
2099     if (frameName == nil) {
2100         [self loadRequest:request];
2101         return;
2102     }
2103
2104     WebFrame *frame = [self findFrameNamed:frameName];
2105     
2106     if (frame != nil) {
2107         [frame loadRequest:request];
2108         return;
2109     }
2110
2111     NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
2112     [self _checkNewWindowPolicyForRequest:request action:(NSDictionary *)action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
2113 }
2114
2115 // Return next frame to be traversed, visiting children after parent
2116 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
2117 {
2118     return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
2119 }
2120
2121 // Return previous frame to be traversed, exact reverse order of _nextFrame
2122 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
2123 {
2124     return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
2125 }
2126
2127 - (void)_setShouldCreateRenderers:(BOOL)f
2128 {
2129     [_private->bridge setShouldCreateRenderers:f];
2130 }
2131
2132 - (BOOL)_shouldCreateRenderers
2133 {
2134     return [_private->bridge shouldCreateRenderers];
2135 }
2136
2137 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
2138 {
2139     if (!recurse)
2140         return [[self _bridge] numPendingOrLoadingRequests];
2141
2142     int num = 0;
2143     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2144         num += [[frame _bridge] numPendingOrLoadingRequests];
2145
2146     return num;
2147 }
2148
2149 - (NSColor *)_bodyBackgroundColor
2150 {
2151     return [_private->bridge bodyBackgroundColor];
2152 }
2153
2154 - (void)_reloadForPluginChanges
2155 {
2156     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2157         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2158         if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
2159             [frame reload];
2160     }
2161 }
2162
2163 - (void)_attachScriptDebugger
2164 {
2165     if (!_private->scriptDebugger)
2166         _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
2167 }
2168
2169 - (void)_detachScriptDebugger
2170 {
2171     if (_private->scriptDebugger) {
2172         id old = _private->scriptDebugger;
2173         _private->scriptDebugger = nil;
2174         [old release];
2175     }
2176 }
2177
2178 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
2179 {
2180     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2181         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2182         if ([documentView isKindOfClass:[WebHTMLView class]])
2183             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
2184     }
2185 }
2186
2187 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
2188 {
2189     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2190         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
2191         if ([documentView isKindOfClass:[WebHTMLView class]])
2192             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
2193     }
2194 }
2195
2196 - (BOOL)_firstLayoutDone
2197 {
2198     return _private->firstLayoutDone;
2199 }
2200
2201 @end
2202
2203 @implementation WebFrame (WebInternal)
2204
2205 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
2206 {
2207     self = [super init];
2208     if (!self)
2209         return nil;
2210
2211     _private = [[WebFramePrivate alloc] init];
2212
2213     _private->bridge = bridge;
2214
2215     if (fv) {
2216         [_private setWebFrameView:fv];
2217         [fv _setWebFrame:self];
2218     }
2219     
2220     _private->frameLoader = [[WebFrameLoader alloc] initWithWebFrame:self];
2221     
2222     ++WebFrameCount;
2223     
2224     return self;
2225 }
2226
2227 - (NSArray *)_documentViews
2228 {
2229     NSMutableArray *result = [NSMutableArray array];
2230     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2231         id docView = [[frame frameView] documentView];
2232         if (docView)
2233             [result addObject:docView];
2234     }
2235         
2236     return result;
2237 }
2238
2239 - (void)_updateBackground
2240 {
2241     BOOL drawsBackground = [[self webView] drawsBackground];
2242     NSColor *backgroundColor = [[self webView] backgroundColor];
2243
2244     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2245         // Never call setDrawsBackground:YES on the scroll view or the background color will
2246         // flash between pages loads, very noticeable during the PLT.
2247         if (!drawsBackground)
2248             [[[frame frameView] _scrollView] setDrawsBackground:NO];
2249         [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
2250         id documentView = [[frame frameView] documentView];
2251         if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
2252             [documentView setDrawsBackground:drawsBackground];
2253         if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
2254             [documentView setBackgroundColor:backgroundColor];
2255         [[frame _bridge] setDrawsBackground:drawsBackground];
2256         [[frame _bridge] setBaseBackgroundColor:backgroundColor];
2257     }
2258 }
2259
2260 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
2261 {
2262     _private->internalLoadDelegate = internalLoadDelegate;
2263 }
2264
2265 - (id)_internalLoadDelegate
2266 {
2267     return _private->internalLoadDelegate;
2268 }
2269
2270 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
2271 {
2272     ASSERT(request != nil);
2273     
2274     WebView *wv = [self webView];
2275     id delegate = [wv resourceLoadDelegate];
2276     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2277     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2278     WebDataSource *dataSource = [self dataSource];
2279     
2280     if (implementations.delegateImplementsIdentifierForRequest) {
2281         *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2282     } else {
2283         *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
2284     }
2285         
2286     NSURLRequest *newRequest;
2287     if (implementations.delegateImplementsWillSendRequest) {
2288         newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2289     } else {
2290         newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
2291     }
2292     
2293     if (newRequest == nil) {
2294         *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
2295     } else {
2296         *error = nil;
2297     }
2298     
2299     return newRequest;
2300 }
2301
2302 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error 
2303 {    
2304     WebView *wv = [self webView];
2305     id delegate = [wv resourceLoadDelegate];
2306     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
2307     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
2308     WebDataSource *dataSource = [self dataSource];
2309         
2310     if (response != nil) {
2311         if (implementations.delegateImplementsDidReceiveResponse) {
2312             [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2313         } else {
2314             [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
2315         }
2316     }
2317     
2318     if (length > 0) {
2319         if (implementations.delegateImplementsDidReceiveContentLength) {
2320             [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2321         } else {
2322             [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
2323         }
2324     }
2325     
2326     if (error == nil) {
2327         if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
2328             [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2329         } else {
2330             [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
2331         }
2332         [self _checkLoadComplete];
2333     } else {
2334         [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
2335     }
2336 }
2337
2338 - (void)_safeLoadURL:(NSURL *)URL
2339 {
2340    // Call the bridge because this is where our security checks are made.
2341     [[self _bridge] loadURL:URL 
2342                     referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2343                       reload:NO
2344                  userGesture:YES       
2345                       target:nil
2346              triggeringEvent:[NSApp currentEvent]
2347                         form:nil 
2348                   formValues:nil];
2349 }
2350
2351 - (void)_unmarkAllMisspellings
2352 {
2353     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2354         [[frame _bridge] unmarkAllMisspellings];
2355 }
2356
2357 - (void)_didFirstLayout
2358 {
2359     if ([[self webView] backForwardList]) {
2360         WebFrameLoadType loadType = [self _loadType];
2361         if (loadType == WebFrameLoadTypeForward ||
2362             loadType == WebFrameLoadTypeBack ||
2363             loadType == WebFrameLoadTypeIndexedBackForward)
2364         {
2365             [self _restoreScrollPositionAndViewState];
2366         }
2367     }
2368     
2369     _private->firstLayoutDone = YES;
2370 }
2371
2372
2373 - (BOOL)_hasSelection
2374 {
2375     id documentView = [[self frameView] documentView];    
2376     
2377     // optimization for common case to avoid creating potentially large selection string
2378     if ([documentView isKindOfClass:[WebHTMLView class]]) {
2379         DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
2380         return selectedDOMRange && ![selectedDOMRange collapsed];
2381     }
2382     
2383     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2384         return [[documentView selectedString] length] > 0;
2385     
2386     return NO;
2387 }
2388
2389 - (void)_clearSelection
2390 {
2391     id documentView = [[self frameView] documentView];    
2392     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
2393         [documentView deselectAll];
2394 }
2395
2396 #ifndef NDEBUG
2397
2398 - (BOOL)_atMostOneFrameHasSelection;
2399 {
2400     // FIXME: 4186050 is one known case that makes this debug check fail
2401     BOOL found = NO;
2402     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
2403         if ([frame _hasSelection]) {
2404             if (found)
2405                 return NO;
2406             found = YES;
2407         }
2408     }
2409
2410     return YES;
2411 }
2412 #endif
2413
2414 - (WebFrame *)_findFrameWithSelection
2415 {
2416     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
2417         if ([frame _hasSelection])
2418             return frame;
2419
2420     return nil;
2421 }
2422
2423 - (void)_clearSelectionInOtherFrames
2424 {
2425     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
2426     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
2427     // notification sent when the first responder changes in general (Radar 2573089).
2428     WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
2429     if (frameWithSelection != self)
2430         [frameWithSelection _clearSelection];
2431
2432     // While we're in the general area of selection and frames, check that there is only one now.
2433     ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
2434 }
2435
2436 - (void)_stopLoadingSubframes
2437 {
2438     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2439         [child stopLoading];
2440 }
2441
2442 - (BOOL)_subframeIsLoading
2443 {
2444     // It's most likely that the last added frame is the last to load so we walk backwards.
2445     for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
2446         if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
2447             return YES;
2448     return NO;
2449 }
2450
2451 - (void)_addPlugInView:(NSView *)plugInView
2452 {
2453     ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
2454     ASSERT(![_private->plugInViews containsObject:plugInView]);
2455     
2456     if (!_private->plugInViews)
2457         _private->plugInViews = [[NSMutableSet alloc] init];
2458         
2459     [plugInView setWebFrame:self];
2460     [_private->plugInViews addObject:plugInView];
2461 }
2462
2463 - (void)_removeAllPlugInViews
2464 {
2465     if (!_private->plugInViews)
2466         return;
2467     
2468     [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
2469     [_private->plugInViews release];
2470     _private->plugInViews = nil;
2471 }
2472
2473 // This is called when leaving a page or closing the WebView
2474 - (void)_willCloseURL
2475 {
2476     [self _removeAllPlugInViews];
2477 }
2478
2479 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2480 {
2481     [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
2482     
2483     if (_private->loadType == WebFrameLoadTypeReload)
2484         [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2485     
2486     // Don't set the cookie policy URL if it's already been set.
2487     if ([request mainDocumentURL] == nil) {
2488         if (mainResource && (self == [[self webView] mainFrame] || f))
2489             [request setMainDocumentURL:[request URL]];
2490         else
2491             [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
2492     }
2493     
2494     if (mainResource)
2495         [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"];
2496 }
2497
2498 - (BOOL)_isMainFrame
2499 {
2500     return self == [[self webView] mainFrame];
2501 }
2502
2503 - (void)_addInspector:(WebInspector *)inspector
2504 {
2505     if (!_private->inspectors)
2506         _private->inspectors = [[NSMutableSet alloc] init];
2507     ASSERT(![_private->inspectors containsObject:inspector]);
2508     [_private->inspectors addObject:inspector];
2509 }
2510
2511 - (void)_removeInspector:(WebInspector *)inspector
2512 {
2513     ASSERT([_private->inspectors containsObject:inspector]);
2514     [_private->inspectors removeObject:inspector];
2515 }
2516
2517 - (WebFrameLoader *)_frameLoader
2518 {
2519     return _private->frameLoader;
2520 }
2521
2522 - (void)_provisionalLoadStarted
2523 {
2524     _private->firstLayoutDone = NO;
2525     [_private->bridge provisionalLoadStarted];
2526     
2527     // FIXME: This is OK as long as no one resizes the window,
2528     // but in the case where someone does, it means garbage outside
2529     // the occupied part of the scroll view.
2530     [[[self frameView] _scrollView] setDrawsBackground:NO];
2531     
2532     // Cache the page, if possible.
2533     // Don't write to the cache if in the middle of a redirect, since we will want to
2534     // store the final page we end up on.
2535     // No point writing to the cache on a reload or loadSame, since we will just write
2536     // over it again when we leave that page.
2537     WebHistoryItem *item = [_private currentItem];
2538     WebFrameLoadType loadType = [self _loadType];
2539     if ([self _canCachePage]
2540         && [_private->bridge canCachePage]
2541     && item
2542     && !_private->quickRedirectComing
2543     && loadType != WebFrameLoadTypeReload 
2544     && loadType != WebFrameLoadTypeReloadAllowingStaleData
2545     && loadType != WebFrameLoadTypeSame
2546     && ![[self dataSource] isLoading]
2547     && ![[self dataSource] _isStopping]) {
2548         if ([[[self dataSource] representation] isKindOfClass: [WebHTMLRepresentation class]]) {
2549             if (![item pageCache]){
2550                 
2551                 // Add the items to this page's cache.
2552                 if ([self _createPageCacheForItem:item]) {
2553                     LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2554                     
2555                     // See if any page caches need to be purged after the addition of this
2556                     // new page cache.
2557                     [self _purgePageCache];
2558                 }
2559                 else
2560                     LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
2561             }
2562         } else
2563             // Put the document into a null state, so it can be restored correctly.
2564             [_private->bridge clear];
2565     } else
2566         LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
2567 }
2568
2569 - (void)_prepareForDataSourceReplacement
2570 {
2571     if (![_private->frameLoader dataSource]) {
2572         ASSERT(![self _childFrameCount]);
2573         return;
2574     }
2575     
2576     // Make sure that any work that is triggered by resigning first reponder can get done.
2577     // The main example where this came up is the textDidEndEditing that is sent to the
2578     // FormsDelegate (3223413).  We need to do this before _detachChildren, since that will
2579     // remove the views as a side-effect of freeing the bridge, at which point we can't
2580     // post the FormDelegate messages.
2581     //
2582     // Note that this can also take FirstResponder away from a child of our frameView that
2583     // is not in a child frame's view.  This is OK because we are in the process
2584     // of loading new content, which will blow away all editors in this top frame, and if
2585     // a non-editor is firstReponder it will not be affected by endEditingFor:.
2586     // Potentially one day someone could write a DocView whose editors were not all
2587     // replaced by loading new content, but that does not apply currently.
2588     NSView *frameView = [self frameView];
2589     NSWindow *window = [frameView window];
2590     NSResponder *firstResp = [window firstResponder];
2591     if ([firstResp isKindOfClass:[NSView class]]
2592         && [(NSView *)firstResp isDescendantOf:frameView])
2593     {
2594         [window endEditingFor:firstResp];
2595     }
2596     
2597     [self _detachChildren];
2598 }
2599
2600 - (void)_frameLoadCompleted
2601 {
2602     NSScrollView *sv = [[self frameView] _scrollView];
2603     if ([[self webView] drawsBackground])
2604         [sv setDrawsBackground:YES];
2605     [_private setPreviousItem:nil];
2606     // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
2607     if ([_private->frameLoader dataSource])
2608         _private->firstLayoutDone = YES;
2609 }
2610
2611 - (BOOL)_shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
2612 {
2613     NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
2614     if (unreachableURL == nil) {
2615         return NO;
2616     }
2617     
2618     if (_private->policyLoadType != WebFrameLoadTypeForward
2619         && _private->policyLoadType != WebFrameLoadTypeBack
2620         && _private->policyLoadType != WebFrameLoadTypeIndexedBackForward) {
2621         return NO;
2622     }
2623     
2624     // We only treat unreachableURLs specially during the delegate callbacks
2625     // for provisional load errors and navigation policy decisions. The former
2626     // case handles well-formed URLs that can't be loaded, and the latter
2627     // case handles malformed URLs and unknown schemes. Loading alternate content
2628     // at other times behaves like a standard load.
2629     WebDataSource *compareDataSource = nil;
2630     if (_private->delegateIsDecidingNavigationPolicy || _private->delegateIsHandlingUnimplementablePolicy) {
2631         compareDataSource = _private->policyDataSource;
2632     } else if (_private->delegateIsHandlingProvisionalLoadError) {
2633         compareDataSource = [self provisionalDataSource];
2634     }
2635     
2636     return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
2637 }
2638
2639 @end
2640
2641 @implementation WebFormState : NSObject
2642
2643 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
2644 {
2645     self = [super init];
2646     if (!self)
2647         return nil;
2648     
2649     _form = [form retain];
2650     _values = [values copy];
2651     _sourceFrame = [sourceFrame retain];
2652     return self;
2653 }
2654
2655 - (void)dealloc
2656 {
2657     [_form release];
2658     [_values release];
2659     [_sourceFrame release];
2660     [super dealloc];
2661 }
2662
2663 - (DOMElement *)form
2664 {
2665     return _form;
2666 }
2667
2668 - (NSDictionary *)values
2669 {
2670     return _values;
2671 }
2672
2673 - (WebFrame *)sourceFrame
2674 {
2675     return _sourceFrame;
2676 }
2677
2678 @end
2679
2680 @implementation WebFrame
2681
2682 - (id)init
2683 {
2684     return [self initWithName:nil webFrameView:nil webView:nil];
2685 }
2686
2687 // FIXME: this method can't work any more and should be marked deprecated
2688 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2689 {
2690     return [self _initWithWebFrameView:fv webView:v bridge:nil];
2691 }
2692
2693 - (void)dealloc
2694 {
2695     ASSERT(_private->bridge == nil);
2696     [_private release];
2697
2698     --WebFrameCount;
2699
2700     [super dealloc];
2701 }
2702
2703 - (void)finalize
2704 {
2705     ASSERT(_private->bridge == nil);
2706
2707     --WebFrameCount;
2708
2709     [super finalize];
2710 }
2711
2712 - (NSString *)name
2713 {
2714     return [[self _bridge] name];
2715 }
2716
2717 - (WebFrameView *)frameView
2718 {
2719     return [_private webFrameView];
2720 }
2721
2722 - (WebView *)webView
2723 {
2724     return [[[self _bridge] page] webView];
2725 }
2726
2727 - (DOMDocument *)DOMDocument
2728 {
2729     return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2730 }
2731
2732 - (DOMHTMLElement *)frameElement
2733 {
2734     return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2735 }
2736
2737 - (WebDataSource *)provisionalDataSource
2738 {
2739     return [_private->frameLoader provisionalDataSource];
2740 }
2741
2742 - (WebDataSource *)dataSource
2743 {
2744     return [_private->frameLoader dataSource];
2745 }
2746
2747 - (void)loadRequest:(NSURLRequest *)request
2748 {
2749     // FIXME: is this the right place to reset loadType? Perhaps, this should be done
2750     // after loading is finished or aborted.
2751     _private->loadType = WebFrameLoadTypeStandard;
2752     
2753     [_private->frameLoader _loadRequest:request archive:nil];
2754 }
2755
2756 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2757 {
2758     NSURLRequest *request = [self _webDataRequestForData:data 
2759                                                 MIMEType:MIMEType 
2760                                         textEncodingName:encodingName 
2761                                                  baseURL:URL
2762                                           unreachableURL:unreachableURL];
2763     [self loadRequest:request];
2764 }
2765
2766
2767 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2768 {
2769     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2770 }
2771
2772 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2773 {
2774     CFStringEncoding cfencoding = CFStringGetFastestEncoding((CFStringRef)string);
2775     NSStringEncoding nsencoding = CFStringConvertEncodingToNSStringEncoding(cfencoding);
2776     CFStringRef cfencodingName = CFStringConvertEncodingToIANACharSetName(cfencoding);
2777     
2778     if (!cfencodingName || nsencoding == kCFStringEncodingInvalidId){
2779         NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
2780         [self _loadData:data MIMEType:nil textEncodingName:@"utf-16" baseURL:URL unreachableURL:unreachableURL];
2781     }
2782     else {
2783         NSData *data = [string dataUsingEncoding: nsencoding];
2784         [self _loadData:data MIMEType:nil textEncodingName:(NSString *)cfencodingName baseURL:URL unreachableURL:unreachableURL];
2785     }
2786 }
2787
2788 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2789 {
2790     [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2791 }
2792
2793 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2794 {
2795     [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2796 }
2797
2798 - (void)loadArchive:(WebArchive *)archive
2799 {
2800     WebResource *mainResource = [archive mainResource];
2801     if (mainResource) {
2802         NSURLRequest *request = [self _webDataRequestForData:[mainResource data] 
2803                                                     MIMEType:[mainResource MIMEType]
2804                                             textEncodingName:[mainResource textEncodingName]
2805                                                      baseURL:[mainResource URL]
2806                                               unreachableURL:nil];
2807         [_private->frameLoader _loadRequest:request archive:archive];
2808     }
2809 }
2810
2811 - (void)stopLoading
2812 {
2813     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2814     if (_private->isStoppingLoad)
2815         return;
2816
2817     _private->isStoppingLoad = YES;
2818     
2819     [self _invalidatePendingPolicyDecisionCallingDefaultAction:YES];
2820
2821     [self _stopLoadingSubframes];
2822     [_private->frameLoader stopLoading];
2823
2824     _private->isStoppingLoad = NO;
2825 }
2826
2827 - (void)reload
2828 {
2829     [_private->frameLoader reload];
2830 }
2831
2832 - (WebFrame *)findFrameNamed:(NSString *)name
2833 {
2834     return Frame([[self _bridge] findFrameNamed:name]);
2835 }
2836
2837 - (WebFrame *)parentFrame
2838 {
2839     return [[Frame([[self _bridge] parent]) retain] autorelease];
2840 }
2841
2842 - (NSArray *)childFrames
2843 {
2844     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2845     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2846         [children addObject:child];
2847
2848     return children;
2849 }
2850
2851 @end