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