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