Reviewed by Darin.
[WebKit-https.git] / WebKit / WebView / WebFrame.m
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebFrameInternal.h"
30
31 #import "WebArchive.h"
32 #import "WebBackForwardList.h"
33 #import "WebDataProtocol.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultResourceLoadDelegate.h"
36 #import "WebDefaultUIDelegate.h"
37 #import "WebDocumentInternal.h"
38 #import "WebDocumentLoaderMac.h"
39 #import "WebFormDataStream.h"
40 #import "WebFrameBridge.h"
41 #import "WebFrameLoadDelegate.h"
42 #import "WebFrameLoader.h"
43 #import "WebFrameViewInternal.h"
44 #import "WebHTMLRepresentationPrivate.h"
45 #import "WebHTMLViewInternal.h"
46 #import "WebHTMLViewPrivate.h"
47 #import "WebHistoryItemPrivate.h"
48 #import "WebHistoryPrivate.h"
49 #import "WebKitErrorsPrivate.h"
50 #import "WebKitLogging.h"
51 #import "WebKitNSStringExtras.h"
52 #import "WebKitStatisticsPrivate.h"
53 #import "WebNSObjectExtras.h"
54 #import "WebNSURLExtras.h"
55 #import "WebNSURLRequestExtras.h"
56 #import "WebNetscapePluginEmbeddedView.h"
57 #import "WebNullPluginView.h"
58 #import "WebPlugin.h"
59 #import "WebPluginController.h"
60 #import "WebPreferencesPrivate.h"
61 #import "WebResourceLoadDelegate.h"
62 #import "WebResourcePrivate.h"
63 #import "WebScriptDebugDelegatePrivate.h"
64 #import "WebUIDelegate.h"
65 #import "WebViewInternal.h"
66 #import <WebKit/DOM.h>
67 #import <WebKitSystemInterface.h>
68 #import <objc/objc-runtime.h>
69
70 /*
71 Here is the current behavior matrix for four types of navigations:
72
73 Standard Nav:
74
75  Restore form state:   YES
76  Restore scroll and focus state:  YES
77  WF Cache policy: NSURLRequestUseProtocolCachePolicy
78  Add to back/forward list: YES
79  
80 Back/Forward:
81
82  Restore form state:   YES
83  Restore scroll and focus state:  YES
84  WF Cache policy: NSURLRequestReturnCacheDataElseLoad
85  Add to back/forward list: NO
86
87 Reload (meaning only the reload button):
88
89  Restore form state:   NO
90  Restore scroll and focus state:  YES
91  WF Cache policy: NSURLRequestReloadIgnoringCacheData
92  Add to back/forward list: NO
93
94 Repeat load of the same URL (by any other means of navigation other than the reload button, including hitting return in the location field):
95
96  Restore form state:   NO
97  Restore scroll and focus state:  NO, reset to initial conditions
98  WF Cache policy: NSURLRequestReloadIgnoringCacheData
99  Add to back/forward list: NO
100 */
101
102 NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey";
103 NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey";
104 NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
105
106 @interface WebFrame (ForwardDecls)
107 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL;
108 - (NSDictionary *)_actionInformationForLoadType:(FrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL;
109
110 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item;
111
112 - (WebHistoryItem *)_createItem:(BOOL)useOriginal;
113 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip;
114 - (WebHistoryItem *)_currentBackForwardListItemToResetTo;
115 @end
116
117 @interface WebFrame (FrameTraversal)
118 - (WebFrame *)_firstChildFrame;
119 - (WebFrame *)_lastChildFrame;
120 - (unsigned)_childFrameCount;
121 - (WebFrame *)_previousSiblingFrame;
122 - (WebFrame *)_nextSiblingFrame;
123 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin;
124 @end
125
126 @interface NSView (WebFramePluginHosting)
127 - (void)setWebFrame:(WebFrame *)webFrame;
128 @end
129
130 @interface WebFramePrivate : NSObject
131 {
132 @public
133     WebFrameView *webFrameView;
134
135     WebFrameBridge *bridge;
136     WebHistoryItem *currentItem;        // BF item for our current content
137     WebHistoryItem *provisionalItem;    // BF item for where we're trying to go
138                                         // (only known when navigating to a pre-existing BF item)
139     WebHistoryItem *previousItem;       // BF item for previous content, see _itemForSavingDocState
140
141     WebScriptDebugger *scriptDebugger;
142     id internalLoadDelegate;
143     
144     NSMutableSet *plugInViews;
145     NSMutableSet *inspectors;
146 }
147
148 - (void)setWebFrameView:(WebFrameView *)v;
149
150 - (void)setProvisionalItem:(WebHistoryItem *)item;
151 - (void)setPreviousItem:(WebHistoryItem *)item;
152 - (void)setCurrentItem:(WebHistoryItem *)item;
153
154 @end
155
156 @implementation WebFramePrivate
157
158 - (void)dealloc
159 {
160     [webFrameView release];
161
162     [currentItem release];
163     [provisionalItem release];
164     [previousItem release];
165     
166     [scriptDebugger release];
167     
168     [inspectors release];
169
170     ASSERT(plugInViews == nil);
171     
172     [super dealloc];
173 }
174
175 - (void)setWebFrameView:(WebFrameView *)v 
176
177     [v retain];
178     [webFrameView release];
179     webFrameView = v;
180 }
181
182 - (void)setProvisionalItem:(WebHistoryItem *)item
183 {
184     [item retain];
185     [provisionalItem release];
186     provisionalItem = item;
187 }
188
189 - (void)setPreviousItem:(WebHistoryItem *)item
190 {
191     [item retain];
192     [previousItem release];
193     previousItem = item;
194 }
195
196 - (void)setCurrentItem:(WebHistoryItem *)item
197 {
198     [item retain];
199     [currentItem release];
200     currentItem = item;
201 }
202
203 @end
204
205 static inline WebFrame *Frame(WebCoreFrameBridge *bridge)
206 {
207     return [(WebFrameBridge *)bridge webFrame];
208 }
209
210 @implementation WebFrame (FrameTraversal)
211
212 - (WebFrame *)_firstChildFrame
213 {
214     return Frame([[self _bridge] firstChild]);
215 }
216
217 - (WebFrame *)_lastChildFrame
218 {
219     return Frame([[self _bridge] lastChild]);
220 }
221
222 - (unsigned)_childFrameCount
223 {
224     return [[self _bridge] childCount];
225 }
226
227 - (WebFrame *)_previousSiblingFrame;
228 {
229     return Frame([[self _bridge] previousSibling]);
230 }
231
232 - (WebFrame *)_nextSiblingFrame;
233 {
234     return Frame([[self _bridge] nextSibling]);
235 }
236
237 - (WebFrame *)_traverseNextFrameStayWithin:(WebFrame *)stayWithin
238 {
239     return Frame([[self _bridge] traverseNextFrameStayWithin:[stayWithin _bridge]]);
240 }
241
242 @end
243
244 @implementation WebFrame (WebInternal)
245
246 - (NSURLRequest *)_webDataRequestForData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
247 {
248     NSURL *fakeURL = [NSURL _web_uniqueWebDataURL];
249     NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:fakeURL] autorelease];
250     [request _webDataRequestSetData:data];
251     [request _webDataRequestSetEncoding:encodingName];
252     [request _webDataRequestSetBaseURL:URL];
253     [request _webDataRequestSetUnreachableURL:unreachableURL];
254     [request _webDataRequestSetMIMEType: MIMEType ? MIMEType : (NSString *)@"text/html"];
255     return request;
256 }
257
258 // helper method used in various nav cases below
259 - (void)_addBackForwardItemClippedAtTarget:(BOOL)doClip
260 {
261     if ([[self dataSource] _URLForHistory] != nil) {
262         WebHistoryItem *bfItem = [[[self webView] mainFrame] _createItemTreeWithTargetFrame:self clippedAtTarget:doClip];
263         LOG (BackForward, "for frame %@, adding item  %@\n", [self name], bfItem);
264         [[[self webView] backForwardList] addItem:bfItem];
265     }
266 }
267
268 - (void)_addHistoryItemForFragmentScroll
269 {
270     [self _addBackForwardItemClippedAtTarget:NO];
271 }
272
273 - (void)_didFinishLoad
274 {
275     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];    
276 }
277
278 - (WebHistoryItem *)_createItem:(BOOL)useOriginal
279 {
280     WebDataSource *dataSrc = [self dataSource];
281     NSURLRequest *request;
282     NSURL *unreachableURL = [dataSrc unreachableURL];
283     NSURL *URL;
284     NSURL *originalURL;
285     WebHistoryItem *bfItem;
286
287     if (useOriginal)
288         request = [[dataSrc _documentLoader] originalRequestCopy];
289     else
290         request = [dataSrc request];
291
292     if (unreachableURL != nil) {
293         URL = unreachableURL;
294         originalURL = unreachableURL;
295     } else {
296         URL = [request URL];
297         originalURL = [[[dataSrc _documentLoader] originalRequestCopy] URL];
298     }
299
300     LOG (History, "creating item for %@", request);
301     
302     // Frames that have never successfully loaded any content
303     // may have no URL at all. Currently our history code can't
304     // deal with such things, so we nip that in the bud here.
305     // Later we may want to learn to live with nil for URL.
306     // See bug 3368236 and related bugs for more information.
307     if (URL == nil) {
308         URL = [NSURL URLWithString:@"about:blank"];
309     }
310     if (originalURL == nil) {
311         originalURL = [NSURL URLWithString:@"about:blank"];
312     }
313     
314     bfItem = [[[WebHistoryItem alloc] initWithURL:URL target:[self name] parent:[[self parentFrame] name] title:[dataSrc pageTitle]] autorelease];
315     [bfItem setOriginalURLString:[originalURL _web_originalDataAsString]];
316
317     // save form state if this is a POST
318     [bfItem _setFormInfoFromRequest:request];
319
320     // Set the item for which we will save document state
321     [_private setPreviousItem:_private->currentItem];
322     [_private setCurrentItem:bfItem];
323
324     return bfItem;
325 }
326
327 /*
328     In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.  
329     The item that was the target of the user's navigation is designated as the "targetItem".  
330     When this method is called with doClip=YES we're able to create the whole tree except for the target's children, 
331     which will be loaded in the future.  That part of the tree will be filled out as the child loads are committed.
332 */
333 - (WebHistoryItem *)_createItemTreeWithTargetFrame:(WebFrame *)targetFrame clippedAtTarget:(BOOL)doClip
334 {
335     WebHistoryItem *bfItem = [self _createItem:[self parentFrame] ? YES : NO];
336
337     [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
338     if (!(doClip && self == targetFrame)) {
339         // save frame state for items that aren't loading (khtml doesn't save those)
340         [_private->bridge saveDocumentState];
341
342         for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
343             [bfItem addChildItem:[child _createItemTreeWithTargetFrame:targetFrame clippedAtTarget:doClip]];
344     }
345     if (self == targetFrame)
346         [bfItem setIsTargetItem:YES];
347
348     return bfItem;
349 }
350
351 - (WebFrame *)_immediateChildFrameNamed:(NSString *)name
352 {
353     return Frame([[self _bridge] childFrameNamed:name]);
354 }
355
356 - (void)_detachChildren
357 {
358     // FIXME: is it really necessary to do this in reverse order any more?
359     WebFrame *child = [self _lastChildFrame];
360     WebFrame *prev = [child _previousSiblingFrame];
361     for (; child; child = prev, prev = [child _previousSiblingFrame])
362         [child _detachFromParent];
363 }
364
365 - (void)_detachFromParent
366 {
367     WebFrameBridge *bridge = [_private->bridge retain];
368
369     [bridge closeURL];
370     [self stopLoading];
371
372     [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
373     [self _detachChildren];
374     [_private->inspectors makeObjectsPerformSelector:@selector(_webFrameDetached:) withObject:self];
375
376     [_private->webFrameView _setWebFrame:nil]; // needed for now to be compatible w/ old behavior
377
378     [[self _frameLoader] clearDataSource];
379     [_private setWebFrameView:nil];
380
381     [self retain]; // retain self temporarily because dealloc can re-enter this method
382
383     [[[self parentFrame] _bridge] removeChild:bridge];
384
385     [bridge close];
386     [bridge release];
387
388     bridge = nil;
389     _private->bridge = nil;
390
391     [self release];
392 }
393
394 - (void)_makeDocumentView
395 {
396     NSView <WebDocumentView> *documentView = [_private->webFrameView _makeDocumentViewForDataSource:[[self _frameLoader] dataSource]];
397     if (!documentView)
398         return;
399
400     // FIXME: We could save work and not do this for a top-level view that is not a WebHTMLView.
401     WebFrameView *v = _private->webFrameView;
402     [_private->bridge createFrameViewWithNSView:documentView marginWidth:[v _marginWidth] marginHeight:[v _marginHeight]];
403     [self _updateBackground];
404     [_private->bridge installInFrame:[v _scrollView]];
405
406     // Call setDataSource on the document view after it has been placed in the view hierarchy.
407     // This what we for the top-level view, so should do this for views in subframes as well.
408     [documentView setDataSource:[[self _frameLoader] dataSource]];
409 }
410
411 - (void)_transitionToCommitted:(NSDictionary *)pageCache
412 {
413     ASSERT([self webView] != nil);
414     
415     switch ([[self _frameLoader] state]) {
416         case WebFrameStateProvisional:
417         {
418             [[[[self frameView] _scrollView] contentView] setCopiesOnScroll:YES];
419
420             FrameLoadType loadType = [[self _frameLoader] loadType];
421             if (loadType == FrameLoadTypeForward ||
422                 loadType == FrameLoadTypeBack ||
423                 loadType == FrameLoadTypeIndexedBackForward ||
424                 (loadType == FrameLoadTypeReload && [[[self _frameLoader] provisionalDataSource] unreachableURL] != nil))
425             {
426                 // Once committed, we want to use current item for saving DocState, and
427                 // the provisional item for restoring state.
428                 // Note previousItem must be set before we close the URL, which will
429                 // happen when the data source is made non-provisional below
430                 [_private setPreviousItem:_private->currentItem];
431                 ASSERT(_private->provisionalItem);
432                 [_private setCurrentItem:_private->provisionalItem];
433                 [_private setProvisionalItem:nil];
434             }
435
436             // The call to closeURL invokes the unload event handler, which can execute arbitrary
437             // JavaScript. If the script initiates a new load, we need to abandon the current load,
438             // or the two will stomp each other.
439             WebDataSource *pd = [[self _frameLoader] provisionalDataSource];
440             [[self _bridge] closeURL];
441             if (pd != [[self _frameLoader] provisionalDataSource])
442                 return;
443
444             [[self _frameLoader] commitProvisionalLoad];
445
446             // Handle adding the URL to the back/forward list.
447             WebDataSource *ds = [self dataSource];
448             NSString *ptitle = [ds pageTitle];
449
450             switch (loadType) {
451             case FrameLoadTypeForward:
452             case FrameLoadTypeBack:
453             case FrameLoadTypeIndexedBackForward:
454                 if ([[self webView] backForwardList]) {
455                     // Must grab the current scroll position before disturbing it
456                     [self _saveScrollPositionAndViewStateToItem:_private->previousItem];
457                     
458                     // Create a document view for this document, or used the cached view.
459                     if (pageCache){
460                         NSView <WebDocumentView> *cachedView = [pageCache objectForKey: WebPageCacheDocumentViewKey];
461                         ASSERT(cachedView != nil);
462                         [[self frameView] _setDocumentView: cachedView];
463                     }
464                     else
465                         [self _makeDocumentView];
466                 }
467                 break;
468
469             case FrameLoadTypeReload:
470             case FrameLoadTypeSame:
471             case FrameLoadTypeReplace:
472             {
473                 WebHistoryItem *currItem = _private->currentItem;
474                 LOG(PageCache, "Clearing back/forward cache, %@\n", [currItem URL]);
475                 [currItem setHasPageCache:NO];
476                 if (loadType == FrameLoadTypeReload) {
477                     [self _saveScrollPositionAndViewStateToItem:currItem];
478                 }
479                 NSURLRequest *request = [ds request];
480                 if ([request _webDataRequestUnreachableURL] == nil) {
481                     // Sometimes loading a page again leads to a different result because of cookies.  Bugzilla 4072
482                     [currItem setURL:[request URL]];
483                 }
484                 // Update the last visited time.  Mostly interesting for URL autocompletion
485                 // statistics.
486                 NSURL *URL = [[[[ds _documentLoader] originalRequestCopy] URL] _webkit_canonicalize];
487                 WebHistory *sharedHistory = [WebHistory optionalSharedHistory];
488                 WebHistoryItem *oldItem = [sharedHistory itemForURL:URL];
489                 if (oldItem)
490                     [sharedHistory setLastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate] forItem:oldItem];
491                 
492                 [self _makeDocumentView];
493                 break;
494             }
495
496             // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
497             case FrameLoadTypeReloadAllowingStaleData:
498                 [self _makeDocumentView];
499                 break;
500                 
501             case FrameLoadTypeStandard:
502                 if (![[ds _documentLoader] isClientRedirect]) {
503                     // Add item to history and BF list
504                     NSURL *URL = [ds _URLForHistory];
505                     if (URL && ![URL _web_isEmpty]){
506                         ASSERT([self webView]);
507                         if (![[[self webView] preferences] privateBrowsingEnabled]) {
508                             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] addItemForURL:URL];
509                             if (ptitle)
510                                 [entry setTitle: ptitle];                            
511                         }
512                         [self _addBackForwardItemClippedAtTarget:YES];
513                     }
514
515                 } else {
516                     NSURLRequest *request = [ds request];
517                     
518                     // update the URL in the BF list that we made before the redirect, unless
519                     // this is alternate content for an unreachable URL (we want the BF list
520                     // item to remember the unreachable URL in case it becomes reachable later)
521                     if ([request _webDataRequestUnreachableURL] == nil) {
522                         [_private->currentItem setURL:[request URL]];
523
524                         // clear out the form data so we don't repost it to the wrong place if we
525                         // ever go back/forward to this item
526                         [_private->currentItem _setFormInfoFromRequest:request];
527
528                         // We must also clear out form data so we don't try to restore it into the incoming page,
529                         // see -_opened
530                     }
531                 }
532                 [self _makeDocumentView];
533                 break;
534                 
535             case FrameLoadTypeInternal:
536                 // Add an item to the item tree for this frame
537                 ASSERT(![[ds _documentLoader] isClientRedirect]);
538                 WebFrame *parentFrame = [self parentFrame];
539                 if (parentFrame) {
540                     WebHistoryItem *parentItem = parentFrame->_private->currentItem;
541                     // The only case where parentItem==nil should be when a parent frame loaded an
542                     // empty URL, which doesn't set up a current item in that parent.
543                     if (parentItem)
544                         [parentItem addChildItem:[self _createItem: YES]];
545                 } else {
546                     // See 3556159.  It's not clear if it's valid to be in FrameLoadTypeOnLoadEvent
547                     // for a top-level frame, but that was a likely explanation for those crashes,
548                     // so let's guard against it.
549                     // ...and all FrameLoadTypeOnLoadEvent uses were folded to FrameLoadTypeInternal
550                     LOG_ERROR("no parent frame in _transitionToCommitted:, loadType=%d", loadType);
551                 }
552                 [self _makeDocumentView];
553                 break;
554
555             // FIXME Remove this check when dummy ds is removed.  An exception should be thrown
556             // if we're in the FrameLoadTypeUninitialized state.
557             default:
558                 ASSERT_NOT_REACHED();
559             }
560
561             
562             // Tell the client we've committed this URL.
563             ASSERT([[self frameView] documentView] != nil);
564             [[self webView] _didCommitLoadForFrame: self];
565             [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didCommitLoadForFrame:self];
566             
567             // If we have a title let the WebView know about it.
568             if (ptitle) {
569                 [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
570                                                            didReceiveTitle:ptitle
571                                                                   forFrame:self];
572             }
573             break;
574         }
575         
576         case WebFrameStateCommittedPage:
577         case WebFrameStateComplete:
578         default:
579         {
580             ASSERT_NOT_REACHED();
581         }
582     }
583 }
584
585 - (BOOL)_canCachePage
586 {
587     return [[[self webView] backForwardList] _usesPageCache];
588 }
589
590 - (void)_purgePageCache
591 {
592     // This method implements the rule for purging the page cache.
593     unsigned sizeLimit = [[[self webView] backForwardList] pageCacheSize];
594     unsigned pagesCached = 0;
595     WebBackForwardList *backForwardList = [[self webView] backForwardList];
596     NSArray *backList = [backForwardList backListWithLimit: 999999];
597     WebHistoryItem *oldestNonSnapbackItem = nil;
598     
599     unsigned i;
600     for (i = 0; i < [backList count]; i++){
601         WebHistoryItem *item = [backList objectAtIndex: i];
602         if ([item hasPageCache]){
603             if (oldestNonSnapbackItem == nil && ![item alwaysAttemptToUsePageCache])
604                 oldestNonSnapbackItem = item;
605             pagesCached++;
606         }
607     }
608
609     // Snapback items are never directly purged here.
610     if (pagesCached >= sizeLimit) {
611         LOG(PageCache, "Purging back/forward cache, %@\n", [oldestNonSnapbackItem URL]);
612         [oldestNonSnapbackItem setHasPageCache:NO];
613     }
614 }
615
616 + (CFAbsoluteTime)_timeOfLastCompletedLoad
617 {
618     return [WebFrameLoader timeOfLastCompletedLoad];
619 }
620
621 - (BOOL)_createPageCacheForItem:(WebHistoryItem *)item
622 {
623     NSMutableDictionary *pageCache;
624
625     [item setHasPageCache: YES];
626
627     if (![_private->bridge saveDocumentToPageCache]){
628         [item setHasPageCache: NO];
629         return NO;
630     }
631     else {
632         pageCache = [item pageCache];
633         [pageCache setObject:[NSDate date]  forKey: WebPageCacheEntryDateKey];
634         [pageCache setObject:[self dataSource] forKey: WebPageCacheDataSourceKey];
635         [pageCache setObject:[[self frameView] documentView] forKey: WebPageCacheDocumentViewKey];
636     }
637     return YES;
638 }
639
640 - (void)_provisionalLoadStarted
641 {
642     FrameLoadType loadType = [[self _frameLoader] loadType];
643     
644     // FIXME: This is OK as long as no one resizes the window,
645     // but in the case where someone does, it means garbage outside
646     // the occupied part of the scroll view.
647     [[[self frameView] _scrollView] setDrawsBackground:NO];
648     
649     // Cache the page, if possible.
650     // Don't write to the cache if in the middle of a redirect, since we will want to
651     // store the final page we end up on.
652     // No point writing to the cache on a reload or loadSame, since we will just write
653     // over it again when we leave that page.
654     WebHistoryItem *item = _private->currentItem;
655     if ([self _canCachePage]
656         && [_private->bridge canCachePage]
657         && item
658         && ![[self _frameLoader] isQuickRedirectComing]
659         && loadType != FrameLoadTypeReload 
660         && loadType != FrameLoadTypeReloadAllowingStaleData
661         && loadType != FrameLoadTypeSame
662         && ![[self dataSource] isLoading]
663         && ![[[self _frameLoader] documentLoader] isStopping]) {
664         if ([[[self dataSource] representation] isKindOfClass:[WebHTMLRepresentation class]]) {
665             if (![item pageCache]){
666                 // Add the items to this page's cache.
667                 if ([self _createPageCacheForItem:item]) {
668                     LOG(PageCache, "Saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
669                     
670                     // See if any page caches need to be purged after the addition of this
671                     // new page cache.
672                     [self _purgePageCache];
673                 }
674                 else
675                     LOG(PageCache, "NOT saving page to back/forward cache, unable to create items, %@\n", [[self dataSource] _URL]);
676             }
677         } else
678             // Put the document into a null state, so it can be restored correctly.
679             [_private->bridge clear];
680     } else
681         LOG(PageCache, "NOT saving page to back/forward cache, %@\n", [[self dataSource] _URL]);
682 }
683
684 // Called after we send an openURL:... down to WebCore.
685 - (void)_opened
686 {
687     if ([[self _frameLoader] loadType] == FrameLoadTypeStandard && [[[self dataSource] _documentLoader] isClientRedirect]) {
688         // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
689         // khtml has closed the URL and saved away the form state.
690         WebHistoryItem *item = _private->currentItem;
691         [item setDocumentState:nil];
692         [item setScrollPoint:NSZeroPoint];
693     }
694
695     if ([[self dataSource] _loadingFromPageCache]){
696         // Force a layout to update view size and thereby update scrollbars.
697         NSView <WebDocumentView> *view = [[self frameView] documentView];
698         if ([view isKindOfClass:[WebHTMLView class]]) {
699             [(WebHTMLView *)view setNeedsToApplyStyles:YES];
700         }
701         [view setNeedsLayout: YES];
702         [view layout];
703
704         NSArray *responses = [[[self _frameLoader] documentLoader] responses];
705         NSURLResponse *response;
706         int i, count = [responses count];
707         for (i = 0; i < count; i++){
708             response = [responses objectAtIndex: i];
709             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
710             NSError *error;
711             id identifier;
712             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
713             [self _requestFromDelegateForRequest:request identifier:&identifier error:&error];
714             [self _sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
715             [request release];
716         }
717         
718         // Release the resources kept in the page cache.  They will be
719         // reset when we leave this page.  The core side of the page cache
720         // will have already been invalidated by the bridge to prevent
721         // premature release.
722         [_private->currentItem setHasPageCache:NO];
723
724         [[[self _frameLoader] documentLoader] setPrimaryLoadComplete:YES];
725         // why only this frame and not parent frames?
726         [self _checkLoadCompleteForThisFrame];
727     }
728 }
729
730 - (void)_checkLoadCompleteForThisFrame
731 {
732     ASSERT([self webView] != nil);
733
734     switch ([[self _frameLoader] state]) {
735         case WebFrameStateProvisional:
736         {
737             if ([[self _frameLoader] delegateIsHandlingProvisionalLoadError])
738                 return;
739
740             WebDataSource *pd = [self provisionalDataSource];
741             
742             LOG(Loading, "%@:  checking complete in WebFrameStateProvisional", [self name]);
743             // If we've received any errors we may be stuck in the provisional state and actually
744             // complete.
745             NSError *error = [pd _mainDocumentError];
746             if (error != nil) {
747                 // Check all children first.
748                 LOG(Loading, "%@:  checking complete, current state WebFrameStateProvisional", [self name]);
749                 WebHistoryItem *resetItem = [self _currentBackForwardListItemToResetTo];
750                 BOOL shouldReset = YES;
751                 if (![pd isLoading]) {
752                     LOG(Loading, "%@:  checking complete in WebFrameStateProvisional, load done", [self name]);
753                     [[self webView] _didFailProvisionalLoadWithError:error forFrame:self];
754                     [[self _frameLoader] setDelegateIsHandlingProvisionalLoadError:YES];
755                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
756                                           didFailProvisionalLoadWithError:error
757                                                                  forFrame:self];
758                     [[self _frameLoader] setDelegateIsHandlingProvisionalLoadError:NO];
759                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
760
761                     // FIXME: can stopping loading here possibly have
762                     // any effect, if isLoading is false, which it
763                     // must be, to be in this branch of the if? And is it ok to just do 
764                     // a full-on stopLoading?
765                     [[self _frameLoader] stopLoadingSubframes];
766                     [[pd _documentLoader] stopLoading];
767
768                     // Finish resetting the load state, but only if another load hasn't been started by the
769                     // delegate callback.
770                     if (pd == [[self _frameLoader] provisionalDataSource])
771                         [[self _frameLoader] clearProvisionalLoad];
772                     else {
773                         NSURL *unreachableURL = [[[self _frameLoader] provisionalDataSource] unreachableURL];
774                         if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]]) {
775                             shouldReset = NO;
776                         }
777                     }
778                 }
779                 if (shouldReset && resetItem != nil) {
780                     [[[self webView] backForwardList] goToItem:resetItem];
781                 }
782             }
783             return;
784         }
785         
786         case WebFrameStateCommittedPage:
787         {
788             WebDataSource *ds = [self dataSource];
789             
790             //LOG(Loading, "%@:  checking complete, current state WEBFRAMESTATE_COMMITTED", [self name]);
791             if (![ds isLoading]) {
792                 WebFrameView *thisView = [self frameView];
793                 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
794                 ASSERT(thisDocumentView != nil);
795
796                 [[self _frameLoader] markLoadComplete];
797
798                 // FIXME: Is this subsequent work important if we already navigated away?
799                 // Maybe there are bugs because of that, or extra work we can skip because
800                 // the new page is ready.
801
802                 // Tell the just loaded document to layout.  This may be necessary
803                 // for non-html content that needs a layout message.
804                 if (!([[self dataSource] _isDocumentHTML])) {
805                     [thisDocumentView setNeedsLayout:YES];
806                     [thisDocumentView layout];
807                     [thisDocumentView setNeedsDisplay:YES];
808                 }
809                  
810                 // If the user had a scroll point scroll to it.  This will override
811                 // the anchor point.  After much discussion it was decided by folks
812                 // that the user scroll point should override the anchor point.
813                 if ([[self webView] backForwardList]) {
814                     switch ([[self _frameLoader] loadType]) {
815                     case FrameLoadTypeForward:
816                     case FrameLoadTypeBack:
817                     case FrameLoadTypeIndexedBackForward:
818                     case FrameLoadTypeReload:
819                         [self _restoreScrollPositionAndViewState];
820                         break;
821
822                     case FrameLoadTypeStandard:
823                     case FrameLoadTypeInternal:
824                     case FrameLoadTypeReloadAllowingStaleData:
825                     case FrameLoadTypeSame:
826                     case FrameLoadTypeReplace:
827                         // Do nothing.
828                         break;
829
830                     default:
831                         ASSERT_NOT_REACHED();
832                         break;
833                     }
834                 }
835
836                 NSError *error = [ds _mainDocumentError];
837                 if (error != nil) {
838                     [[self webView] _didFailLoadWithError:error forFrame:self];
839                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
840                                                      didFailLoadWithError:error
841                                                                  forFrame:self];
842                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:error];
843                 } else {
844                     [[self webView] _didFinishLoadForFrame:self];
845                     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
846                                                     didFinishLoadForFrame:self];
847                     [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
848                 }
849                 
850                 [[self webView] _progressCompleted: self];
851  
852                 return;
853             }
854             return;
855         }
856         
857         case WebFrameStateComplete:
858         {
859             LOG(Loading, "%@:  checking complete, current state WebFrameStateComplete", [self name]);
860             // Even if already complete, we might have set a previous item on a frame that
861             // didn't do any data loading on the past transaction.  Make sure to clear these out.
862             [_private setPreviousItem:nil];
863             return;
864         }
865     }
866     
867     // Yikes!  Serious horkage.
868     ASSERT_NOT_REACHED();
869 }
870
871 - (void)_handledOnloadEvents
872 {
873     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView] didHandleOnloadEventsForFrame:self];
874 }
875
876 // Called every time a resource is completely loaded, or an error is received.
877 - (void)_checkLoadComplete
878 {
879     ASSERT([self webView] != nil);
880
881     WebFrame *parent;
882     for (WebFrame *frame = self; frame; frame = parent) {
883         [frame retain];
884         [frame _checkLoadCompleteForThisFrame];
885         parent = [frame parentFrame];
886         [frame release];
887     }
888 }
889
890 - (WebFrameBridge *)_bridge
891 {
892     return _private->bridge;
893 }
894
895 // helper method that determines whether the subframes described by the item's subitems
896 // match our own current frameset
897 - (BOOL)_childFramesMatchItem:(WebHistoryItem *)item
898 {
899     NSArray *childItems = [item children];
900     int numChildItems = [childItems count];
901     int numChildFrames = [self _childFrameCount];
902     if (numChildFrames != numChildItems)
903         return NO;
904
905     int i;
906     for (i = 0; i < numChildItems; i++) {
907         NSString *itemTargetName = [[childItems objectAtIndex:i] target];
908         //Search recursive here?
909         if (![self _immediateChildFrameNamed:itemTargetName])
910             return NO; // couldn't match the i'th itemTarget
911     }
912
913     return YES; // found matches for all itemTargets
914 }
915
916 // Walk the frame tree and ensure that the URLs match the URLs in the item.
917 - (BOOL)_URLsMatchItem:(WebHistoryItem *)item
918 {
919     NSURL *currentURL = [[[self dataSource] request] URL];
920
921     if (![[[item URL] _webkit_URLByRemovingFragment] isEqual:[currentURL _webkit_URLByRemovingFragment]])
922         return NO;
923     
924     NSArray *childItems = [item children];
925     WebHistoryItem *childItem;
926     WebFrame *childFrame;
927     int i, count = [childItems count];
928     for (i = 0; i < count; i++){
929         childItem = [childItems objectAtIndex:i];
930         childFrame = [self _immediateChildFrameNamed:[childItem target]];
931         if (![childFrame _URLsMatchItem: childItem])
932             return NO;
933     }
934     
935     return YES;
936 }
937
938 // loads content into this frame, as specified by item
939 - (void)_loadItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)loadType
940 {
941     NSURL *itemURL = [item URL];
942     NSURL *itemOriginalURL = [NSURL _web_URLWithDataAsString:[item originalURLString]];
943     NSURL *currentURL = [[[self dataSource] request] URL];
944     NSArray *formData = [item formData];
945
946     // Are we navigating to an anchor within the page?
947     // Note if we have child frames we do a real reload, since the child frames might not
948     // match our current frame structure, or they might not have the right content.  We could
949     // check for all that as an additional optimization.
950     // We also do not do anchor-style navigation if we're posting a form.
951     
952     // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
953     // Perhaps they should.
954     if (!formData && ![[self _frameLoader] shouldReloadForCurrent:itemURL andDestination:currentURL] && [self _URLsMatchItem:item] )
955     {
956 #if 0
957         // FIXME:  We need to normalize the code paths for anchor navigation.  Something
958         // like the following line of code should be done, but also accounting for correct
959         // updates to the back/forward list and scroll position.
960         // rjw 4/9/03 See 3223929.
961         [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
962 #endif
963         // must do this maintenance here, since we don't go through a real page reload
964         [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
965         // FIXME: form state might want to be saved here too
966
967         // We always call scrollToAnchorWithURL here, even if the URL doesn't have an
968         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
969         [_private->bridge scrollToAnchorWithURL:[item URL]];
970     
971         // must do this maintenance here, since we don't go through a real page reload
972         [_private setCurrentItem:item];
973         [self _restoreScrollPositionAndViewState];
974
975         // Fake the URL change by updating the data source's request.  This will no longer
976         // be necessary if we do the better fix described above.
977         [[[self _frameLoader] documentLoader] replaceRequestURLForAnchorScrollWithURL:itemURL];
978         
979         [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
980                                didChangeLocationWithinPageForFrame:self];
981         [_private->internalLoadDelegate webFrame:self didFinishLoadWithError:nil];
982     } else {
983         // Remember this item so we can traverse any child items as child frames load
984         [_private setProvisionalItem:item];
985
986         WebDataSource *newDataSource;
987         BOOL inPageCache = NO;
988         
989         // Check if we'll be using the page cache.  We only use the page cache
990         // if one exists and it is less than _backForwardCacheExpirationInterval
991         // seconds old.  If the cache is expired it gets flushed here.
992         if ([item hasPageCache]){
993             NSDictionary *pageCache = [item pageCache];
994             NSDate *cacheDate = [pageCache objectForKey: WebPageCacheEntryDateKey];
995             NSTimeInterval delta = [[NSDate date] timeIntervalSinceDate: cacheDate];
996
997             if (delta <= [[[self webView] preferences] _backForwardCacheExpirationInterval]){
998                 newDataSource = [pageCache objectForKey: WebPageCacheDataSourceKey];
999                 [[self _frameLoader] loadDataSource:newDataSource withLoadType:loadType formState:nil];   
1000                 inPageCache = YES;
1001             }
1002             else {
1003                 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]);
1004                 [item setHasPageCache: NO];
1005             }
1006         }
1007         
1008         if (!inPageCache) {
1009             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:itemURL];
1010             [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(formData != nil) ? YES : NO];
1011
1012             // If this was a repost that failed the page cache, we might try to repost the form.
1013             NSDictionary *action;
1014             if (formData) {
1015                 [request setHTTPMethod:@"POST"];
1016                 [request _web_setHTTPReferrer:[item formReferrer]];
1017                 webSetHTTPBody(request, formData);
1018                 [request _web_setHTTPContentType:[item formContentType]];
1019
1020                 // Slight hack to test if the WF cache contains the page we're going to.  We want
1021                 // to know this before talking to the policy delegate, since it affects whether we
1022                 // show the DoYouReallyWantToRepost nag.
1023                 //
1024                 // This trick has a small bug (3123893) where we might find a cache hit, but then
1025                 // have the item vanish when we try to use it in the ensuing nav.  This should be
1026                 // extremely rare, but in that case the user will get an error on the navigation.
1027                 [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
1028                 NSURLResponse *synchResponse = nil;
1029                 [NSURLConnection sendSynchronousRequest:request returningResponse:&synchResponse error:nil];
1030                 if (synchResponse == nil) { 
1031                     // Not in WF cache
1032                     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1033                     action = [self _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:itemURL];
1034                 } else {
1035                     // We can use the cache, don't use navType=resubmit
1036                     action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemURL];
1037                 }
1038             } else {
1039                 switch (loadType) {
1040                     case FrameLoadTypeReload:
1041                         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1042                         break;
1043                     case FrameLoadTypeBack:
1044                     case FrameLoadTypeForward:
1045                     case FrameLoadTypeIndexedBackForward:
1046                         if (![[itemURL scheme] isEqual:@"https"]) {
1047                             [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1048                         }
1049                         break;
1050                     case FrameLoadTypeStandard:
1051                     case FrameLoadTypeInternal:
1052                         // no-op: leave as protocol default
1053                         // FIXME:  I wonder if we ever hit this case
1054                         break;
1055                     case FrameLoadTypeSame:
1056                     case FrameLoadTypeReloadAllowingStaleData:
1057                     default:
1058                         ASSERT_NOT_REACHED();
1059                 }
1060
1061                 action = [self _actionInformationForLoadType:loadType isFormSubmission:NO event:nil originalURL:itemOriginalURL];
1062             }
1063
1064             [[self _frameLoader] _loadRequest:request triggeringAction:action loadType:loadType formState:nil];
1065             [request release];
1066         }
1067     }
1068 }
1069
1070 // The general idea here is to traverse the frame tree and the item tree in parallel,
1071 // tracking whether each frame already has the content the item requests.  If there is
1072 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
1073 // reload that frame, and all its kids.
1074 - (void)_recursiveGoToItem:(WebHistoryItem *)item fromItem:(WebHistoryItem *)fromItem withLoadType:(FrameLoadType)type
1075 {
1076     NSURL *itemURL = [item URL];
1077     NSURL *currentURL = [[[self dataSource] request] URL];
1078
1079     // Always reload the target frame of the item we're going to.  This ensures that we will
1080     // do -some- load for the transition, which means a proper notification will be posted
1081     // to the app.
1082     // The exact URL has to match, including fragment.  We want to go through the _load
1083     // method, even if to do a within-page navigation.
1084     // The current frame tree and the frame tree snapshot in the item have to match.
1085     if (![item isTargetItem] &&
1086         [itemURL isEqual:currentURL] &&
1087         (([self name] == nil && [item target] == nil) ||[[self name] isEqualToString:[item target]]) &&
1088         [self _childFramesMatchItem:item])
1089     {
1090         // This content is good, so leave it alone and look for children that need reloading
1091
1092         // Save form state (works from currentItem, since prevItem is nil)
1093         ASSERT(!_private->previousItem);
1094         [_private->bridge saveDocumentState];
1095         [self _saveScrollPositionAndViewStateToItem:_private->currentItem];
1096         
1097         [_private setCurrentItem:item];
1098
1099         // Restore form state (works from currentItem)
1100         [_private->bridge restoreDocumentState];
1101         // Restore the scroll position (taken in favor of going back to the anchor)
1102         [self _restoreScrollPositionAndViewState];
1103         
1104         NSArray *childItems = [item children];
1105         int numChildItems = childItems ? [childItems count] : 0;
1106         int i;
1107         for (i = numChildItems - 1; i >= 0; i--) {
1108             WebHistoryItem *childItem = [childItems objectAtIndex:i];
1109             NSString *childName = [childItem target];
1110             WebHistoryItem *fromChildItem = [fromItem childItemWithName:childName];
1111             ASSERT(fromChildItem || [fromItem isTargetItem]);
1112             WebFrame *childFrame = [self _immediateChildFrameNamed:childName];
1113             ASSERT(childFrame);
1114             [childFrame _recursiveGoToItem:childItem fromItem:fromChildItem withLoadType:type];
1115         }
1116     } else {
1117         // We need to reload the content
1118         [self _loadItem:item withLoadType:type];
1119     }
1120 }
1121
1122 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
1123 // This includes recursion to handle loading into framesets properly
1124 - (void)_goToItem:(WebHistoryItem *)item withLoadType:(FrameLoadType)type
1125 {
1126     ASSERT(![self parentFrame]);
1127     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
1128     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
1129     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
1130     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
1131     if ([[[self webView] _policyDelegateForwarder] webView:[self webView] shouldGoToHistoryItem:item]) {    
1132         WebBackForwardList *backForwardList = [[self webView] backForwardList];
1133         WebHistoryItem *currItem = [backForwardList currentItem];
1134         // Set the BF cursor before commit, which lets the user quickly click back/forward again.
1135         // - plus, it only makes sense for the top level of the operation through the frametree,
1136         // as opposed to happening for some/one of the page commits that might happen soon
1137         [backForwardList goToItem:item];
1138         [self _recursiveGoToItem:item fromItem:currItem withLoadType:type];
1139     }
1140 }
1141
1142 -(NSDictionary *)_actionInformationForNavigationType:(WebNavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1143 {
1144     switch ([event type]) {
1145         case NSLeftMouseDown:
1146         case NSRightMouseDown:
1147         case NSOtherMouseDown:
1148         case NSLeftMouseUp:
1149         case NSRightMouseUp:
1150         case NSOtherMouseUp:
1151         {
1152             NSView *topViewInEventWindow = [[event window] contentView];
1153             NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1154             while (viewContainingPoint != nil) {
1155                 if ([viewContainingPoint isKindOfClass:[WebHTMLView class]]) {
1156                     break;
1157                 }
1158                 viewContainingPoint = [viewContainingPoint superview];
1159             }
1160             if (viewContainingPoint != nil) {
1161                 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1162                 NSDictionary *elementInfo = [(WebHTMLView *)viewContainingPoint elementAtPoint:point];
1163         
1164                 return [NSDictionary dictionaryWithObjectsAndKeys:
1165                     [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1166                     elementInfo, WebActionElementKey,
1167                     [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1168                     [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1169                     URL, WebActionOriginalURLKey,
1170                     nil];
1171             }
1172         }
1173             
1174         // fall through
1175         
1176         default:
1177             return [NSDictionary dictionaryWithObjectsAndKeys:
1178                 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1179                 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1180                 URL, WebActionOriginalURLKey,
1181                 nil];
1182     }
1183 }
1184
1185 -(NSDictionary *)_actionInformationForLoadType:(FrameLoadType)loadType isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1186 {
1187     WebNavigationType navType;
1188     if (isFormSubmission) {
1189         navType = WebNavigationTypeFormSubmitted;
1190     } else if (event == nil) {
1191         if (loadType == FrameLoadTypeReload) {
1192             navType = WebNavigationTypeReload;
1193         } else if (loadType == FrameLoadTypeForward
1194                    || loadType == FrameLoadTypeBack
1195                    || loadType == FrameLoadTypeIndexedBackForward) {
1196             navType = WebNavigationTypeBackForward;
1197         } else {
1198             navType = WebNavigationTypeOther;
1199         }
1200     } else {
1201         navType = WebNavigationTypeLinkClicked;
1202     }
1203     return [self _actionInformationForNavigationType:navType event:event originalURL:URL];
1204 }
1205
1206 - (void)_continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1207 {
1208     if (!request)
1209         return;
1210
1211     [self retain];
1212
1213     WebView *webView = nil;
1214     WebView *currentWebView = [self webView];
1215     id wd = [currentWebView UIDelegate];
1216     if ([wd respondsToSelector:@selector(webView:createWebViewWithRequest:)])
1217         webView = [wd webView:currentWebView createWebViewWithRequest:nil];
1218     else
1219         webView = [[WebDefaultUIDelegate sharedUIDelegate] webView:currentWebView createWebViewWithRequest:nil];
1220     if (!webView)
1221         goto exit;
1222
1223     WebFrame *frame = [webView mainFrame];
1224     if (!frame)
1225         goto exit;
1226
1227     [frame retain];
1228
1229     [[frame _bridge] setName:frameName];
1230
1231     [[webView _UIDelegateForwarder] webViewShow:webView];
1232
1233     [[frame _bridge] setOpener:[self _bridge]];
1234     [[frame _frameLoader] _loadRequest:request triggeringAction:nil loadType:FrameLoadTypeStandard formState:formState];
1235
1236     [frame release];
1237
1238 exit:
1239     [self release];
1240 }
1241
1242 - (void)_loadURL:(NSURL *)URL referrer:(NSString *)referrer intoChild:(WebFrame *)childFrame
1243 {
1244     WebHistoryItem *parentItem = _private->currentItem;
1245     NSArray *childItems = [parentItem children];
1246     FrameLoadType loadType = [[self _frameLoader] loadType];
1247     FrameLoadType childLoadType = FrameLoadTypeInternal;
1248     WebHistoryItem *childItem = nil;
1249
1250     // If we're moving in the backforward list, we might want to replace the content
1251     // of this child frame with whatever was there at that point.
1252     // Reload will maintain the frame contents, LoadSame will not.
1253     if (childItems &&
1254         (loadType == FrameLoadTypeForward
1255          || loadType == FrameLoadTypeBack
1256          || loadType == FrameLoadTypeIndexedBackForward
1257          || loadType == FrameLoadTypeReload
1258          || loadType == FrameLoadTypeReloadAllowingStaleData))
1259     {
1260         childItem = [parentItem childItemWithName:[childFrame name]];
1261         if (childItem) {
1262             // Use the original URL to ensure we get all the side-effects, such as
1263             // onLoad handlers, of any redirects that happened. An example of where
1264             // this is needed is Radar 3213556.
1265             URL = [NSURL _web_URLWithDataAsString:[childItem originalURLString]];
1266             // These behaviors implied by these loadTypes should apply to the child frames
1267             childLoadType = loadType;
1268
1269             if (loadType == FrameLoadTypeForward
1270                 || loadType == FrameLoadTypeBack
1271                 || loadType == FrameLoadTypeIndexedBackForward)
1272             {
1273                 // For back/forward, remember this item so we can traverse any child items as child frames load
1274                 [childFrame->_private setProvisionalItem:childItem];
1275             } else {
1276                 // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
1277                 [childFrame->_private setCurrentItem:childItem];
1278             }
1279         }
1280     }
1281
1282     WebArchive *archive = [[self dataSource] _popSubframeArchiveWithName:[childFrame name]];
1283     if (archive) {
1284         [childFrame loadArchive:archive];
1285     } else {
1286         [[childFrame _frameLoader] loadURL:URL referrer:referrer loadType:childLoadType target:nil triggeringEvent:nil form:nil formValues:nil];
1287     }
1288 }
1289
1290 - (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
1291 {
1292     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1293     // This prevents a potential bug which may cause a page with a form that uses itself
1294     // as an action to be returned from the cache without submitting.
1295
1296     // FIXME: Where's the code that implements what the comment above says?
1297
1298     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1299     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1300     [request _web_setHTTPReferrer:referrer];
1301     [request setHTTPMethod:@"POST"];
1302     webSetHTTPBody(request, postData);
1303     [request _web_setHTTPContentType:contentType];
1304
1305     NSDictionary *action = [self _actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1306     WebFormState *formState = nil;
1307     if (form && values) {
1308         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:self];
1309     }
1310
1311     if (target != nil) {
1312         WebFrame *targetFrame = [self findFrameNamed:target];
1313
1314         if (targetFrame != nil) {
1315             [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1316         } else {
1317             [[self _frameLoader] checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState andCall:self
1318                 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1319         }
1320         [request release];
1321         [formState release];
1322         return;
1323     }
1324
1325     [[self _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1326
1327     [request release];
1328     [formState release];
1329 }
1330
1331 - (void)_setTitle:(NSString *)title
1332 {
1333     [_private->currentItem setTitle:title];
1334 }
1335
1336 - (void)_saveScrollPositionAndViewStateToItem:(WebHistoryItem *)item
1337 {
1338     if (item) {
1339         NSView <WebDocumentView> *docView = [[self frameView] documentView];
1340         NSView *parent = [docView superview];
1341         // we might already be detached when this is called from detachFromParent, in which
1342         // case we don't want to override real data earlier gathered with (0,0)
1343         if (parent) {
1344             NSPoint point;
1345             if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {
1346                 // The view has it's own idea of where it is scrolled to, perhaps because it contains its own
1347                 // ScrollView instead of using the one provided by the WebFrame
1348                 point = [(id <_WebDocumentViewState>)docView scrollPoint];
1349                 [item setViewState:[(id <_WebDocumentViewState>)docView viewState]];
1350             } else {
1351                 // Parent is the clipview of the DynamicScrollView the WebFrame installs
1352                 ASSERT([parent isKindOfClass:[NSClipView class]]);
1353                 point = [parent bounds].origin;
1354             }
1355             [item setScrollPoint:point];
1356         }
1357     }
1358 }
1359
1360 - (void)_defersCallbacksChanged
1361 {
1362     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1363         [[frame _frameLoader] defersCallbacksChanged];
1364 }
1365
1366 - (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
1367 {
1368     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1369         [[[frame frameView] documentView] viewWillMoveToHostWindow:hostWindow];
1370 }
1371
1372 - (void)_viewDidMoveToHostWindow
1373 {
1374     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1375         [[[frame frameView] documentView] viewDidMoveToHostWindow];
1376 }
1377
1378 - (void)_addChild:(WebFrame *)child
1379 {
1380     [[self _bridge] appendChild:[child _bridge]];
1381     [[[child dataSource] _documentLoader] setOverrideEncoding:[[[self dataSource] _documentLoader] overrideEncoding]];  
1382 }
1383
1384 // If we bailed out of a b/f navigation, we might need to set the b/f cursor back to the current
1385 // item, because we optimistically move it right away at the start of the operation. But when
1386 // alternate content is loaded for an unreachableURL, we don't want to reset the b/f cursor.
1387 // Return the item that we would reset to, so we can decide later whether to actually reset.
1388 - (WebHistoryItem *)_currentBackForwardListItemToResetTo
1389 {
1390     FrameLoadType loadType = [[self _frameLoader] loadType];
1391     if ((loadType == FrameLoadTypeForward
1392          || loadType == FrameLoadTypeBack
1393          || loadType == FrameLoadTypeIndexedBackForward)
1394         && self == [[self webView] mainFrame]) {
1395         return _private->currentItem;
1396     }
1397     return nil;
1398 }
1399
1400 - (WebHistoryItem *)_itemForSavingDocState
1401 {
1402     // For a standard page load, we will have a previous item set, which will be used to
1403     // store the form state.  However, in some cases we will have no previous item, and
1404     // the current item is the right place to save the state.  One example is when we
1405     // detach a bunch of frames because we are navigating from a site with frames to
1406     // another site.  Another is when saving the frame state of a frame that is not the
1407     // target of the current navigation (if we even decide to save with that granularity).
1408
1409     // Because of previousItem's "masking" of currentItem for this purpose, it's important
1410     // that previousItem be cleared at the end of a page transition.  We leverage the
1411     // checkLoadComplete recursion to achieve this goal.
1412
1413     return _private->previousItem ? _private->previousItem : _private->currentItem;
1414 }
1415
1416 - (WebHistoryItem *)_itemForRestoringDocState
1417 {
1418     switch ([[self _frameLoader] loadType]) {
1419         case FrameLoadTypeReload:
1420         case FrameLoadTypeReloadAllowingStaleData:
1421         case FrameLoadTypeSame:
1422         case FrameLoadTypeReplace:
1423             // Don't restore any form state on reload or loadSame
1424             return nil;
1425         case FrameLoadTypeBack:
1426         case FrameLoadTypeForward:
1427         case FrameLoadTypeIndexedBackForward:
1428         case FrameLoadTypeInternal:
1429         case FrameLoadTypeStandard:
1430             return _private->currentItem;
1431     }
1432     ASSERT_NOT_REACHED();
1433     return nil;
1434 }
1435
1436 // Walk the frame tree, telling all frames to save their form state into their current
1437 // history item.
1438 - (void)_saveDocumentAndScrollState
1439 {
1440     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1441         [[frame _bridge] saveDocumentState];
1442         [frame _saveScrollPositionAndViewStateToItem:frame->_private->currentItem];
1443     }
1444 }
1445
1446 // used to decide to use loadType=Same
1447 - (BOOL)_shouldTreatURLAsSameAsCurrent:(NSURL *)URL
1448 {
1449     WebHistoryItem *item = _private->currentItem;
1450     NSString* URLString = [URL _web_originalDataAsString];
1451     return [URLString isEqual:[item URLString]] || [URLString isEqual:[item originalURLString]];
1452 }    
1453
1454 - (void)_loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1455 {
1456     if (frameName == nil) {
1457         [self loadRequest:request];
1458         return;
1459     }
1460
1461     WebFrame *frame = [self findFrameNamed:frameName];
1462     
1463     if (frame != nil) {
1464         [frame loadRequest:request];
1465         return;
1466     }
1467
1468     NSDictionary *action = [self _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1469     [[self _frameLoader] checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil andCall:self withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1470 }
1471
1472 // Return next frame to be traversed, visiting children after parent
1473 - (WebFrame *)_nextFrameWithWrap:(BOOL)wrapFlag
1474 {
1475     return Frame([[self _bridge] nextFrameWithWrap:wrapFlag]);
1476 }
1477
1478 // Return previous frame to be traversed, exact reverse order of _nextFrame
1479 - (WebFrame *)_previousFrameWithWrap:(BOOL)wrapFlag
1480 {
1481     return Frame([[self _bridge] previousFrameWithWrap:wrapFlag]);
1482 }
1483
1484 - (BOOL)_shouldCreateRenderers
1485 {
1486     return [_private->bridge shouldCreateRenderers];
1487 }
1488
1489 - (int)_numPendingOrLoadingRequests:(BOOL)recurse
1490 {
1491     if (!recurse)
1492         return [[self _bridge] numPendingOrLoadingRequests];
1493
1494     int num = 0;
1495     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1496         num += [[frame _bridge] numPendingOrLoadingRequests];
1497
1498     return num;
1499 }
1500
1501 - (void)_reloadForPluginChanges
1502 {
1503     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1504         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1505         if (([documentView isKindOfClass:[WebHTMLView class]] && [_private->bridge containsPlugins]))
1506             [frame reload];
1507     }
1508 }
1509
1510 - (void)_attachScriptDebugger
1511 {
1512     if (!_private->scriptDebugger)
1513         _private->scriptDebugger = [[WebScriptDebugger alloc] initWithWebFrame:self];
1514 }
1515
1516 - (void)_detachScriptDebugger
1517 {
1518     if (_private->scriptDebugger) {
1519         id old = _private->scriptDebugger;
1520         _private->scriptDebugger = nil;
1521         [old release];
1522     }
1523 }
1524
1525 - (void)_recursive_pauseNullEventsForAllNetscapePlugins
1526 {
1527     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1528         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1529         if ([documentView isKindOfClass:[WebHTMLView class]])
1530             [(WebHTMLView *)documentView _pauseNullEventsForAllNetscapePlugins];
1531     }
1532 }
1533
1534 - (void)_recursive_resumeNullEventsForAllNetscapePlugins
1535 {
1536     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1537         NSView <WebDocumentView> *documentView = [[frame frameView] documentView];
1538         if ([documentView isKindOfClass:[WebHTMLView class]])
1539             [(WebHTMLView *)documentView _resumeNullEventsForAllNetscapePlugins];
1540     }
1541 }
1542
1543 - (void)_didReceiveServerRedirectForProvisionalLoadForFrame
1544 {
1545     [[[self webView] _frameLoadDelegateForwarder] webView:[self webView]
1546         didReceiveServerRedirectForProvisionalLoadForFrame:self];
1547 }
1548
1549 - (id)_initWithWebFrameView:(WebFrameView *)fv webView:(WebView *)v bridge:(WebFrameBridge *)bridge
1550 {
1551     self = [super init];
1552     if (!self)
1553         return nil;
1554
1555     _private = [[WebFramePrivate alloc] init];
1556
1557     _private->bridge = bridge;
1558
1559     if (fv) {
1560         [_private setWebFrameView:fv];
1561         [fv _setWebFrame:self];
1562     }
1563     
1564     ++WebFrameCount;
1565     
1566     return self;
1567 }
1568
1569 - (NSArray *)_documentViews
1570 {
1571     NSMutableArray *result = [NSMutableArray array];
1572     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1573         id docView = [[frame frameView] documentView];
1574         if (docView)
1575             [result addObject:docView];
1576     }
1577         
1578     return result;
1579 }
1580
1581 - (void)_updateBackground
1582 {
1583     BOOL drawsBackground = [[self webView] drawsBackground];
1584     NSColor *backgroundColor = [[self webView] backgroundColor];
1585
1586     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1587         // Never call setDrawsBackground:YES here on the scroll view or the background color will
1588         // flash between pages loads. setDrawsBackground:YES will be called in WebFrame's _frameLoadCompleted.
1589         if (!drawsBackground)
1590             [[[frame frameView] _scrollView] setDrawsBackground:NO];
1591         [[[frame frameView] _scrollView] setBackgroundColor:backgroundColor];
1592         id documentView = [[frame frameView] documentView];
1593         if ([documentView respondsToSelector:@selector(setDrawsBackground:)])
1594             [documentView setDrawsBackground:drawsBackground];
1595         if ([documentView respondsToSelector:@selector(setBackgroundColor:)])
1596             [documentView setBackgroundColor:backgroundColor];
1597         [[frame _bridge] setDrawsBackground:drawsBackground];
1598         [[frame _bridge] setBaseBackgroundColor:backgroundColor];
1599     }
1600 }
1601
1602 - (void)_setInternalLoadDelegate:(id)internalLoadDelegate
1603 {
1604     _private->internalLoadDelegate = internalLoadDelegate;
1605 }
1606
1607 - (id)_internalLoadDelegate
1608 {
1609     return _private->internalLoadDelegate;
1610 }
1611
1612 - (NSURLRequest *)_requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1613 {
1614     ASSERT(request != nil);
1615     
1616     WebView *wv = [self webView];
1617     id delegate = [wv resourceLoadDelegate];
1618     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1619     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1620     WebDataSource *dataSource = [self dataSource];
1621     
1622     if (implementations.delegateImplementsIdentifierForRequest) {
1623         *identifier = [delegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1624     } else {
1625         *identifier = [sharedDelegate webView:wv identifierForInitialRequest:request fromDataSource:dataSource];
1626     }
1627         
1628     NSURLRequest *newRequest;
1629     if (implementations.delegateImplementsWillSendRequest) {
1630         newRequest = [delegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1631     } else {
1632         newRequest = [sharedDelegate webView:wv resource:*identifier willSendRequest:request redirectResponse:nil fromDataSource:dataSource];
1633     }
1634     
1635     if (newRequest == nil) {
1636         *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1637     } else {
1638         *error = nil;
1639     }
1640     
1641     return newRequest;
1642 }
1643
1644 - (void)_sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error 
1645 {    
1646     WebView *wv = [self webView];
1647     id delegate = [wv resourceLoadDelegate];
1648     id sharedDelegate = [WebDefaultResourceLoadDelegate sharedResourceLoadDelegate];
1649     WebResourceDelegateImplementationCache implementations = [wv _resourceLoadDelegateImplementations];
1650     WebDataSource *dataSource = [self dataSource];
1651         
1652     if (response != nil) {
1653         if (implementations.delegateImplementsDidReceiveResponse) {
1654             [delegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1655         } else {
1656             [sharedDelegate webView:wv resource:identifier didReceiveResponse:response fromDataSource:dataSource];
1657         }
1658     }
1659     
1660     if (length > 0) {
1661         if (implementations.delegateImplementsDidReceiveContentLength) {
1662             [delegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1663         } else {
1664             [sharedDelegate webView:wv resource:identifier didReceiveContentLength:(WebNSUInteger)length fromDataSource:dataSource];
1665         }
1666     }
1667     
1668     if (error == nil) {
1669         if (implementations.delegateImplementsDidFinishLoadingFromDataSource) {
1670             [delegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1671         } else {
1672             [sharedDelegate webView:wv resource:identifier didFinishLoadingFromDataSource:dataSource];
1673         }
1674         [self _checkLoadComplete];
1675     } else {
1676         [[wv _resourceLoadDelegateForwarder] webView:wv resource:identifier didFailLoadingWithError:error fromDataSource:dataSource];
1677     }
1678 }
1679
1680 - (void)_safeLoadURL:(NSURL *)URL
1681 {
1682    // Call the bridge because this is where our security checks are made.
1683     [[self _bridge] loadURL:URL 
1684                     referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
1685                       reload:NO
1686                  userGesture:YES       
1687                       target:nil
1688              triggeringEvent:[NSApp currentEvent]
1689                         form:nil 
1690                   formValues:nil];
1691 }
1692
1693 - (void)_unmarkAllMisspellings
1694 {
1695     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1696         [[frame _bridge] unmarkAllMisspellings];
1697 }
1698
1699 - (BOOL)_hasSelection
1700 {
1701     id documentView = [[self frameView] documentView];    
1702     
1703     // optimization for common case to avoid creating potentially large selection string
1704     if ([documentView isKindOfClass:[WebHTMLView class]]) {
1705         DOMRange *selectedDOMRange = [[self _bridge] selectedDOMRange];
1706         return selectedDOMRange && ![selectedDOMRange collapsed];
1707     }
1708     
1709     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1710         return [[documentView selectedString] length] > 0;
1711     
1712     return NO;
1713 }
1714
1715 - (void)_clearSelection
1716 {
1717     id documentView = [[self frameView] documentView];    
1718     if ([documentView conformsToProtocol:@protocol(WebDocumentText)])
1719         [documentView deselectAll];
1720 }
1721
1722 #ifndef NDEBUG
1723
1724 - (BOOL)_atMostOneFrameHasSelection;
1725 {
1726     // FIXME: 4186050 is one known case that makes this debug check fail
1727     BOOL found = NO;
1728     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self]) {
1729         if ([frame _hasSelection]) {
1730             if (found)
1731                 return NO;
1732             found = YES;
1733         }
1734     }
1735
1736     return YES;
1737 }
1738 #endif
1739
1740 - (WebFrame *)_findFrameWithSelection
1741 {
1742     for (WebFrame *frame = self; frame; frame = [frame _traverseNextFrameStayWithin:self])
1743         if ([frame _hasSelection])
1744             return frame;
1745
1746     return nil;
1747 }
1748
1749 - (void)_clearSelectionInOtherFrames
1750 {
1751     // We rely on WebDocumentSelection protocol implementors to call this method when they become first 
1752     // responder. It would be nicer to just notice first responder changes here instead, but there's no 
1753     // notification sent when the first responder changes in general (Radar 2573089).
1754     WebFrame *frameWithSelection = [[[self webView] mainFrame] _findFrameWithSelection];
1755     if (frameWithSelection != self)
1756         [frameWithSelection _clearSelection];
1757
1758     // While we're in the general area of selection and frames, check that there is only one now.
1759     ASSERT([[[self webView] mainFrame] _atMostOneFrameHasSelection]);
1760 }
1761
1762 - (BOOL)_subframeIsLoading
1763 {
1764     // It's most likely that the last added frame is the last to load so we walk backwards.
1765     for (WebFrame *frame = [self _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1766         if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1767             return YES;
1768     return NO;
1769 }
1770
1771 - (void)_addPlugInView:(NSView *)plugInView
1772 {
1773     ASSERT([plugInView respondsToSelector:@selector(setWebFrame:)]);
1774     ASSERT(![_private->plugInViews containsObject:plugInView]);
1775     
1776     if (!_private->plugInViews)
1777         _private->plugInViews = [[NSMutableSet alloc] init];
1778         
1779     [plugInView setWebFrame:self];
1780     [_private->plugInViews addObject:plugInView];
1781 }
1782
1783 - (void)_removeAllPlugInViews
1784 {
1785     if (!_private->plugInViews)
1786         return;
1787     
1788     [_private->plugInViews makeObjectsPerformSelector:@selector(setWebFrame:) withObject:nil];
1789     [_private->plugInViews release];
1790     _private->plugInViews = nil;
1791 }
1792
1793 // This is called when leaving a page or closing the WebView
1794 - (void)_willCloseURL
1795 {
1796     [self _removeAllPlugInViews];
1797 }
1798
1799 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1800 {
1801     [request _web_setHTTPUserAgent:[[self webView] userAgentForURL:[request URL]]];
1802     
1803     if ([[self _frameLoader] loadType] == FrameLoadTypeReload)
1804         [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1805     
1806     // Don't set the cookie policy URL if it's already been set.
1807     if ([request mainDocumentURL] == nil) {
1808         if (mainResource && (self == [[self webView] mainFrame] || f))
1809             [request setMainDocumentURL:[request URL]];
1810         else
1811             [request setMainDocumentURL:[[[[self webView] mainFrame] dataSource] _URL]];
1812     }
1813     
1814     if (mainResource)
1815         [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
1816 }
1817
1818 - (BOOL)_isMainFrame
1819 {
1820     return self == [[self webView] mainFrame];
1821 }
1822
1823 - (void)_addInspector:(WebInspector *)inspector
1824 {
1825     if (!_private->inspectors)
1826         _private->inspectors = [[NSMutableSet alloc] init];
1827     ASSERT(![_private->inspectors containsObject:inspector]);
1828     [_private->inspectors addObject:inspector];
1829 }
1830
1831 - (void)_removeInspector:(WebInspector *)inspector
1832 {
1833     ASSERT([_private->inspectors containsObject:inspector]);
1834     [_private->inspectors removeObject:inspector];
1835 }
1836
1837 - (WebFrameLoader *)_frameLoader
1838 {
1839     return [_private->bridge loader];
1840 }
1841
1842 - (void)_prepareForDataSourceReplacement
1843 {
1844     if (![[self _frameLoader] dataSource]) {
1845         ASSERT(![self _childFrameCount]);
1846         return;
1847     }
1848     
1849     // Make sure that any work that is triggered by resigning first reponder can get done.
1850     // The main example where this came up is the textDidEndEditing that is sent to the
1851     // FormsDelegate (3223413).  We need to do this before _detachChildren, since that will
1852     // remove the views as a side-effect of freeing the bridge, at which point we can't
1853     // post the FormDelegate messages.
1854     //
1855     // Note that this can also take FirstResponder away from a child of our frameView that
1856     // is not in a child frame's view.  This is OK because we are in the process
1857     // of loading new content, which will blow away all editors in this top frame, and if
1858     // a non-editor is firstReponder it will not be affected by endEditingFor:.
1859     // Potentially one day someone could write a DocView whose editors were not all
1860     // replaced by loading new content, but that does not apply currently.
1861     NSView *frameView = [self frameView];
1862     NSWindow *window = [frameView window];
1863     NSResponder *firstResp = [window firstResponder];
1864     if ([firstResp isKindOfClass:[NSView class]]
1865         && [(NSView *)firstResp isDescendantOf:frameView])
1866     {
1867         [window endEditingFor:firstResp];
1868     }
1869     
1870     [self _detachChildren];
1871 }
1872
1873 - (void)_frameLoadCompleted
1874 {
1875     NSScrollView *sv = [[self frameView] _scrollView];
1876     if ([[self webView] drawsBackground])
1877         [sv setDrawsBackground:YES];
1878     [_private setPreviousItem:nil];
1879 }
1880
1881 - (WebDataSource *)_dataSourceForDocumentLoader:(WebDocumentLoader *)loader
1882 {
1883     return [(WebDocumentLoaderMac *)loader dataSource];
1884 }
1885
1886 - (WebDocumentLoader *)_createDocumentLoaderWithRequest:(NSURLRequest *)request
1887 {
1888     WebDocumentLoaderMac *loader = [[WebDocumentLoaderMac alloc] initWithRequest:request];
1889     
1890     WebDataSource *dataSource = [[WebDataSource alloc] _initWithDocumentLoader:loader];
1891     [loader setDataSource:dataSource];
1892     [dataSource release];
1893
1894     return loader;
1895 }
1896
1897 /*
1898     There is a race condition between the layout and load completion that affects restoring the scroll position.
1899     We try to restore the scroll position at both the first layout and upon load completion.
1900
1901     1) If first layout happens before the load completes, we want to restore the scroll position then so that the
1902        first time we draw the page is already scrolled to the right place, instead of starting at the top and later
1903        jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
1904        which case the restore silent fails and we will fix it in when we try to restore on doc completion.
1905     2) If the layout happens after the load completes, the attempt to restore at load completion time silently
1906        fails.  We then successfully restore it when the layout happens.
1907  */
1908
1909 - (void)_restoreScrollPositionAndViewState
1910 {
1911     ASSERT(_private->currentItem);
1912     NSView <WebDocumentView> *docView = [[self frameView] documentView];
1913     NSPoint point = [_private->currentItem scrollPoint];
1914     if ([docView conformsToProtocol:@protocol(_WebDocumentViewState)]) {        
1915         id state = [_private->currentItem viewState];
1916         if (state) {
1917             [(id <_WebDocumentViewState>)docView setViewState:state];
1918         }
1919         
1920         [(id <_WebDocumentViewState>)docView setScrollPoint:point];
1921     } else {
1922         [docView scrollPoint:point];
1923     }
1924 }
1925
1926 @end
1927
1928 @implementation WebFrame (WebPrivate)
1929
1930 // FIXME: this exists only as a convenience for Safari, consider moving there
1931 - (BOOL)_isDescendantOfFrame:(WebFrame *)ancestor
1932 {
1933     return [[self _bridge] isDescendantOfFrame:[ancestor _bridge]];
1934 }
1935
1936 - (void)_setShouldCreateRenderers:(BOOL)f
1937 {
1938     [_private->bridge setShouldCreateRenderers:f];
1939 }
1940
1941 - (NSColor *)_bodyBackgroundColor
1942 {
1943     return [_private->bridge bodyBackgroundColor];
1944 }
1945
1946 - (BOOL)_isFrameSet
1947 {
1948     return [_private->bridge isFrameSet];
1949 }
1950
1951 - (BOOL)_firstLayoutDone
1952 {
1953     return [[self _frameLoader] firstLayoutDone];
1954 }
1955
1956 - (WebFrameLoadType)_loadType
1957 {
1958     return (WebFrameLoadType)[[self _frameLoader] loadType];
1959 }
1960
1961 @end
1962
1963 @implementation WebFormState : NSObject
1964
1965 - (id)initWithForm:(DOMElement *)form values:(NSDictionary *)values sourceFrame:(WebFrame *)sourceFrame
1966 {
1967     self = [super init];
1968     if (!self)
1969         return nil;
1970     
1971     _form = [form retain];
1972     _values = [values copy];
1973     _sourceFrame = [sourceFrame retain];
1974     return self;
1975 }
1976
1977 - (void)dealloc
1978 {
1979     [_form release];
1980     [_values release];
1981     [_sourceFrame release];
1982     [super dealloc];
1983 }
1984
1985 - (DOMElement *)form
1986 {
1987     return _form;
1988 }
1989
1990 - (NSDictionary *)values
1991 {
1992     return _values;
1993 }
1994
1995 - (WebFrame *)sourceFrame
1996 {
1997     return _sourceFrame;
1998 }
1999
2000 @end
2001
2002 @implementation WebFrame
2003
2004 - (id)init
2005 {
2006     return [self initWithName:nil webFrameView:nil webView:nil];
2007 }
2008
2009 // FIXME: this method can't work any more and should be marked deprecated
2010 - (id)initWithName:(NSString *)n webFrameView:(WebFrameView *)fv webView:(WebView *)v
2011 {
2012     return [self _initWithWebFrameView:fv webView:v bridge:nil];
2013 }
2014
2015 - (void)dealloc
2016 {
2017     ASSERT(_private->bridge == nil);
2018     [_private release];
2019
2020     --WebFrameCount;
2021
2022     [super dealloc];
2023 }
2024
2025 - (void)finalize
2026 {
2027     ASSERT(_private->bridge == nil);
2028
2029     --WebFrameCount;
2030
2031     [super finalize];
2032 }
2033
2034 - (NSString *)name
2035 {
2036     return [[self _bridge] name];
2037 }
2038
2039 - (WebFrameView *)frameView
2040 {
2041     return _private->webFrameView;
2042 }
2043
2044 - (WebView *)webView
2045 {
2046     return [[[self _bridge] page] webView];
2047 }
2048
2049 - (DOMDocument *)DOMDocument
2050 {
2051     return [[self dataSource] _isDocumentHTML] ? [_private->bridge DOMDocument] : nil;
2052 }
2053
2054 - (DOMHTMLElement *)frameElement
2055 {
2056     return [[self webView] mainFrame] != self ? [_private->bridge frameElement] : nil;
2057 }
2058
2059 - (WebDataSource *)provisionalDataSource
2060 {
2061     return [[self _frameLoader] provisionalDataSource];
2062 }
2063
2064 - (WebDataSource *)dataSource
2065 {
2066     return [[self _frameLoader] dataSource];
2067 }
2068
2069 - (void)loadRequest:(NSURLRequest *)request
2070 {
2071     // FIXME: is this the right place to reset loadType? Perhaps this should be done
2072     // after loading is finished or aborted.
2073     [[self _frameLoader] setLoadType:FrameLoadTypeStandard];
2074     [[self _frameLoader] _loadRequest:request archive:nil];
2075 }
2076
2077 - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2078 {
2079     NSURLRequest *request = [self _webDataRequestForData:data 
2080                                                 MIMEType:MIMEType 
2081                                         textEncodingName:encodingName 
2082                                                  baseURL:URL
2083                                           unreachableURL:unreachableURL];
2084     [self loadRequest:request];
2085 }
2086
2087
2088 - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)URL
2089 {
2090     [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:URL unreachableURL:nil];
2091 }
2092
2093 - (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)URL unreachableURL:(NSURL *)unreachableURL
2094 {
2095     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
2096     [self _loadData:data MIMEType:nil textEncodingName:@"UTF-8" baseURL:URL unreachableURL:unreachableURL];
2097 }
2098
2099 - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)URL
2100 {
2101     [self _loadHTMLString:string baseURL:URL unreachableURL:nil];
2102 }
2103
2104 - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)URL forUnreachableURL:(NSURL *)unreachableURL
2105 {
2106     [self _loadHTMLString:string baseURL:URL unreachableURL:unreachableURL];
2107 }
2108
2109 - (void)loadArchive:(WebArchive *)archive
2110 {
2111     WebResource *mainResource = [archive mainResource];
2112     if (mainResource) {
2113         NSURLRequest *request = [self _webDataRequestForData:[mainResource data] 
2114                                                     MIMEType:[mainResource MIMEType]
2115                                             textEncodingName:[mainResource textEncodingName]
2116                                                      baseURL:[mainResource URL]
2117                                               unreachableURL:nil];
2118         [[self _frameLoader] _loadRequest:request archive:archive];
2119     }
2120 }
2121
2122 - (void)stopLoading
2123 {
2124     [[self _frameLoader] stopLoading];
2125 }
2126
2127 - (void)reload
2128 {
2129     [[self _frameLoader] reload];
2130 }
2131
2132 - (WebFrame *)findFrameNamed:(NSString *)name
2133 {
2134     return Frame([[self _bridge] findFrameNamed:name]);
2135 }
2136
2137 - (WebFrame *)parentFrame
2138 {
2139     return [[Frame([[self _bridge] parent]) retain] autorelease];
2140 }
2141
2142 - (NSArray *)childFrames
2143 {
2144     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self _childFrameCount]];
2145     for (WebFrame *child = [self _firstChildFrame]; child; child = [child _nextSiblingFrame])
2146         [children addObject:child];
2147
2148     return children;
2149 }
2150
2151 @end
2152
2153 @implementation WebFrame (WebFrameLoaderClient)
2154
2155 - (void)_resetBackForwardList
2156 {
2157     // Note this doesn't verify the current load type as a b/f operation because it is called from
2158     // a subframe in the case of a delegate bailing out of the nav before it even gets to provisional state.
2159     ASSERT(self == [[self webView] mainFrame]);
2160     WebHistoryItem *resetItem = _private->currentItem;
2161     if (resetItem)
2162         [[[self webView] backForwardList] goToItem:resetItem];
2163 }
2164
2165 - (void)_invalidateCurrentItemPageCache
2166 {
2167     // When we are pre-commit, the currentItem is where the pageCache data resides
2168     NSDictionary *pageCache = [_private->currentItem pageCache];
2169
2170     [[self _bridge] invalidatePageCache:pageCache];
2171     
2172     // We're assuming that WebCore invalidates its pageCache state in didNotOpen:pageCache:
2173     [_private->currentItem setHasPageCache:NO];
2174 }
2175
2176 - (BOOL)_provisionalItemIsTarget
2177 {
2178     return [_private->provisionalItem isTargetItem];
2179 }
2180
2181 - (BOOL)_loadProvisionalItemFromPageCache
2182 {
2183     WebHistoryItem *item = _private->provisionalItem;
2184     if (![item hasPageCache])
2185         return NO;
2186     NSDictionary *pageCache = [item pageCache];
2187     if (![pageCache objectForKey:WebCorePageCacheStateKey])
2188         return NO;
2189     LOG(PageCache, "Restoring page from back/forward cache, %@", [item URL]);
2190     [[self provisionalDataSource] _loadFromPageCache:pageCache];
2191     return YES;
2192 }
2193
2194 @end