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