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