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