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