Reviewed by Brady.
[WebKit-https.git] / WebKit / Loader / WebFrameLoader.m
1 /*
2  * Copyright (C) 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 "WebFrameLoader.h"
30
31 #import "WebDataProtocol.h"
32 #import "WebDocumentLoader.h"
33 #import "WebFormDataStream.h"
34 #import "WebFormState.h"
35 #import "WebFrameLoaderClient.h"
36 #import "WebMainResourceLoader.h"
37 #import <JavaScriptCore/Assertions.h>
38 #import <WebKit/DOMHTML.h>
39 #import <WebCore/WebCoreFrameBridge.h>
40 #import <WebCore/WebCoreIconDatabaseBridge.h>
41 #import <WebCore/WebCoreSystemInterface.h>
42
43 #import "WebFrameInternal.h"
44 #import "WebNSURLExtras.h"
45 #import "WebResourcePrivate.h"
46 #import "WebViewInternal.h"
47
48 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
49 {
50     return [a caseInsensitiveCompare:b] == NSOrderedSame;
51 }
52
53 BOOL isBackForwardLoadType(FrameLoadType type)
54 {
55     switch (type) {
56         case FrameLoadTypeStandard:
57         case FrameLoadTypeReload:
58         case FrameLoadTypeReloadAllowingStaleData:
59         case FrameLoadTypeSame:
60         case FrameLoadTypeInternal:
61         case FrameLoadTypeReplace:
62             return false;
63         case FrameLoadTypeBack:
64         case FrameLoadTypeForward:
65         case FrameLoadTypeIndexedBackForward:
66             return true;
67     }
68     ASSERT_NOT_REACHED();
69     return false;
70 }
71
72 @implementation WebFrameLoader
73
74 - (id)initWithFrame:(WebCoreFrameBridge *)bridge client:(WebFrame <WebFrameLoaderClient> *)c
75 {
76     self = [super init];
77     if (self) {
78         client = c;
79         frameBridge = bridge;
80         state = WebFrameStateCommittedPage;
81     }
82     return self;    
83 }
84
85 - (void)dealloc
86 {
87     // FIXME: should these even exist?
88     [mainResourceLoader release];
89     [subresourceLoaders release];
90     [plugInStreamLoaders release];
91     [documentLoader release];
92     [provisionalDocumentLoader release];
93  
94     ASSERT(!policyDocumentLoader);
95     
96     [super dealloc];
97 }
98
99 - (WebDocumentLoader *)activeDocumentLoader
100 {
101     if (state == WebFrameStateProvisional)
102         return provisionalDocumentLoader;
103     
104     return documentLoader;    
105 }
106
107 - (void)addPlugInStreamLoader:(WebLoader *)loader
108 {
109     if (!plugInStreamLoaders)
110         plugInStreamLoaders = [[NSMutableArray alloc] init];
111     [plugInStreamLoaders addObject:loader];
112     [[self activeDocumentLoader] setLoading:YES];
113 }
114
115 - (void)removePlugInStreamLoader:(WebLoader *)loader
116 {
117     [plugInStreamLoaders removeObject:loader];
118     [[self activeDocumentLoader] updateLoading];
119 }
120
121 - (void)defersCallbacksChanged
122 {
123     BOOL defers = [frameBridge defersLoading];
124     for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
125         [[frame _frameLoader] setDefersCallbacks:defers];
126 }
127
128 - (BOOL)defersCallbacks
129 {
130     return [frameBridge defersLoading];
131 }
132
133 - (void)setDefersCallbacks:(BOOL)defers
134 {
135     [mainResourceLoader setDefersCallbacks:defers];
136     
137     NSEnumerator *e = [subresourceLoaders objectEnumerator];
138     WebLoader *loader;
139     while ((loader = [e nextObject]))
140         [loader setDefersCallbacks:defers];
141     
142     e = [plugInStreamLoaders objectEnumerator];
143     while ((loader = [e nextObject]))
144         [loader setDefersCallbacks:defers];
145
146     [self deliverArchivedResourcesAfterDelay];
147 }
148
149 - (void)stopLoadingPlugIns
150 {
151     [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
152     [plugInStreamLoaders removeAllObjects];   
153 }
154
155 - (BOOL)isLoadingMainResource
156 {
157     return mainResourceLoader != nil;
158 }
159
160 - (BOOL)isLoadingSubresources
161 {
162     return [subresourceLoaders count];
163 }
164
165 - (BOOL)isLoadingPlugIns
166 {
167     return [plugInStreamLoaders count];
168 }
169
170 - (BOOL)isLoading
171 {
172     return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
173 }
174
175 - (void)stopLoadingSubresources
176 {
177     NSArray *loaders = [subresourceLoaders copy];
178     [loaders makeObjectsPerformSelector:@selector(cancel)];
179     [loaders release];
180     [subresourceLoaders removeAllObjects];
181 }
182
183 - (void)addSubresourceLoader:(WebLoader *)loader
184 {
185     ASSERT(!provisionalDocumentLoader);
186     if (subresourceLoaders == nil)
187         subresourceLoaders = [[NSMutableArray alloc] init];
188     [subresourceLoaders addObject:loader];
189     [[self activeDocumentLoader] setLoading:YES];
190 }
191
192 - (void)removeSubresourceLoader:(WebLoader *)loader
193 {
194     [subresourceLoaders removeObject:loader];
195     [[self activeDocumentLoader] updateLoading];
196 }
197
198 - (NSData *)mainResourceData
199 {
200     return [mainResourceLoader resourceData];
201 }
202
203 - (void)releaseMainResourceLoader
204 {
205     [mainResourceLoader release];
206     mainResourceLoader = nil;
207 }
208
209 - (void)cancelMainResourceLoad
210 {
211     [mainResourceLoader cancel];
212 }
213
214 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
215 {
216     mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
217     
218     [mainResourceLoader setIdentifier:identifier];
219     [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
220     if (![mainResourceLoader loadWithRequest:request]) {
221         // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
222         // should it be caught by other parts of WebKit or other parts of the app?
223         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
224         [mainResourceLoader release];
225         mainResourceLoader = nil;
226         return NO;
227     }
228     
229     return YES;
230 }
231
232 - (void)stopLoadingWithError:(NSError *)error
233 {
234     [mainResourceLoader cancelWithError:error];
235 }
236
237 - (void)setDocumentLoader:(WebDocumentLoader *)loader
238 {
239     if (loader == nil && documentLoader == nil)
240         return;
241     
242     ASSERT(loader != documentLoader);
243     
244     [client _prepareForDataSourceReplacement];
245     [documentLoader detachFromFrameLoader];
246     
247     [loader retain];
248     [documentLoader release];
249     documentLoader = loader;
250 }
251
252 - (WebDocumentLoader *)documentLoader
253 {
254     return documentLoader;
255 }
256
257 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
258 {
259     if (policyDocumentLoader == loader)
260         return;
261
262     if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
263         [policyDocumentLoader detachFromFrameLoader];
264
265     [policyDocumentLoader release];
266     [loader retain];
267     policyDocumentLoader = loader;
268 }
269    
270 - (WebDocumentLoader *)provisionalDocumentLoader
271 {
272     return provisionalDocumentLoader;
273 }
274
275 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
276 {
277     ASSERT(!loader || !provisionalDocumentLoader);
278
279     if (provisionalDocumentLoader != documentLoader)
280         [provisionalDocumentLoader detachFromFrameLoader];
281
282     [loader retain];
283     [provisionalDocumentLoader release];
284     provisionalDocumentLoader = loader;
285 }
286
287 - (WebFrameState)state
288 {
289     return state;
290 }
291
292 #if !LOG_DISABLED
293 static const char * const stateNames[] = {
294     "WebFrameStateProvisional",
295     "WebFrameStateCommittedPage",
296     "WebFrameStateComplete"
297 };
298 #endif
299
300 static CFAbsoluteTime _timeOfLastCompletedLoad;
301
302 + (CFAbsoluteTime)timeOfLastCompletedLoad
303 {
304     return _timeOfLastCompletedLoad;
305 }
306
307 - (void)provisionalLoadStarted
308 {
309     firstLayoutDone = NO;
310     [frameBridge provisionalLoadStarted];
311
312     [client _provisionalLoadStarted];
313 }
314
315 - (void)setState:(WebFrameState)newState
316 {    
317     state = newState;
318     
319     if (state == WebFrameStateProvisional)
320         [self provisionalLoadStarted];
321     else if (state == WebFrameStateComplete) {
322         [self frameLoadCompleted];
323         _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
324         [[self documentLoader] stopRecordingResponses];
325     }
326 }
327
328 - (void)clearProvisionalLoad
329 {
330     [self setProvisionalDocumentLoader:nil];
331     [client _progressCompleted];
332     [self setState:WebFrameStateComplete];
333 }
334
335 - (void)markLoadComplete
336 {
337     [self setState:WebFrameStateComplete];
338 }
339
340 - (void)commitProvisionalLoad
341 {
342     [self stopLoadingSubresources];
343     [self stopLoadingPlugIns];
344
345     [self setDocumentLoader:provisionalDocumentLoader];
346     [self setProvisionalDocumentLoader:nil];
347     [self setState:WebFrameStateCommittedPage];
348 }
349
350 - (void)stopLoadingSubframes
351 {
352     for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
353         [[(WebFrameBridge *)child frameLoader] stopLoading];
354 }
355
356 - (void)stopLoading
357 {
358     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
359     if (isStoppingLoad)
360         return;
361     
362     isStoppingLoad = YES;
363     
364     [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
365     
366     [self stopLoadingSubframes];
367     [provisionalDocumentLoader stopLoading];
368     [documentLoader stopLoading];
369     [self setProvisionalDocumentLoader:nil];
370     [self clearArchivedResources];
371
372     isStoppingLoad = NO;    
373 }
374
375 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
376 - (void)startLoading
377 {
378     [provisionalDocumentLoader prepareForLoadStart];
379         
380     if ([self isLoadingMainResource])
381         return;
382
383     [client _clearLoadingFromPageCacheForDocumentLoader:provisionalDocumentLoader];
384
385     id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
386         
387     if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
388         [provisionalDocumentLoader updateLoading];
389 }
390
391 - (void)startProvisionalLoad:(WebDocumentLoader *)loader
392 {
393     [self setProvisionalDocumentLoader:loader];
394     [self setState:WebFrameStateProvisional];
395 }
396
397 - (void)setupForReplace
398 {
399     [self setState:WebFrameStateProvisional];
400     WebDocumentLoader *old = provisionalDocumentLoader;
401     provisionalDocumentLoader = documentLoader;
402     documentLoader = nil;
403     [old release];
404     
405     [self detachChildren];
406 }
407
408 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
409 {
410     // FIXME: why retain here, but not in the other place this happens?
411
412     // The identifier is released after the last callback, rather than in dealloc,
413     // to avoid potential cycles.    
414     return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
415 }
416
417 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
418 {
419     [clientRequest setValue:[frameBridge userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
420     return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
421 }
422
423 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
424 {
425     [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
426 }
427
428 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
429 {
430     [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
431 }
432
433 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
434 {
435     [[self activeDocumentLoader] addResponse:r];
436     
437     [client _incrementProgressForIdentifier:identifier response:r];
438     [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
439 }
440
441 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
442 {
443     [client _incrementProgressForIdentifier:identifier data:data];
444     [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
445 }
446
447 - (void)_didFinishLoadingForResource:(id)identifier
448 {    
449     [client _completeProgressForIdentifier:identifier];
450     [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
451 }
452
453 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
454 {
455     [client _completeProgressForIdentifier:identifier];
456     if (error)
457         [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
458 }
459
460 - (BOOL)_privateBrowsingEnabled
461 {
462     return [client _privateBrowsingEnabled];
463 }
464
465 - (void)_finishedLoadingResource
466 {
467     [self checkLoadComplete];
468 }
469
470 - (void)_receivedError:(NSError *)error
471 {
472     [self checkLoadComplete];
473 }
474
475 - (NSURLRequest *)_originalRequest
476 {
477     return [[self activeDocumentLoader] originalRequestCopy];
478 }
479
480 - (WebFrame *)webFrame
481 {
482     return client;
483 }
484
485 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
486 {
487     WebDocumentLoader *loader = [self activeDocumentLoader];
488     [loader retain];
489     
490     WebCoreFrameBridge *bridge = frameBridge;
491     
492     // Retain the bridge because the stop may release the last reference to it.
493     [bridge retain];
494  
495     WebFrame *cli = [client retain];
496    
497     if (isComplete) {
498         // FIXME: Don't want to do this if an entirely new load is going, so should check
499         // that both data sources on the frame are either self or nil.
500         // Can't call _bridge because we might not have commited yet
501         [bridge stop];
502         if ([cli _shouldFallBackForError:error])
503             [bridge handleFallbackContent];
504     }
505     
506     if ([self state] == WebFrameStateProvisional) {
507         NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
508         [bridge didNotOpenURL:failedURL];
509         [client _invalidateCurrentItemPageCache];
510         
511         // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
512         // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
513         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are definitely
514         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
515         // has ended.
516         if (sentRedirectNotification)
517             [self clientRedirectCancelledOrFinished:NO];
518     }
519     
520     
521     [loader mainReceivedError:error complete:isComplete];
522
523     [bridge release];
524     [cli release];
525     [loader release];
526 }
527
528 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
529 {
530     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
531     // the redirect succeeded.  We should either rename this API, or add a new method, like
532     // -webView:didFinishClientRedirectForFrame:
533     [client _dispatchDidCancelClientRedirectForFrame];
534
535     if (!cancelWithLoadInProgress)
536         quickRedirectComing = NO;
537     
538     sentRedirectNotification = NO;
539 }
540
541 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
542 {
543     [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
544     
545     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
546     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
547     sentRedirectNotification = YES;
548     
549     // If a "quick" redirect comes in an, we set a special mode so we treat the next
550     // load as part of the same navigation.
551     
552     if (!documentLoader || isJavaScriptFormAction) {
553         // If we don't have a dataSource, we have no "original" load on which to base a redirect,
554         // so we better just treat the redirect as a normal load.
555         quickRedirectComing = NO;
556     } else {
557         quickRedirectComing = lockHistory;
558     }
559 }
560
561 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
562 {
563     return !(([currentURL fragment] || [destinationURL fragment]) &&
564              [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
565 }
566
567 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
568 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
569 {
570     BOOL isFormSubmission = (values != nil);
571     
572     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
573     [request setValue:referrer forHTTPHeaderField:@"Referer"];
574     [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
575     if (_loadType == FrameLoadTypeReload)
576         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
577     
578     // I believe this is never called with LoadSame.  If it is, we probably want to set the cache
579     // policy of LoadFromOrigin, but I didn't test that.
580     ASSERT(_loadType != FrameLoadTypeSame);
581     
582     NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
583     WebFormState *formState = nil;
584     if (form && values)
585         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
586     
587     if (target != nil) {
588         WebFrame *targetFrame = [client findFrameNamed:target];
589         if (targetFrame != nil) {
590             [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
591         } else {
592             [self checkNewWindowPolicyForRequest:request
593                                           action:action
594                                        frameName:target
595                                        formState:formState
596                                          andCall:self
597                                     withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
598         }
599         [request release];
600         [formState release];
601         return;
602     }
603     
604     WebDocumentLoader *oldDocumentLoader = [documentLoader retain];
605     
606     BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
607     
608     // Make sure to do scroll to anchor processing even if the URL is
609     // exactly the same so pages with '#' links and DHTML side effects
610     // work properly.
611     if (!isFormSubmission
612         && _loadType != FrameLoadTypeReload
613         && _loadType != FrameLoadTypeSame
614         && ![self shouldReloadForCurrent:URL andDestination:[frameBridge URL]]
615         
616         // We don't want to just scroll if a link from within a
617         // frameset is trying to reload the frameset into _top.
618         && ![frameBridge isFrameSet]) {
619         
620         // Just do anchor navigation within the existing content.
621         
622         // We don't do this if we are submitting a form, explicitly reloading,
623         // currently displaying a frameset, or if the new URL does not have a fragment.
624         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
625         
626         // FIXME: What about load types other than Standard and Reload?
627         
628         [oldDocumentLoader setTriggeringAction:action];
629         [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
630         [self checkNavigationPolicyForRequest:request
631                                    documentLoader:oldDocumentLoader formState:formState
632                                       andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
633     } else {
634         // must grab this now, since this load may stop the previous load and clear this flag
635         BOOL isRedirect = quickRedirectComing;
636         [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
637         if (isRedirect) {
638             quickRedirectComing = NO;
639             [provisionalDocumentLoader setIsClientRedirect:YES];
640         } else if (sameURL) {
641             // Example of this case are sites that reload the same URL with a different cookie
642             // driving the generated content, or a master frame with links that drive a target
643             // frame, where the user has clicked on the same link repeatedly.
644             [self setLoadType:FrameLoadTypeSame];
645         }            
646     }
647     
648     [request release];
649     [oldDocumentLoader release];
650     [formState release];
651 }
652
653 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
654 {
655     if (!request)
656         return;
657     
658     NSURL *URL = [request URL];
659     
660     BOOL isRedirect = quickRedirectComing;
661     quickRedirectComing = NO;
662     
663     [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
664     if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
665         // NB: must happen after _setURL, since we add based on the current request.
666         // Must also happen before we openURL and displace the scroll position, since
667         // adding the BF item will save away scroll state.
668         
669         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
670         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
671         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
672         // though its load is not yet done.  I think this all works out OK, for one because
673         // we have already saved away the scroll and doc state for the long slow load,
674         // but it's not an obvious case.
675
676         [client _addHistoryItemForFragmentScroll];
677     }
678     
679     [frameBridge scrollToAnchorWithURL:URL];
680     
681     if (!isRedirect) {
682         // This will clear previousItem from the rest of the frame tree tree that didn't
683         // doing any loading.  We need to make a pass on this now, since for anchor nav
684         // we'll not go through a real load and reach Completed state
685         [self checkLoadComplete];
686     }
687  
688     [client _dispatchDidChangeLocationWithinPageForFrame];
689     [client _didFinishLoad];
690 }
691
692 - (void)closeOldDataSources
693 {
694     // FIXME: is it important for this traversal to be postorder instead of preorder?
695     // FIXME: add helpers for postorder traversal?
696     for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
697         [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
698     
699     if (documentLoader)
700         [client _dispatchWillCloseFrame];
701
702     [client _setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
703 }
704
705 // Called after we send an openURL:... down to WebCore.
706 - (void)opened
707 {
708     if ([self loadType] == FrameLoadTypeStandard && [documentLoader isClientRedirect])
709         [client _updateHistoryAfterClientRedirect];
710
711     if ([client _isDocumentLoaderLoadingFromPageCache:documentLoader]) {
712         // Force a layout to update view size and thereby update scrollbars.
713         [client _forceLayout];
714
715         NSArray *responses = [[self documentLoader] responses];
716         NSURLResponse *response;
717         int i, count = [responses count];
718         for (i = 0; i < count; i++) {
719             response = [responses objectAtIndex: i];
720             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
721             NSError *error;
722             id identifier;
723             NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
724             [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
725             [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
726             [request release];
727         }
728         
729         [client _loadedFromPageCache];
730
731         [[self documentLoader] setPrimaryLoadComplete:YES];
732
733         // FIXME: Why only this frame and not parent frames?
734         [self checkLoadCompleteForThisFrame];
735     }
736 }
737
738 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
739 {
740     bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
741     
742     WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
743     
744     NSURLResponse *response = [pdl response];
745     
746     NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
747         ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
748     
749     if (loadType != FrameLoadTypeReplace)
750         [self closeOldDataSources];
751     
752     if (!pageCache)
753         [client _makeRepresentationForDocumentLoader:pdl];
754     
755     [self transitionToCommitted:pageCache];
756     
757     // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
758     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
759     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
760     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
761     if (sentRedirectNotification)
762         [self clientRedirectCancelledOrFinished:NO];
763     
764     NSURL *baseURL = [[provisionalDocumentLoader request] _webDataRequestBaseURL];        
765     NSURL *URL = baseURL ? baseURL : [response URL];
766     
767     if (!URL || [URL _web_isEmpty])
768         URL = [NSURL URLWithString:@"about:blank"];    
769     
770     [frameBridge openURL:URL
771                      reload:reload 
772                 contentType:[response MIMEType]
773                     refresh:[headers objectForKey:@"Refresh"]
774                lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
775                   pageCache:pageCache];
776     
777     [self opened];
778     
779     [pdl release];
780 }
781
782 - (NSURLRequest *)initialRequest
783 {
784     return [[self activeDocumentLoader] initialRequest];
785 }
786
787 - (void)_receivedData:(NSData *)data
788 {
789     [[self activeDocumentLoader] receivedData:data];
790 }
791
792 - (void)_setRequest:(NSURLRequest *)request
793 {
794     [[self activeDocumentLoader] setRequest:request];
795 }
796
797 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
798     request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
799 {
800     [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
801 }
802
803 - (WebCoreFrameBridge *)bridge
804 {
805     return frameBridge;
806 }
807
808 - (void)_handleFallbackContent
809 {
810     [frameBridge handleFallbackContent];
811 }
812
813 - (BOOL)_isStopping
814 {
815     return [[self activeDocumentLoader] isStopping];
816 }
817
818 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
819 {
820     [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
821 }
822
823 - (void)_setResponse:(NSURLResponse *)response
824 {
825     [[self activeDocumentLoader] setResponse:response];
826 }
827
828 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
829 {
830     [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
831 }
832
833 - (void)_finishedLoading
834 {
835     WebDocumentLoader *dl = [self activeDocumentLoader];
836     
837     WebCoreFrameBridge *bridge = frameBridge;
838
839     [bridge retain];
840     [dl finishedLoading];
841
842     if ([dl mainDocumentError] || ![dl frameLoader]) {
843         [bridge release];
844         return;
845     }
846
847     [dl setPrimaryLoadComplete:YES];
848     [client _dispatchDidLoadMainResourceForDocumentLoader:dl];
849     [self checkLoadComplete];
850
851     [bridge release];
852 }
853
854 - (void)_notifyIconChanged:(NSURL *)iconURL
855 {
856     ASSERT([[WebCoreIconDatabaseBridge sharedInstance] _isEnabled]);
857     NSImage *icon = [[WebCoreIconDatabaseBridge sharedInstance]
858         iconForPageURL:[[[self activeDocumentLoader] URL] _web_originalDataAsString]
859         withSize:NSMakeSize(16, 16)];
860     [client _dispatchDidReceiveIcon:icon];
861 }
862
863 - (NSURL *)_URL
864 {
865     return [[self activeDocumentLoader] URL];
866 }
867
868 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
869 {
870     return [client _cancelledErrorWithRequest:request];
871 }
872
873 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
874 {
875     return [client _fileDoesNotExistErrorWithResponse:response];    
876 }
877
878 - (void)clearArchivedResources
879 {
880     [pendingArchivedResources removeAllObjects];
881     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
882 }
883
884 - (void)deliverArchivedResources
885 {
886     if (![pendingArchivedResources count] || [self defersCallbacks])
887         return;
888         
889     NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
890     WebLoader *loader;
891     while ((loader = [keyEnum nextObject])) {
892         WebResource *resource = [pendingArchivedResources objectForKey:loader];
893         [loader didReceiveResponse:[resource _response]];
894         NSData *data = [resource data];
895         [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
896         [loader didFinishLoading];
897     }
898     
899     [pendingArchivedResources removeAllObjects];
900 }
901
902 - (void)deliverArchivedResourcesAfterDelay
903 {
904     if (![pendingArchivedResources count] || [self defersCallbacks])
905         return;
906     
907     [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
908 }
909
910 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
911 // FIXME: It would be nice to eventually to share this code somehow.
912 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
913 {
914     NSURLRequestCachePolicy policy = [theRequest cachePolicy];
915     
916     if (policy == NSURLRequestReturnCacheDataElseLoad) {
917         return YES;
918     } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
919         return YES;
920     } else if (policy == NSURLRequestReloadIgnoringCacheData) {
921         return NO;
922     } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
923         return NO;
924     } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
925         return NO;
926     } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
927         return NO;
928     } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
929         return NO;
930     } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
931         return NO;
932     } else {
933         return YES;
934     }
935 }
936
937 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
938 {
939     if (wkGetNSURLResponseMustRevalidate(response))
940         return NO;
941     if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
942         return NO;
943     return YES;
944 }
945
946 - (NSMutableDictionary *)pendingArchivedResources
947 {
948     if (!pendingArchivedResources)
949         pendingArchivedResources = [[NSMutableDictionary alloc] init];
950     
951     return pendingArchivedResources;
952 }
953
954 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
955 {
956     if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
957         WebResource *resource = [client _archivedSubresourceForURL:originalURL fromDocumentLoader:[self activeDocumentLoader]];
958         if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
959             CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
960             // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
961             [self deliverArchivedResourcesAfterDelay];
962             return YES;
963         }
964     }
965     return NO;
966 }
967
968 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
969 {
970     return [pendingArchivedResources objectForKey:loader] != nil;
971 }
972
973 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
974 {
975     [pendingArchivedResources removeObjectForKey:loader];
976     
977     if (![pendingArchivedResources count])
978         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
979 }
980
981 - (void)handleUnimplementablePolicyWithError:(NSError *)error
982 {
983     delegateIsHandlingUnimplementablePolicy = YES;
984     [client _dispatchUnableToImplementPolicyWithError:error];
985     delegateIsHandlingUnimplementablePolicy = NO;
986 }
987
988 - (void)cannotShowMIMETypeWithResponse:(NSURLResponse *)response
989 {
990     [self handleUnimplementablePolicyWithError:[client _cannotShowMIMETypeErrorWithResponse:response]];    
991 }
992
993 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
994 {
995     return [client _interruptForPolicyChangeErrorWithRequest:request];
996 }
997
998 - (BOOL)isHostedByObjectElement
999 {
1000     // Handle <object> fallback for error cases.            
1001     DOMHTMLElement *hostElement = [client frameElement];
1002     return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1003 }
1004
1005 - (BOOL)isLoadingMainFrame
1006 {
1007     return [client _isMainFrame];
1008 }
1009
1010 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1011 {
1012     return [WebView canShowMIMEType:MIMEType];
1013 }
1014
1015 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1016 {
1017     return [WebView _representationExistsForURLScheme:URLScheme];
1018 }
1019
1020 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1021 {
1022     return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1023 }
1024
1025 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1026 {
1027     [self checkNavigationPolicyForRequest:newRequest
1028                            documentLoader:[self activeDocumentLoader]
1029                                 formState:nil
1030                                   andCall:obj
1031                              withSelector:sel];
1032 }
1033
1034 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1035 {
1036     WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1037     listener = l;
1038     
1039     [l retain];
1040
1041     [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1042
1043     [l release];
1044 }
1045
1046 - (void)cancelContentPolicy
1047 {
1048     [listener _invalidate];
1049     [listener release];
1050     listener = nil;
1051 }
1052
1053 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1054 {
1055     NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1056     if (unreachableURL == nil)
1057         return NO;
1058     
1059     if (!isBackForwardLoadType(policyLoadType))
1060         return NO;
1061     
1062     // We only treat unreachableURLs specially during the delegate callbacks
1063     // for provisional load errors and navigation policy decisions. The former
1064     // case handles well-formed URLs that can't be loaded, and the latter
1065     // case handles malformed URLs and unknown schemes. Loading alternate content
1066     // at other times behaves like a standard load.
1067     WebDocumentLoader *compareDocumentLoader = nil;
1068     if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1069         compareDocumentLoader = policyDocumentLoader;
1070     else if (delegateIsHandlingProvisionalLoadError)
1071         compareDocumentLoader = [self provisionalDocumentLoader];
1072     
1073     return compareDocumentLoader != nil && [unreachableURL isEqual:[[compareDocumentLoader request] URL]];
1074 }
1075
1076 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1077 {
1078     FrameLoadType type;
1079     
1080     ASSERT(!policyDocumentLoader);
1081     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1082
1083     NSMutableURLRequest *r = [policyDocumentLoader request];
1084     [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1085     if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1086         [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1087         type = FrameLoadTypeSame;
1088     } else
1089         type = FrameLoadTypeStandard;
1090     
1091     [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1092     [client _addDocumentLoader:policyDocumentLoader toUnarchiveState:archive];
1093     
1094     // When we loading alternate content for an unreachable URL that we're
1095     // visiting in the b/f list, we treat it as a reload so the b/f list 
1096     // is appropriately maintained.
1097     if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1098         ASSERT(type == FrameLoadTypeStandard);
1099         type = FrameLoadTypeReload;
1100     }
1101     
1102     [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:nil];
1103 }
1104
1105 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1106 {
1107     ASSERT(!policyDocumentLoader);
1108     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1109
1110     [policyDocumentLoader setTriggeringAction:action];
1111     [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1112
1113     [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:formState];
1114 }
1115
1116 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1117 {
1118     if (documentLoader == nil)
1119         return;
1120
1121     NSMutableURLRequest *request = [[documentLoader request] mutableCopy];
1122     NSURL *unreachableURL = [documentLoader unreachableURL];
1123     if (unreachableURL != nil)
1124         [request setURL:unreachableURL];
1125
1126     [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1127     ASSERT(!policyDocumentLoader);
1128     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1129     [request release];
1130     
1131     [policyDocumentLoader setOverrideEncoding:encoding];
1132
1133     [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1134 }
1135
1136 - (void)reload
1137 {
1138     if (documentLoader == nil)
1139         return;
1140
1141     NSMutableURLRequest *initialRequest = [documentLoader request];
1142     
1143     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1144     // Reloading in this case will lose the current contents (see 4151001).
1145     if ([[[[documentLoader request] URL] absoluteString] length] == 0)
1146         return;
1147
1148     // Replace error-page URL with the URL we were trying to reach.
1149     NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1150     if (unreachableURL != nil)
1151         initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1152     
1153     ASSERT(!policyDocumentLoader);
1154     policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1155     NSMutableURLRequest *request = [policyDocumentLoader request];
1156
1157     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1158
1159     // If we're about to rePOST, set up action so the app can warn the user
1160     if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1161         NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeFormResubmitted
1162             event:nil originalURL:[request URL]];
1163         [policyDocumentLoader setTriggeringAction:action];
1164     }
1165
1166     [policyDocumentLoader setOverrideEncoding:[documentLoader overrideEncoding]];
1167     
1168     [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReload formState:nil];
1169 }
1170
1171 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1172 {
1173     [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1174 }
1175
1176 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1177 {
1178     [client _finishedLoadingDocument:loader];
1179 }
1180
1181 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1182 {
1183     [client _committedLoadWithDocumentLoader:loader data:data];
1184 }
1185
1186 - (BOOL)isReplacing
1187 {
1188     return loadType == FrameLoadTypeReplace;
1189 }
1190
1191 - (void)setReplacing
1192 {
1193     loadType = FrameLoadTypeReplace;
1194 }
1195
1196 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1197 {
1198     [client _revertToProvisionalWithDocumentLoader:loader];
1199 }
1200
1201 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1202 {
1203     [client _documentLoader:loader setMainDocumentError:error];
1204 }
1205
1206 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1207 {
1208     [loader setPrimaryLoadComplete:YES];
1209     [client _dispatchDidLoadMainResourceForDocumentLoader:[self activeDocumentLoader]];
1210     [self checkLoadComplete];
1211 }
1212
1213 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1214 {
1215     [client _finalSetupForReplaceWithDocumentLoader:loader];
1216 }
1217
1218 - (void)prepareForLoadStart
1219 {
1220     [client _progressStarted];
1221     [client _dispatchDidStartProvisionalLoadForFrame];
1222 }
1223
1224 - (BOOL)subframeIsLoading
1225 {
1226     // It's most likely that the last added frame is the last to load so we walk backwards.
1227     for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1228         if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1229             return YES;
1230     return NO;
1231 }
1232
1233 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1234 {
1235     [client _willChangeTitleForDocument:loader];
1236 }
1237
1238 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1239 {
1240     [client _didChangeTitleForDocument:loader];
1241
1242     // The title doesn't get communicated to the WebView until we are committed.
1243     if ([loader isCommitted]) {
1244         NSURL *URLForHistory = [client _URLForHistoryForDocumentLoader:loader];
1245         if (URLForHistory != nil) {
1246             // Must update the entries in the back-forward list too.
1247             // This must go through the WebFrame because it has the right notion of the current b/f item.
1248             [client _setTitle:[loader title] forURL:URLForHistory];
1249             [client _setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1250             [client _dispatchDidReceiveTitle:[loader title]];
1251         }
1252     }
1253 }
1254
1255 - (FrameLoadType)loadType
1256 {
1257     return loadType;
1258 }
1259
1260 - (void)setLoadType:(FrameLoadType)type
1261 {
1262     loadType = type;
1263 }
1264
1265 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1266 {
1267     [listener _invalidate];
1268     [listener release];
1269     listener = nil;
1270
1271     NSURLRequest *request = policyRequest;
1272     NSString *frameName = policyFrameName;
1273     id target = policyTarget;
1274     SEL selector = policySelector;
1275     WebFormState *formState = policyFormState;
1276
1277     policyRequest = nil;
1278     policyFrameName = nil;
1279     policyTarget = nil;
1280     policySelector = nil;
1281     policyFormState = nil;
1282
1283     if (call) {
1284         if (frameName)
1285             objc_msgSend(target, selector, nil, nil, nil);
1286         else
1287             objc_msgSend(target, selector, nil, nil);
1288     }
1289
1290     [request release];
1291     [frameName release];
1292     [target release];
1293     [formState release];
1294 }
1295
1296 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1297 {
1298     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1299         _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1300
1301     policyRequest = [request retain];
1302     policyTarget = [target retain];
1303     policyFrameName = [frameName retain];
1304     policySelector = selector;
1305     listener = [decisionListener retain];
1306     policyFormState = [formState retain];
1307
1308     [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1309     
1310     [decisionListener release];
1311 }
1312
1313 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1314 {
1315     NSURLRequest *request = [[policyRequest retain] autorelease];
1316     NSString *frameName = [[policyFrameName retain] autorelease];
1317     id target = [[policyTarget retain] autorelease];
1318     SEL selector = policySelector;
1319     WebFormState *formState = [[policyFormState retain] autorelease];
1320
1321     // will release policy* objects, hence the above retains
1322     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1323
1324     switch (policy) {
1325         case WebPolicyIgnore:
1326             request = nil;
1327             break;
1328         case WebPolicyDownload:
1329             [client _startDownloadWithRequest:request];
1330             request = nil;
1331             break;
1332         case WebPolicyUse:
1333             break;
1334     }
1335
1336     objc_msgSend(target, selector, request, frameName, formState);
1337 }
1338
1339 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1340                          documentLoader:(WebDocumentLoader *)loader
1341                               formState:(WebFormState *)formState
1342                                 andCall:(id)target
1343                            withSelector:(SEL)selector
1344 {
1345     NSDictionary *action = [loader triggeringAction];
1346     if (action == nil) {
1347         action = [self actionInformationForNavigationType:NavigationTypeOther
1348             event:nil originalURL:[request URL]];
1349         [loader setTriggeringAction:action];
1350     }
1351         
1352     // Don't ask more than once for the same request or if we are loading an empty URL.
1353     // This avoids confusion on the part of the client.
1354     if ([request isEqual:[loader lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1355         [target performSelector:selector withObject:request withObject:nil];
1356         return;
1357     }
1358     
1359     // We are always willing to show alternate content for unreachable URLs;
1360     // treat it like a reload so it maintains the right state for b/f list.
1361     if ([request _webDataRequestUnreachableURL] != nil) {
1362         if (isBackForwardLoadType(policyLoadType))
1363             policyLoadType = FrameLoadTypeReload;
1364         [target performSelector:selector withObject:request withObject:nil];
1365         return;
1366     }
1367     
1368     [loader setLastCheckedRequest:request];
1369
1370     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1371     
1372     ASSERT(policyRequest == nil);
1373     policyRequest = [request retain];
1374     ASSERT(policyTarget == nil);
1375     policyTarget = [target retain];
1376     policySelector = selector;
1377     ASSERT(listener == nil);
1378     listener = [decisionListener retain];
1379     ASSERT(policyFormState == nil);
1380     policyFormState = [formState retain];
1381
1382     delegateIsDecidingNavigationPolicy = YES;
1383     [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1384     delegateIsDecidingNavigationPolicy = NO;
1385     
1386     [decisionListener release];
1387 }
1388
1389 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1390 {
1391     NSURLRequest *request = [[policyRequest retain] autorelease];
1392     id target = [[policyTarget retain] autorelease];
1393     SEL selector = policySelector;
1394     WebFormState *formState = [[policyFormState retain] autorelease];
1395     
1396     // will release policy* objects, hence the above retains
1397     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1398
1399     switch (policy) {
1400         case WebPolicyIgnore:
1401             request = nil;
1402             break;
1403         case WebPolicyDownload:
1404             [client _startDownloadWithRequest:request];
1405             request = nil;
1406             break;
1407         case WebPolicyUse:
1408             if (![WebView _canHandleRequest:request]) {
1409                 [self handleUnimplementablePolicyWithError:[client _cannotShowURLErrorWithRequest:request]];
1410                 request = nil;
1411             }
1412             break;
1413     }
1414
1415     [target performSelector:selector withObject:request withObject:formState];
1416 }
1417
1418 // Called after the FormsDelegate is done processing willSubmitForm:
1419 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1420 {
1421     if (listener) {
1422         [listener _invalidate];
1423         [listener release];
1424         listener = nil;
1425     }
1426     [self startLoading];
1427 }
1428
1429 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1430 {
1431     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1432     // nil policyDataSource because loading the alternate page will have passed
1433     // through this method already, nested; otherwise, policyDataSource should still be set.
1434     ASSERT(policyDocumentLoader || [provisionalDocumentLoader unreachableURL] != nil);
1435
1436     BOOL isTargetItem = [client _provisionalItemIsTarget];
1437
1438     // Two reasons we can't continue:
1439     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
1440     //       is the user responding Cancel to the form repost nag sheet.
1441     //    2) User responded Cancel to an alert popped up by the before unload event handler.
1442     // The "before unload" event handler runs only for the main frame.
1443     BOOL canContinue = request && (![self isLoadingMainFrame] || [frameBridge shouldClose]);
1444
1445     if (!canContinue) {
1446         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
1447         // need to report that the client redirect was cancelled.
1448         if (quickRedirectComing)
1449             [self clientRedirectCancelledOrFinished:NO];
1450
1451         [self setPolicyDocumentLoader:nil];
1452
1453         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
1454         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
1455         // we only do this when punting a navigation for the target frame or top-level frame.  
1456         if ((isTargetItem || [self isLoadingMainFrame]) && isBackForwardLoadType(policyLoadType))
1457             [client _resetBackForwardList];
1458
1459         return;
1460     }
1461     
1462     FrameLoadType type = policyLoadType;
1463     WebDocumentLoader *dl = [policyDocumentLoader retain];
1464     
1465     [self stopLoading];
1466     loadType = type;
1467
1468     [self startProvisionalLoad:dl];
1469
1470     [dl release];
1471     [self setPolicyDocumentLoader:nil];
1472     
1473     if (isBackForwardLoadType(type) && [client _loadProvisionalItemFromPageCache])
1474         return;
1475
1476     if (formState) {
1477         // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1478         // mechanism across the willSubmitForm callout.
1479         listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1480         [[client _formDelegate] frame:client sourceFrame:[(WebFrameBridge *)[formState sourceFrame] webFrame]
1481             willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1482     } else
1483         [self continueAfterWillSubmitForm:WebPolicyUse];
1484 }
1485
1486 - (void)loadDocumentLoader:(WebDocumentLoader *)loader withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1487 {
1488     ASSERT([client _hasWebView]);
1489
1490     // Unfortunately the view must be non-nil, this is ultimately due
1491     // to parser requiring a FrameView.  We should fix this dependency.
1492
1493     ASSERT([client frameView] != nil);
1494
1495     policyLoadType = type;
1496
1497     WebFrame *parentFrame = [client parentFrame];
1498     if (parentFrame)
1499         [loader setOverrideEncoding:[[[parentFrame _frameLoader] documentLoader] overrideEncoding]];
1500
1501     [loader setFrameLoader:self];
1502
1503     [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1504
1505     [self setPolicyDocumentLoader:loader];
1506
1507     [self checkNavigationPolicyForRequest:[loader request]
1508                            documentLoader:loader
1509                                 formState:formState
1510                                   andCall:self
1511                              withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1512 }
1513
1514 - (void)didFirstLayout
1515 {
1516     if (isBackForwardLoadType(loadType) && [client _hasBackForwardList])
1517         [client _restoreScrollPositionAndViewState];
1518
1519     firstLayoutDone = YES;
1520     [client _dispatchDidFirstLayoutInFrame];
1521 }
1522
1523 - (void)frameLoadCompleted
1524 {
1525     [client _frameLoadCompleted];
1526
1527     // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1528     if (documentLoader)
1529         firstLayoutDone = YES;
1530 }
1531
1532 - (BOOL)firstLayoutDone
1533 {
1534     return firstLayoutDone;
1535 }
1536
1537 - (BOOL)isQuickRedirectComing
1538 {
1539     return quickRedirectComing;
1540 }
1541
1542 - (void)transitionToCommitted:(NSDictionary *)pageCache
1543 {
1544     ASSERT([client _hasWebView]);
1545     ASSERT([self state] == WebFrameStateProvisional);
1546
1547     if ([self state] != WebFrameStateProvisional)
1548         return;
1549
1550     [client _setCopiesOnScroll];
1551     [client _updateHistoryForCommit];
1552
1553     // The call to closeURL invokes the unload event handler, which can execute arbitrary
1554     // JavaScript. If the script initiates a new load, we need to abandon the current load,
1555     // or the two will stomp each other.
1556     WebDocumentLoader *pdl = provisionalDocumentLoader;
1557     [frameBridge closeURL];
1558     if (pdl != provisionalDocumentLoader)
1559         return;
1560
1561     [self commitProvisionalLoad];
1562
1563     // Handle adding the URL to the back/forward list.
1564     WebDocumentLoader *dl = documentLoader;
1565     NSString *ptitle = [dl title];
1566
1567     switch (loadType) {
1568     case WebFrameLoadTypeForward:
1569     case WebFrameLoadTypeBack:
1570     case WebFrameLoadTypeIndexedBackForward:
1571         if ([client _hasBackForwardList]) {
1572             [client _updateHistoryForBackForwardNavigation];
1573
1574             // Create a document view for this document, or used the cached view.
1575             if (pageCache)
1576                 [client _setDocumentViewFromPageCache:pageCache];
1577             else
1578                 [client _makeDocumentView];
1579         }
1580         break;
1581
1582     case WebFrameLoadTypeReload:
1583     case WebFrameLoadTypeSame:
1584     case WebFrameLoadTypeReplace:
1585         [client _updateHistoryForReload];
1586         [client _makeDocumentView];
1587         break;
1588
1589     // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1590     case WebFrameLoadTypeReloadAllowingStaleData:
1591         [client _makeDocumentView];
1592         break;
1593
1594     case WebFrameLoadTypeStandard:
1595         [client _updateHistoryForStandardLoad];
1596         [client _makeDocumentView];
1597         break;
1598
1599     case WebFrameLoadTypeInternal:
1600         [client _updateHistoryForInternalLoad];
1601         [client _makeDocumentView];
1602         break;
1603
1604     // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1605     // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1606     default:
1607         ASSERT_NOT_REACHED();
1608     }
1609
1610     // Tell the client we've committed this URL.
1611     ASSERT([[client frameView] documentView] != nil);
1612     [client _dispatchDidCommitLoadForFrame];
1613     
1614     // If we have a title let the WebView know about it.
1615     if (ptitle)
1616         [client _dispatchDidReceiveTitle:ptitle];
1617 }
1618
1619 - (void)checkLoadCompleteForThisFrame
1620 {
1621     ASSERT([client _hasWebView]);
1622
1623     switch ([self state]) {
1624         case WebFrameStateProvisional: {
1625             if (delegateIsHandlingProvisionalLoadError)
1626                 return;
1627
1628             WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
1629
1630             // If we've received any errors we may be stuck in the provisional state and actually complete.
1631             NSError *error = [pdl mainDocumentError];
1632             if (error != nil) {
1633                 // Check all children first.
1634                 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1635                 BOOL shouldReset = YES;
1636                 if (![pdl isLoadingInAPISense]) {
1637                     delegateIsHandlingProvisionalLoadError = YES;
1638                     [client _dispatchDidFailProvisionalLoadWithError:error];
1639                     delegateIsHandlingProvisionalLoadError = NO;
1640
1641                     // FIXME: can stopping loading here possibly have
1642                     // any effect, if isLoading is false, which it
1643                     // must be, to be in this branch of the if? And is it ok to just do 
1644                     // a full-on stopLoading?
1645                     [self stopLoadingSubframes];
1646                     [pdl stopLoading];
1647
1648                     // Finish resetting the load state, but only if another load hasn't been started by the
1649                     // delegate callback.
1650                     if (pdl == provisionalDocumentLoader)
1651                         [self clearProvisionalLoad];
1652                     else {
1653                         NSURL *unreachableURL = [provisionalDocumentLoader unreachableURL];
1654                         if (unreachableURL != nil && [unreachableURL isEqual:[[pdl request] URL]])
1655                             shouldReset = NO;
1656                     }
1657                 }
1658                 if (shouldReset)
1659                     [client _resetAfterLoadError:resetToken];
1660                 else
1661                     [client _doNotResetAfterLoadError:resetToken];
1662             }
1663             [pdl release];
1664             return;
1665         }
1666         
1667         case WebFrameStateCommittedPage: {
1668             WebDocumentLoader *dl = documentLoader;
1669             
1670             if (![dl isLoadingInAPISense]) {
1671                 [self markLoadComplete];
1672
1673                 // FIXME: Is this subsequent work important if we already navigated away?
1674                 // Maybe there are bugs because of that, or extra work we can skip because
1675                 // the new page is ready.
1676
1677                 [client _forceLayoutForNonHTML];
1678                  
1679                 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
1680                 if ((isBackForwardLoadType([self loadType]) || [self loadType] == WebFrameLoadTypeReload)
1681                         && [client _hasBackForwardList])
1682                     [client _restoreScrollPositionAndViewState];
1683
1684                 NSError *error = [dl mainDocumentError];
1685                 if (error != nil)
1686                     [client _dispatchDidFailLoadWithError:error];
1687                 else
1688                     [client _dispatchDidFinishLoadForFrame];
1689                 
1690                 [client _progressCompleted];
1691  
1692                 return;
1693             }
1694             return;
1695         }
1696         
1697         case WebFrameStateComplete:
1698             // Even if already complete, we might have set a previous item on a frame that
1699             // didn't do any data loading on the past transaction. Make sure to clear these out.
1700             [client _frameLoadCompleted];
1701             return;
1702     }
1703
1704     ASSERT_NOT_REACHED();
1705 }
1706
1707 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1708 {
1709     if (!request)
1710         return;
1711
1712     WebCoreFrameBridge <WebCoreFrameBridge> *bridge = frameBridge;
1713     [bridge retain];
1714
1715     WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1716     if (!mainFrame)
1717         goto exit;
1718
1719     WebCoreFrameBridge *mainBridge = [mainFrame _frameLoader]->frameBridge;
1720     [mainBridge retain];
1721
1722     [mainBridge setName:frameName];
1723
1724     [mainFrame _dispatchShow];
1725
1726     [mainBridge setOpener:bridge];
1727     [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1728
1729     [mainBridge release];
1730
1731 exit:
1732     [bridge release];
1733 }
1734
1735 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error 
1736 {    
1737     if (response != nil)
1738         [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1739     
1740     if (length > 0)
1741         [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1742     
1743     if (error == nil)
1744         [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1745     else
1746         [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1747 }
1748
1749 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1750 {
1751     ASSERT(request != nil);
1752     
1753     *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader]; 
1754     NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1755     
1756     if (newRequest == nil)
1757         *error = [client _cancelledErrorWithRequest:request];
1758     else
1759         *error = nil;
1760     
1761     return newRequest;
1762 }
1763
1764 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1765 {
1766     if (frameName == nil) {
1767         [client loadRequest:request];
1768         return;
1769     }
1770
1771     WebFrame *frame = [client findFrameNamed:frameName];
1772     if (frame != nil) {
1773         [frame loadRequest:request];
1774         return;
1775     }
1776
1777     NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeOther
1778         event:nil originalURL:[request URL]];
1779     [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1780         andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1781 }
1782
1783 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1784     data:(NSArray *)postData contentType:(NSString *)contentType
1785     triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1786 {
1787     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1788     // This prevents a potential bug which may cause a page with a form that uses itself
1789     // as an action to be returned from the cache without submitting.
1790
1791     // FIXME: Where's the code that implements what the comment above says?
1792
1793     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1794     [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1795     [request setValue:referrer forHTTPHeaderField:@"Referer"];
1796     [request setHTTPMethod:@"POST"];
1797     webSetHTTPBody(request, postData);
1798     [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
1799
1800     NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1801     WebFormState *formState = nil;
1802     if (form && values)
1803         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
1804
1805     if (target != nil) {
1806         WebFrame *targetFrame = [client findFrameNamed:target];
1807         if (targetFrame != nil)
1808             [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1809         else
1810             [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1811                 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1812     } else
1813         [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1814
1815     [request release];
1816     [formState release];
1817 }
1818
1819 - (void)detachChildren
1820 {
1821     // FIXME: is it really necessary to do this in reverse order any more?
1822     WebFrame *child = [client _lastChildFrame];
1823     WebFrame *prev = [child _previousSiblingFrame];
1824     for (; child; child = prev, prev = [child _previousSiblingFrame])
1825         [[child _frameLoader] detachFromParent];
1826 }
1827
1828 - (void)detachFromParent
1829 {
1830     WebCoreFrameBridge *bridge = [frameBridge retain];
1831
1832     [bridge closeURL];
1833     [self stopLoading];
1834     [client _detachedFromParent1];
1835     [self detachChildren];
1836     [client _detachedFromParent2];
1837     [self setDocumentLoader:nil];
1838     [client _detachedFromParent3];
1839     [[frameBridge parent] removeChild:bridge];
1840
1841     NSObject <WebFrameLoaderClient>* c = [client retain];
1842     [bridge close];
1843     [c _detachedFromParent4];
1844     [c release];
1845
1846     [bridge release];
1847 }
1848
1849 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1850 {
1851     [request setValue:[frameBridge userAgentForURL:[request URL]] forHTTPHeaderField:@"User-Agent"];
1852     
1853     if ([self loadType] == FrameLoadTypeReload)
1854         [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1855     
1856     // Don't set the cookie policy URL if it's already been set.
1857     if ([request mainDocumentURL] == nil) {
1858         if (mainResource && ([self isLoadingMainFrame] || f))
1859             [request setMainDocumentURL:[request URL]];
1860         else
1861             [request setMainDocumentURL:[client _mainFrameURL]];
1862     }
1863     
1864     if (mainResource)
1865         [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
1866 }
1867
1868 - (void)safeLoadURL:(NSURL *)URL
1869 {
1870    // Call the bridge because this is where our security checks are made.
1871     [frameBridge loadURL:URL 
1872                   referrer:[[[documentLoader request] URL] _web_originalDataAsString]
1873                     reload:NO
1874                userGesture:YES       
1875                     target:nil
1876            triggeringEvent:[NSApp currentEvent]
1877                       form:nil 
1878                 formValues:nil];
1879 }
1880
1881 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1882 {
1883     NavigationType navType;
1884     if (isFormSubmission) {
1885         navType = NavigationTypeFormSubmitted;
1886     } else if (event == nil) {
1887         if (type == FrameLoadTypeReload)
1888             navType = NavigationTypeReload;
1889         else if (isBackForwardLoadType(type))
1890             navType = NavigationTypeBackForward;
1891         else
1892             navType = NavigationTypeOther;
1893     } else {
1894         navType = NavigationTypeLinkClicked;
1895     }
1896     return [self actionInformationForNavigationType:navType event:event originalURL:URL];
1897 }
1898
1899 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1900 {
1901     switch ([event type]) {
1902         case NSLeftMouseDown:
1903         case NSRightMouseDown:
1904         case NSOtherMouseDown:
1905         case NSLeftMouseUp:
1906         case NSRightMouseUp:
1907         case NSOtherMouseUp: {
1908             NSView *topViewInEventWindow = [[event window] contentView];
1909             NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1910             while (viewContainingPoint != nil) {
1911                 if ([viewContainingPoint isKindOfClass:[WebView class]])
1912                     break;
1913                 viewContainingPoint = [viewContainingPoint superview];
1914             }
1915             if (viewContainingPoint != nil) {
1916                 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1917                 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
1918                 return [NSDictionary dictionaryWithObjectsAndKeys:
1919                     [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1920                     elementInfo, WebActionElementKey,
1921                     [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1922                     [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1923                     URL, WebActionOriginalURLKey,
1924                     nil];
1925             }
1926         }
1927             
1928         // fall through
1929         
1930         default:
1931             return [NSDictionary dictionaryWithObjectsAndKeys:
1932                 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1933                 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1934                 URL, WebActionOriginalURLKey,
1935                 nil];
1936     }
1937 }
1938
1939 // Called every time a resource is completely loaded, or an error is received.
1940 - (void)checkLoadComplete
1941 {
1942     ASSERT([client _hasWebView]);
1943
1944     WebFrame *parent;
1945     for (WebFrame *frame = client; frame; frame = parent) {
1946         [frame retain];
1947         [[frame _frameLoader] checkLoadCompleteForThisFrame];
1948         parent = [frame parentFrame];
1949         [frame release];
1950     }
1951 }
1952
1953 @end