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