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