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