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