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