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