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