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