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