949b6ec5eb2bef496cd47e05220f7760d8774d82
[WebKit-https.git] / WebCore / loader / FrameLoader.cpp
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 #include "config.h"
30 #include "FrameLoader.h"
31
32 #include "Cache.h"
33 #include "Chrome.h"
34 #include "CString.h"
35 #include "DOMImplementation.h"
36 #include "DocLoader.h"
37 #include "Document.h"
38 #include "DocumentLoader.h"
39 #include "EditCommand.h"
40 #include "Editor.h"
41 #include "EditorClient.h"
42 #include "Element.h"
43 #include "Event.h"
44 #include "EventNames.h"
45 #include "FloatRect.h"
46 #include "FormState.h"
47 #include "Frame.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameLoaderClient.h"
50 #include "FramePrivate.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "HistoryItem.h"
54 #include "HTMLFormElement.h"
55 #include "HTMLNames.h"
56 #include "HTMLObjectElement.h"
57 #include "HTTPParsers.h"
58 #include "IconDatabase.h"
59 #include "IconLoader.h"
60 #include "Logging.h"
61 #include "MainResourceLoader.h"
62 #include "Page.h"
63 #include "PageCache.h"
64 #include "PageState.h"
65 #include "ProgressTracker.h"
66 #include "RenderPart.h"
67 #include "RenderWidget.h"
68 #include "ResourceHandle.h"
69 #include "ResourceRequest.h"
70 #include "SegmentedString.h"
71 #include "Settings.h"
72 #include "SystemTime.h"
73 #include "TextResourceDecoder.h"
74 #include "WindowFeatures.h"
75 #include "XMLTokenizer.h"
76 #include "kjs_binding.h"
77 #include "kjs_proxy.h"
78 #include "kjs_window.h"
79 #include "xmlhttprequest.h"
80 #include <kjs/JSLock.h>
81 #include <kjs/object.h>
82
83 #if PLATFORM(MAC)
84 #include "FrameMac.h"
85 #import "WebDataProtocol.h"
86 #endif
87
88 using namespace KJS;
89
90 namespace WebCore {
91
92 using namespace HTMLNames;
93 using namespace EventNames;
94
95 struct FormSubmission {
96     const char* action;
97     String URL;
98     RefPtr<FormData> data;
99     String target;
100     String contentType;
101     String boundary;
102     RefPtr<Event> event;
103
104     FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t,
105             const String& ct, const String& b, PassRefPtr<Event> e)
106         : action(a)
107         , URL(u)
108         , data(d)
109         , target(t)
110         , contentType(ct)
111         , boundary(b)
112         , event(e)
113     {
114     }
115 };
116
117 struct ScheduledRedirection {
118     enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
119     Type type;
120     double delay;
121     String URL;
122     String referrer;
123     int historySteps;
124     bool lockHistory;
125     bool wasUserGesture;
126
127     ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory)
128         : type(redirection)
129         , delay(redirectDelay)
130         , URL(redirectURL)
131         , historySteps(0)
132         , lockHistory(redirectLockHistory)
133         , wasUserGesture(false)
134     {
135     }
136
137     ScheduledRedirection(Type locationChangeType,
138             const String& locationChangeURL, const String& locationChangeReferrer,
139             bool locationChangeLockHistory, bool locationChangeWasUserGesture)
140         : type(locationChangeType)
141         , delay(0)
142         , URL(locationChangeURL)
143         , referrer(locationChangeReferrer)
144         , historySteps(0)
145         , lockHistory(locationChangeLockHistory)
146         , wasUserGesture(locationChangeWasUserGesture)
147     {
148     }
149
150     explicit ScheduledRedirection(int historyNavigationSteps)
151         : type(historyNavigation)
152         , delay(0)
153         , historySteps(historyNavigationSteps)
154         , lockHistory(false)
155         , wasUserGesture(false)
156     {
157     }
158 };
159
160 static double storedTimeOfLastCompletedLoad;
161
162 static void cancelAll(const ResourceLoaderSet& loaders)
163 {
164     const ResourceLoaderSet copy = loaders;
165     ResourceLoaderSet::const_iterator end = copy.end();
166     for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it)
167         (*it)->cancel();
168 }
169
170 static bool getString(JSValue* result, String& string)
171 {
172     if (!result)
173         return false;
174     JSLock lock;
175     UString ustring;
176     if (!result->getString(ustring))
177         return false;
178     string = ustring;
179     return true;
180 }
181
182 bool isBackForwardLoadType(FrameLoadType type)
183 {
184     switch (type) {
185         case FrameLoadTypeStandard:
186         case FrameLoadTypeReload:
187         case FrameLoadTypeReloadAllowingStaleData:
188         case FrameLoadTypeSame:
189         case FrameLoadTypeInternal:
190         case FrameLoadTypeReplace:
191             return false;
192         case FrameLoadTypeBack:
193         case FrameLoadTypeForward:
194         case FrameLoadTypeIndexedBackForward:
195             return true;
196     }
197     ASSERT_NOT_REACHED();
198     return false;
199 }
200
201 static int numRequests(Document* document)
202 {
203     if (document)
204         return cache()->loader()->numRequests(document->docLoader());
205     return 0;
206 }
207
208 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
209     : m_frame(frame)
210     , m_client(client)
211     , m_state(FrameStateCommittedPage)
212     , m_loadType(FrameLoadTypeStandard)
213     , m_policyLoadType(FrameLoadTypeStandard)
214     , m_delegateIsHandlingProvisionalLoadError(false)
215     , m_delegateIsDecidingNavigationPolicy(false)
216     , m_delegateIsHandlingUnimplementablePolicy(false)
217     , m_firstLayoutDone(false)
218     , m_quickRedirectComing(false)
219     , m_sentRedirectNotification(false)
220     , m_inStopAllLoaders(false)
221     , m_cachePolicy(CachePolicyVerify)
222     , m_isExecutingJavaScriptFormAction(false)
223     , m_isRunningScript(false)
224     , m_wasLoadEventEmitted(false)
225     , m_wasUnloadEventEmitted(false)
226     , m_isComplete(false)
227     , m_isLoadingMainResource(false)
228     , m_cancellingWithLoadInProgress(false)
229     , m_needsClear(false)
230     , m_receivedData(false)
231     , m_encodingWasChosenByUser(false)
232     , m_containsPlugIns(false)
233     , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
234     , m_opener(0)
235     , m_openedByJavaScript(false)
236 {
237 }
238
239 FrameLoader::~FrameLoader()
240 {
241     setOpener(0);
242
243     HashSet<Frame*>::iterator end = m_openedFrames.end();
244     for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
245         (*it)->loader()->m_opener = 0;
246         
247     m_client->frameLoaderDestroyed();
248 }
249
250 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers)
251 {
252     const ResourceLoaderSet copy = loaders;
253     ResourceLoaderSet::const_iterator end = copy.end();
254     for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it)
255         (*it)->setDefersLoading(defers);
256 }
257
258 void FrameLoader::setDefersLoading(bool defers)
259 {
260     if (m_mainResourceLoader)
261         m_mainResourceLoader->setDefersLoading(defers);
262     setAllDefersLoading(m_subresourceLoaders, defers);
263     setAllDefersLoading(m_plugInStreamLoaders, defers);
264     m_client->setDefersLoading(defers);
265 }
266
267 Frame* FrameLoader::createWindow(const FrameLoadRequest& request, const WindowFeatures& features)
268
269     ASSERT(!features.dialog || request.frameName().isEmpty());
270
271     if (!request.frameName().isEmpty())
272         if (Frame* frame = m_frame->tree()->find(request.frameName())) {
273             if (!request.resourceRequest().url().isEmpty())
274                 frame->loader()->load(request, true, 0, 0, HashMap<String, String>());
275             frame->page()->chrome()->focus();
276             return frame;
277         }
278
279     // FIXME: Setting the referrer should be the caller's responsibility.
280     FrameLoadRequest requestWithReferrer = request;
281     requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
282     
283     Page* page;
284     if (features.dialog)
285         page = m_frame->page()->chrome()->createModalDialog(requestWithReferrer);
286     else
287         page = m_frame->page()->chrome()->createWindow(requestWithReferrer);
288     if (!page)
289         return 0;
290
291     Frame* frame = page->mainFrame();
292     frame->tree()->setName(request.frameName());
293
294     page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
295     page->chrome()->setStatusbarVisible(features.statusBarVisible);
296     page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
297     page->chrome()->setMenubarVisible(features.menuBarVisible);
298     page->chrome()->setResizable(features.resizable);
299
300     // 'x' and 'y' specify the location of the window, while 'width' and 'height' 
301     // specify the size of the page. We can only resize the window, so 
302     // adjust for the difference between the window size and the page size.
303
304     FloatRect windowRect = page->chrome()->windowRect();
305     FloatSize pageSize = page->chrome()->pageRect().size();
306     if (features.xSet)
307         windowRect.setX(features.x);
308     if (features.ySet)
309         windowRect.setY(features.y);
310     if (features.widthSet)
311         windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
312     if (features.heightSet)
313         windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
314     page->chrome()->setWindowRect(windowRect);
315
316     page->chrome()->show();
317
318     return frame;
319 }
320
321 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
322 {
323     return m_client->canHandleRequest(request);
324 }
325
326 void FrameLoader::changeLocation(const String& URL, const String& referrer, bool lockHistory, bool userGesture)
327 {
328     if (URL.find("javascript:", 0, false) == 0) {
329         String script = KURL::decode_string(URL.substring(strlen("javascript:")).deprecatedString());
330         JSValue* result = executeScript(0, script, userGesture);
331         String scriptResult;
332         if (getString(result, scriptResult)) {
333             begin(m_URL);
334             write(scriptResult);
335             end();
336         }
337         return;
338     }
339
340     ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
341         ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
342     ResourceRequest request(completeURL(URL), referrer, policy);
343     
344     urlSelected(request, "_self", 0, lockHistory);
345 }
346
347 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory)
348 {
349     String target = _target;
350     if (target.isEmpty() && m_frame->document())
351         target = m_frame->document()->baseTarget();
352
353     const KURL& url = request.url();
354     if (url.url().startsWith("javascript:", false)) {
355         executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))), true);
356         return;
357     }
358
359     if (!url.isValid())
360         return;
361
362     FrameLoadRequest frameRequest(request, target);
363
364     if (frameRequest.resourceRequest().httpReferrer().isEmpty())
365         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
366
367     urlSelected(frameRequest, triggeringEvent);
368 }
369
370 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
371 {
372     // Support for <frame src="javascript:string">
373     KURL scriptURL;
374     KURL url;
375     if (urlString.startsWith("javascript:", false)) {
376         scriptURL = urlString.deprecatedString();
377         url = "about:blank";
378     } else
379         url = completeURL(urlString);
380
381     Frame* frame = m_frame->tree()->child(frameName);
382     if (frame) {
383         ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
384             ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
385         frame->loader()->urlSelected(ResourceRequest(url, m_outgoingReferrer, policy), 0);
386     } else
387         frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
388     
389     if (!frame)
390         return false;
391
392     if (!scriptURL.isEmpty())
393         frame->loader()->replaceContentsWithScriptResult(scriptURL);
394
395     return true;
396 }
397
398 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
399 {
400     Frame* frame = createFrame(url, name, ownerElement, referrer);
401     if (!frame)  {
402         checkEmitLoadEvent();
403         return 0;
404     }
405     
406     frame->loader()->m_isComplete = false;
407     
408     if (ownerElement->renderer() && frame->view())
409         static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
410     
411     checkEmitLoadEvent();
412     
413     // In these cases, the synchronous load would have finished
414     // before we could connect the signals, so make sure to send the 
415     // completed() signal for the child by hand
416     // FIXME: In this case the Frame will have finished loading before 
417     // it's being added to the child list. It would be a good idea to
418     // create the child first, then invoke the loader separately.
419     if (url.isEmpty() || url == "about:blank") {
420         frame->loader()->completed();
421         frame->loader()->checkCompleted();
422     }
423
424     return frame;
425 }
426
427 void FrameLoader::submitFormAgain()
428 {
429     if (m_isRunningScript)
430         return;
431     OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
432     if (form)
433         submitForm(form->action, form->URL, form->data, form->target,
434             form->contentType, form->boundary, form->event.get());
435 }
436
437 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
438     const String& target, const String& contentType, const String& boundary, Event* event)
439 {
440     ASSERT(formData.get());
441     
442     KURL u = completeURL(url.isNull() ? "" : url);
443     if (!u.isValid())
444         return;
445
446     DeprecatedString urlString = u.url();
447     if (urlString.startsWith("javascript:", false)) {
448         m_isExecutingJavaScriptFormAction = true;
449         executeScript(0, KURL::decode_string(urlString.mid(strlen("javascript:"))));
450         m_isExecutingJavaScriptFormAction = false;
451         return;
452     }
453
454     if (m_isRunningScript) {
455         if (m_deferredFormSubmission)
456             return;
457         m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target,
458             contentType, boundary, event));
459         return;
460     }
461
462     FrameLoadRequest frameRequest;
463
464     if (!m_outgoingReferrer.isEmpty())
465         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
466
467     frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
468
469     // Handle mailto: forms
470     bool mailtoForm = u.protocol() == "mailto";
471     if (mailtoForm) {
472         // Append body=
473         String body;
474         if (equalIgnoringCase(contentType, "multipart/form-data"))
475             // FIXME: is this correct? I suspect not, but what site can we test this on?
476             body = formData->flattenToString();
477         else if (equalIgnoringCase(contentType, "text/plain"))
478             // Convention seems to be to decode, and s/&/\n/
479             body = KURL::decode_string(
480                 formData->flattenToString().replace('&', '\n')
481                 .replace('+', ' ').deprecatedString()); // Recode for the URL
482         else
483             body = formData->flattenToString();
484
485         String query = u.query();
486         if (!query.isEmpty())
487             query.append('&');
488         u.setQuery((query + "body=" + KURL::encode_string(body.deprecatedString())).deprecatedString());
489     }
490
491     if (strcmp(action, "GET") == 0) {
492         if (!mailtoForm)
493             u.setQuery(formData->flattenToString().deprecatedString());
494     } else {
495         frameRequest.resourceRequest().setHTTPBody(formData.get());
496         frameRequest.resourceRequest().setHTTPMethod("POST");
497
498         // construct some user headers if necessary
499         if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
500             frameRequest.resourceRequest().setHTTPContentType(contentType);
501         else // contentType must be "multipart/form-data"
502             frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
503     }
504
505     frameRequest.resourceRequest().setURL(u);
506
507     submitForm(frameRequest, event);
508 }
509
510 void FrameLoader::stopLoading(bool sendUnload)
511 {
512     if (m_frame->document() && m_frame->document()->tokenizer())
513         m_frame->document()->tokenizer()->stopParsing();
514   
515     m_responseRefreshHeader = String();
516     m_responseModifiedHeader = String();
517
518     if (sendUnload) {
519         if (m_frame->document()) {
520             if (m_wasLoadEventEmitted && !m_wasUnloadEventEmitted) {
521                 Node* currentFocusedNode = m_frame->document()->focusedNode();
522                 if (currentFocusedNode)
523                     currentFocusedNode->aboutToUnload();
524                 m_frame->document()->dispatchWindowEvent(unloadEvent, false, false);
525                 if (m_frame->document())
526                     m_frame->document()->updateRendering();
527                 m_wasUnloadEventEmitted = true;
528             }
529         }
530         if (m_frame->document() && !m_frame->document()->inPageCache())
531             m_frame->document()->removeAllEventListenersFromAllNodes();
532     }
533
534     m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
535     m_isLoadingMainResource = false;
536     m_wasLoadEventEmitted = true; // don't want that one either
537     m_cachePolicy = CachePolicyVerify; // Why here?
538
539     if (m_frame->document() && m_frame->document()->parsing()) {
540         finishedParsing();
541         m_frame->document()->setParsing(false);
542     }
543   
544     m_workingURL = KURL();
545
546     if (Document* doc = m_frame->document()) {
547         if (DocLoader* docLoader = doc->docLoader())
548             cache()->loader()->cancelRequests(docLoader);
549         XMLHttpRequest::cancelRequests(doc);
550     }
551
552     // tell all subframes to stop as well
553     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
554         child->loader()->stopLoading(sendUnload);
555
556     cancelRedirection();
557 }
558
559 void FrameLoader::stop()
560 {
561     // http://bugs.webkit.org/show_bug.cgi?id=10854
562     // The frame's last ref may be removed and it will be deleted by checkCompleted().
563     RefPtr<Frame> protector(m_frame);
564     
565     if (m_frame->document()) {
566         if (m_frame->document()->tokenizer())
567             m_frame->document()->tokenizer()->stopParsing();
568         m_frame->document()->finishParsing();
569     } else
570         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
571         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
572         // become true. An example is when a subframe is a pure text doc, and that subframe is the
573         // last one to complete.
574         checkCompleted();
575     if (m_iconLoader)
576         m_iconLoader->stopLoading();
577 }
578
579 bool FrameLoader::closeURL()
580 {
581     saveDocumentState();
582     stopLoading(true);
583     m_frame->editor()->clearUndoRedoOperations();
584     return true;
585 }
586
587 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
588 {
589     m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
590
591     stopRedirectionTimer();
592
593     m_scheduledRedirection.clear();
594 }
595
596 KURL FrameLoader::iconURL()
597 {
598     // If this isn't a top level frame, return nothing
599     if (m_frame->tree() && m_frame->tree()->parent())
600         return "";
601         
602     // If we have an iconURL from a Link element, return that
603     if (m_frame->document() && !m_frame->document()->iconURL().isEmpty())
604         return m_frame->document()->iconURL().deprecatedString();
605         
606     // Don't return a favicon iconURL unless we're http or https
607     if (m_URL.protocol() != "http" && m_URL.protocol() != "https")
608         return "";
609         
610     KURL url;
611     url.setProtocol(m_URL.protocol());
612     url.setHost(m_URL.host());
613     url.setPath("/favicon.ico");
614     return url;
615 }
616
617 bool FrameLoader::didOpenURL(const KURL& url)
618 {
619     if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
620         // A redirect was scheduled before the document was created.
621         // This can happen when one frame changes another frame's location.
622         return false;
623
624     cancelRedirection();
625     m_frame->editor()->setLastEditCommand(0);
626     closeURL();
627
628     m_isComplete = false;
629     m_isLoadingMainResource = true;
630     m_wasLoadEventEmitted = false;
631
632     m_frame->d->m_kjsStatusBarText = String();
633     m_frame->d->m_kjsDefaultStatusBarText = String();
634
635     m_URL = url;
636     if (m_URL.protocol().startsWith("http") && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
637         m_URL.setPath("/");
638     m_workingURL = m_URL;
639
640     started();
641
642     return true;
643 }
644
645 void FrameLoader::didExplicitOpen()
646 {
647     m_isComplete = false;
648     m_wasLoadEventEmitted = false;
649
650     // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
651     // from a subsequent window.document.open / window.document.write call. 
652     // Cancelling redirection here works for all cases because document.open 
653     // implicitly precedes document.write.
654     cancelRedirection(); 
655     if (m_frame->document()->URL() != "about:blank")
656         m_URL = m_frame->document()->URL();
657 }
658
659 void FrameLoader::replaceContentsWithScriptResult(const KURL& url)
660 {
661     JSValue* result = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
662     String scriptResult;
663     if (!getString(result, scriptResult))
664         return;
665     begin();
666     write(scriptResult);
667     end();
668 }
669
670 JSValue* FrameLoader::executeScript(Node* node, const String& script, bool forceUserGesture)
671 {
672     return executeScript(forceUserGesture ? String() : String(m_URL.url()), 0, node, script);
673 }
674
675 JSValue* FrameLoader::executeScript(const String& URL, int baseLine, Node* node, const String& script)
676 {
677     KJSProxy* proxy = m_frame->scriptProxy();
678     if (!proxy)
679         return 0;
680
681     bool wasRunningScript = m_isRunningScript;
682     m_isRunningScript = true;
683
684     JSValue* result = proxy->evaluate(URL, baseLine, script, node);
685
686     if (!wasRunningScript) {
687         m_isRunningScript = false;
688         submitFormAgain();
689         Document::updateDocumentsRendering();
690     }
691
692     return result;
693 }
694
695 void FrameLoader::cancelAndClear()
696 {
697     cancelRedirection();
698
699     if (!m_isComplete)
700         closeURL();
701
702     clear(false);
703 }
704
705 void FrameLoader::clear(bool clearWindowProperties)
706 {
707     // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it
708     // back causes a measurable performance regression which we will need to fix to restore the correct behavior
709     // urlsBridgeKnowsAbout.clear();
710
711 #if PLATFORM(MAC)
712     Mac(m_frame)->setMarkedTextRange(0, nil, nil);
713 #endif
714
715     if (!m_needsClear)
716         return;
717     m_needsClear = false;
718     
719     if (m_frame->document()) {
720         m_frame->document()->cancelParsing();
721         m_frame->document()->willRemove();
722         m_frame->document()->detach();
723     }
724
725     // Do this after detaching the document so that the unload event works.
726     if (clearWindowProperties && m_frame->scriptProxy())
727         m_frame->scriptProxy()->clear();
728
729     m_frame->selectionController()->clear();
730     m_frame->eventHandler()->clear();
731     if (m_frame->view())
732         m_frame->view()->clear();
733
734     // Do not drop the document before the script proxy and view are cleared, as some destructors
735     // might still try to access the document.
736     m_frame->d->m_doc = 0;
737     m_decoder = 0;
738
739     m_containsPlugIns = false;
740     m_frame->cleanupPluginObjects();
741   
742     m_redirectionTimer.stop();
743     m_scheduledRedirection.clear();
744
745     m_receivedData = false;
746
747     if (!m_encodingWasChosenByUser)
748         m_encoding = String();
749 }
750
751 void FrameLoader::receivedFirstData()
752 {
753     begin(m_workingURL);
754
755     m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
756     m_workingURL = KURL();
757
758     const String& refresh = m_responseRefreshHeader;
759
760     double delay;
761     String URL;
762
763     if (!parseHTTPRefresh(refresh, delay, URL))
764         return;
765
766     if (URL.isEmpty())
767         URL = m_URL.url();
768     else
769         URL = m_frame->document()->completeURL(URL);
770
771     // We want a new history item if the refresh timeout > 1 second
772     scheduleRedirection(delay, URL, delay <= 1);
773 }
774
775 const String& FrameLoader::responseMIMEType() const
776 {
777     return m_responseMIMEType;
778 }
779
780 void FrameLoader::setResponseMIMEType(const String& type)
781 {
782     m_responseMIMEType = type;
783 }
784
785 void FrameLoader::begin()
786 {
787     begin(KURL());
788 }
789
790 void FrameLoader::begin(const KURL& url)
791 {
792     if (m_workingURL.isEmpty())
793         createEmptyDocument(); // Creates an empty document if we don't have one already
794
795     clear();
796     partClearedInBegin();
797
798     m_needsClear = true;
799     m_isComplete = false;
800     m_wasLoadEventEmitted = false;
801     m_isLoadingMainResource = true;
802
803     KURL ref(url);
804     ref.setUser(DeprecatedString());
805     ref.setPass(DeprecatedString());
806     ref.setRef(DeprecatedString());
807     m_outgoingReferrer = ref.url();
808     m_URL = url;
809     KURL baseurl;
810
811     if (!m_URL.isEmpty())
812         baseurl = m_URL;
813
814     RefPtr<Document> document = DOMImplementation::instance()->
815         createDocument(m_responseMIMEType, m_frame->view(), m_frame->inViewSourceMode());
816     m_frame->d->m_doc = document;
817
818     if (!document->attached())
819         document->attach();
820     document->setURL(m_URL.url());
821     // We prefer m_baseURL over m_URL because m_URL changes when we are
822     // about to load a new page.
823     document->setBaseURL(baseurl.url());
824     if (m_decoder)
825         document->setDecoder(m_decoder.get());
826
827     updatePolicyBaseURL();
828
829     document->docLoader()->setAutoLoadImages(m_frame->settings()->loadsImagesAutomatically());
830
831     const KURL& userStyleSheet = m_frame->settings()->userStyleSheetLocation();
832     if (!userStyleSheet.isEmpty())
833         m_frame->setUserStyleSheetLocation(KURL(userStyleSheet));
834
835     restoreDocumentState();
836
837     document->implicitOpen();
838
839     if (m_frame->view())
840         m_frame->view()->resizeContents(0, 0);
841 }
842
843 void FrameLoader::write(const char* str, int len, bool flush)
844 {
845     if (len == 0 && !flush)
846         return;
847     
848     if (len == -1)
849         len = strlen(str);
850
851     Tokenizer* tokenizer = m_frame->document()->tokenizer();
852     if (tokenizer && tokenizer->wantsRawData()) {
853         tokenizer->writeRawData(str, len);
854         return;
855     }
856     
857     if (!m_decoder) {
858         m_decoder = new TextResourceDecoder(m_responseMIMEType, m_frame->settings()->defaultTextEncodingName());
859         if (!m_encoding.isNull())
860             m_decoder->setEncoding(m_encoding,
861                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
862         if (m_frame->document())
863             m_frame->document()->setDecoder(m_decoder.get());
864     }
865
866     String decoded = m_decoder->decode(str, len);
867     if (flush)
868         decoded += m_decoder->flush();
869     if (decoded.isEmpty())
870         return;
871
872     if (!m_receivedData) {
873         m_receivedData = true;
874         m_frame->document()->determineParseMode(decoded);
875         if (m_decoder->encoding().usesVisualOrdering())
876             m_frame->document()->setVisuallyOrdered();
877         m_frame->document()->recalcStyle(Node::Force);
878     }
879
880     if (tokenizer) {
881         ASSERT(!tokenizer->wantsRawData());
882         tokenizer->write(decoded, true);
883     }
884 }
885
886 void FrameLoader::write(const String& str)
887 {
888     if (str.isNull())
889         return;
890
891     if (!m_receivedData) {
892         m_receivedData = true;
893         m_frame->document()->setParseMode(Document::Strict);
894     }
895
896     if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
897         tokenizer->write(str, true);
898 }
899
900 void FrameLoader::end()
901 {
902     m_isLoadingMainResource = false;
903     endIfNotLoading();
904 }
905
906 void FrameLoader::endIfNotLoading()
907 {
908     // http://bugs.webkit.org/show_bug.cgi?id=10854
909     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
910     // so we'll add a protective refcount
911     RefPtr<Frame> protector(m_frame);
912
913     if (m_isLoadingMainResource)
914         return;
915
916     // make sure nothing's left in there
917     if (m_frame->document()) {
918         write(0, 0, true);
919         m_frame->document()->finishParsing();
920     } else
921         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
922         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
923         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
924         // last one to complete.
925         checkCompleted();
926
927     startIconLoader();
928 }
929
930 void FrameLoader::startIconLoader()
931 {
932     // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
933     // But we should instead do it when we're done parsing the head element.
934     if (!isLoadingMainFrame())
935         return;
936
937     IconDatabase* iconDB = IconDatabase::sharedIconDatabase();
938     if (!iconDB)
939         return;
940     if (!iconDB->enabled())
941         return;
942
943     KURL url(iconURL());
944     String urlString(url.url());
945     if (urlString.isEmpty())
946         return;
947
948     // If we already have an unexpired icon, we won't kick off a load but we *will* map the appropriate URLs to it
949     if (iconDB->hasEntryForIconURL(urlString) && loadType() != FrameLoadTypeReload && !iconDB->isIconExpiredForIconURL(urlString)) {
950         commitIconURLToIconDatabase(url);
951         return;
952     }
953
954     if (!m_iconLoader)
955         m_iconLoader.set(IconLoader::create(m_frame).release());
956     m_iconLoader->startLoading();
957 }
958
959 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
960 {
961     IconDatabase* iconDB = IconDatabase::sharedIconDatabase();
962     ASSERT(iconDB);
963     iconDB->setIconURLForPageURL(icon.url(), m_URL.url());
964     iconDB->setIconURLForPageURL(icon.url(), originalRequestURL().url());
965 }
966
967 void FrameLoader::restoreDocumentState()
968 {
969     Document* doc = m_frame->document();
970     if (!doc)
971         return;
972         
973     HistoryItem* itemToRestore = 0;
974     
975     switch (loadType()) {
976         case FrameLoadTypeReload:
977         case FrameLoadTypeReloadAllowingStaleData:
978         case FrameLoadTypeSame:
979         case FrameLoadTypeReplace:
980             break;
981         case FrameLoadTypeBack:
982         case FrameLoadTypeForward:
983         case FrameLoadTypeIndexedBackForward:
984         case FrameLoadTypeInternal:
985         case FrameLoadTypeStandard:
986             itemToRestore = m_currentHistoryItem.get(); 
987     }
988     
989     if (!itemToRestore)
990         return;
991         
992     doc->setStateForNewFormElements(itemToRestore->documentState());
993 }
994
995 void FrameLoader::gotoAnchor()
996 {
997     // If our URL has no ref, then we have no place we need to jump to.
998     // OTOH if css target was set previously, we want to set it to 0, recalc
999     // and possibly repaint because :target pseudo class may have been
1000     // set(See bug 11321)
1001     if (!m_URL.hasRef() &&
1002         !(m_frame->document() && m_frame->document()->getCSSTarget()))
1003         return;
1004
1005     DeprecatedString ref = m_URL.encodedHtmlRef();
1006     if (!gotoAnchor(ref)) {
1007         // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1008         // Decoding here has to match encoding in completeURL, which means it has to use the
1009         // page's encoding rather than UTF-8.
1010         if (m_decoder)
1011             gotoAnchor(KURL::decode_string(ref, m_decoder->encoding()));
1012     }
1013 }
1014
1015 void FrameLoader::finishedParsing()
1016 {
1017     // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1018     // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1019     RefPtr<Frame> protector = m_frame->refCount() > 0 ? m_frame : 0;
1020
1021     checkCompleted();
1022
1023     if (!m_frame->view())
1024         return; // We are being destroyed by something checkCompleted called.
1025
1026     // Check if the scrollbars are really needed for the content.
1027     // If not, remove them, relayout, and repaint.
1028     m_frame->view()->restoreScrollbar();
1029
1030     m_client->dispatchDidFinishDocumentLoad();
1031
1032     gotoAnchor();
1033 }
1034
1035 void FrameLoader::loadDone()
1036 {
1037     if (m_frame->document())
1038         checkCompleted();
1039 }
1040
1041 void FrameLoader::checkCompleted()
1042 {
1043     // Any frame that hasn't completed yet?
1044     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1045         if (!child->loader()->m_isComplete)
1046             return;
1047
1048     // Have we completed before?
1049     if (m_isComplete)
1050         return;
1051
1052     // Are we still parsing?
1053     if (m_frame->document() && m_frame->document()->parsing())
1054         return;
1055
1056     // Still waiting for images/scripts?
1057     if (m_frame->document() && m_frame->document()->docLoader())
1058         if (cache()->loader()->numRequests(m_frame->document()->docLoader()))
1059             return;
1060
1061     // OK, completed.
1062     m_isComplete = true;
1063
1064     checkEmitLoadEvent(); // if we didn't do it before
1065
1066     // Do not start a redirection timer for subframes here.
1067     // That is deferred until the parent is completed.
1068     if (m_scheduledRedirection && !m_frame->tree()->parent())
1069         startRedirectionTimer();
1070
1071     completed();
1072 }
1073
1074 void FrameLoader::checkEmitLoadEvent()
1075 {
1076     if (m_wasLoadEventEmitted || !m_frame->document() || m_frame->document()->parsing())
1077         return;
1078
1079     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1080         if (!child->loader()->m_isComplete) // still got a frame running -> too early
1081             return;
1082
1083     // All frames completed -> set their domain to the frameset's domain
1084     // This must only be done when loading the frameset initially (#22039),
1085     // not when following a link in a frame (#44162).
1086     if (m_frame->document()) {
1087         String domain = m_frame->document()->domain();
1088         for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1089             if (child->document())
1090                 child->document()->setDomain(domain);
1091     }
1092
1093     m_wasLoadEventEmitted = true;
1094     m_wasUnloadEventEmitted = false;
1095     if (m_frame->document())
1096         m_frame->document()->implicitClose();
1097 }
1098
1099 KURL FrameLoader::baseURL() const
1100 {
1101     if (!m_frame->document())
1102         return KURL();
1103     return m_frame->document()->baseURL();
1104 }
1105
1106 String FrameLoader::baseTarget() const
1107 {
1108     if (!m_frame->document())
1109         return String();
1110     return m_frame->document()->baseTarget();
1111 }
1112
1113 KURL FrameLoader::completeURL(const String& url)
1114 {
1115     if (!m_frame->document())
1116         return url.deprecatedString();
1117     return m_frame->document()->completeURL(url).deprecatedString();
1118 }
1119
1120 void FrameLoader::scheduleRedirection(double delay, const String& url, bool doLockHistory)
1121 {
1122     if (delay < 0 || delay > INT_MAX / 1000)
1123         return;
1124     if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1125         scheduleRedirection(new ScheduledRedirection(delay, url, doLockHistory));
1126 }
1127
1128 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture)
1129 {    
1130     // If the URL we're going to navigate to is the same as the current one, except for the
1131     // fragment part, we don't need to schedule the location change.
1132     KURL u(url.deprecatedString());
1133     if (u.hasRef() && equalIgnoringRef(m_URL, u)) {
1134         changeLocation(url, referrer, lockHistory, wasUserGesture);
1135         return;
1136     }
1137
1138     // Handle a location change of a page with no document as a special case.
1139     // This may happen when a frame changes the location of another frame.
1140     bool duringLoad = !m_frame->document();
1141
1142     // If a redirect was scheduled during a load, then stop the current load.
1143     // Otherwise when the current load transitions from a provisional to a 
1144     // committed state, pending redirects may be cancelled. 
1145     if (duringLoad)
1146         stopLoading(true);   
1147
1148     ScheduledRedirection::Type type = duringLoad
1149         ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1150     scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture));
1151 }
1152
1153 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1154 {
1155     // Handle a location change of a page with no document as a special case.
1156     // This may happen when a frame requests a refresh of another frame.
1157     bool duringLoad = !m_frame->document();
1158     
1159     // If a refresh was scheduled during a load, then stop the current load.
1160     // Otherwise when the current load transitions from a provisional to a 
1161     // committed state, pending redirects may be cancelled. 
1162     if (duringLoad)
1163         stopLoading(true);   
1164
1165     ScheduledRedirection::Type type = duringLoad
1166         ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1167     scheduleRedirection(new ScheduledRedirection(type, m_URL.url(), m_outgoingReferrer, true, wasUserGesture));
1168     m_cachePolicy = CachePolicyRefresh;
1169 }
1170
1171 bool FrameLoader::isScheduledLocationChangePending() const
1172 {
1173     if (!m_scheduledRedirection)
1174         return false;
1175     switch (m_scheduledRedirection->type) {
1176         case ScheduledRedirection::redirection:
1177             return false;
1178         case ScheduledRedirection::historyNavigation:
1179         case ScheduledRedirection::locationChange:
1180         case ScheduledRedirection::locationChangeDuringLoad:
1181             return true;
1182     }
1183     ASSERT_NOT_REACHED();
1184     return false;
1185 }
1186
1187 void FrameLoader::scheduleHistoryNavigation(int steps)
1188 {
1189     // navigation will always be allowed in the 0 steps case, which is OK because
1190     // that's supposed to force a reload.
1191     if (!canGoBackOrForward(steps)) {
1192         cancelRedirection();
1193         return;
1194     }
1195
1196     // If the URL we're going to navigate to is the same as the current one, except for the
1197     // fragment part, we don't need to schedule the navigation.
1198     if (equalIgnoringRef(m_URL, historyURL(steps))) {
1199         goBackOrForward(steps);
1200         return;
1201     }
1202     
1203     scheduleRedirection(new ScheduledRedirection(steps));
1204 }
1205
1206 void FrameLoader::goBackOrForward(int distance)
1207 {
1208     if (distance == 0)
1209         return;
1210         
1211     Page* page = m_frame->page();
1212     if (!page)
1213         return;
1214     BackForwardList* list = page->backForwardList();
1215     if (!list)
1216         return;
1217     
1218     HistoryItem* item = list->itemAtIndex(distance);
1219     if (!item) {
1220         if (distance > 0) {
1221             int forwardListCount = list->forwardListCount();
1222             if (forwardListCount > 0) 
1223                 item = list->itemAtIndex(forwardListCount);
1224         } else {
1225             int backListCount = list->forwardListCount();
1226             if (backListCount > 0)
1227                 item = list->itemAtIndex(-backListCount);
1228         }
1229     }
1230     if (item)
1231         page->goToItem(item, FrameLoadTypeIndexedBackForward);
1232 }
1233
1234 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1235 {
1236     OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1237
1238     switch (redirection->type) {
1239         case ScheduledRedirection::redirection:
1240         case ScheduledRedirection::locationChange:
1241         case ScheduledRedirection::locationChangeDuringLoad:
1242             changeLocation(redirection->URL, redirection->referrer,
1243                 redirection->lockHistory, redirection->wasUserGesture);
1244             return;
1245         case ScheduledRedirection::historyNavigation:
1246             if (redirection->historySteps == 0) {
1247                 // Special case for go(0) from a frame -> reload only the frame
1248                 urlSelected(m_URL, "", 0);
1249                 return;
1250             }
1251             // go(i!=0) from a frame navigates into the history of the frame only,
1252             // in both IE and NS (but not in Mozilla). We can't easily do that.
1253             goBackOrForward(redirection->historySteps);
1254             return;
1255     }
1256     ASSERT_NOT_REACHED();
1257 }
1258
1259 String FrameLoader::encoding() const
1260 {
1261     if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1262         return m_encoding;
1263     if (m_decoder && m_decoder->encoding().isValid())
1264         return m_decoder->encoding().name();
1265     return m_frame->settings()->defaultTextEncodingName();
1266 }
1267
1268 bool FrameLoader::gotoAnchor(const String& name)
1269 {
1270     if (!m_frame->document())
1271         return false;
1272
1273     Node* anchorNode = m_frame->document()->getElementById(AtomicString(name));
1274     if (!anchorNode)
1275         anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode());
1276
1277     m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1278   
1279     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1280     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1281         return false;
1282
1283     // We need to update the layout before scrolling, otherwise we could
1284     // really mess things up if an anchor scroll comes at a bad moment.
1285     if (m_frame->document()) {
1286         m_frame->document()->updateRendering();
1287         // Only do a layout if changes have occurred that make it necessary.      
1288         if (m_frame->view() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout())
1289             m_frame->view()->layout();
1290     }
1291   
1292     // Scroll nested layers and frames to reveal the anchor.
1293     // Align to the top and to the closest side (this matches other browsers).
1294     RenderObject* renderer;
1295     IntRect rect;
1296     if (!anchorNode)
1297         renderer = m_frame->document()->renderer(); // top of document
1298     else {
1299         renderer = anchorNode->renderer();
1300         rect = anchorNode->getRect();
1301     }
1302     if (renderer)
1303         renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1304
1305     return true;
1306 }
1307
1308 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1309     const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1310 {
1311     if (url.isEmpty() && mimeType.isEmpty())
1312         return true;
1313
1314     KURL completedURL;
1315     if (!url.isEmpty())
1316         completedURL = completeURL(url);
1317
1318     bool useFallback;
1319     if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1320         if (!m_frame->settings()->arePluginsEnabled())
1321             return false;
1322         return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1323     }
1324
1325     ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1326     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1327
1328     AtomicString uniqueFrameName = m_frame->tree()->uniqueChildName(frameName);
1329     element->setFrameName(uniqueFrameName);
1330     
1331     // FIXME: OK to always make a new frame? When does the old frame get removed?
1332     return loadSubframe(element, completedURL, uniqueFrameName, m_outgoingReferrer);
1333 }
1334
1335 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1336 {
1337     ObjectContentType objectType = objectContentType(url, mimeType);
1338     // If an object's content can't be handled and it has no fallback, let
1339     // it be handled as a plugin to show the broken plugin icon.
1340     useFallback = objectType == ObjectContentNone && hasFallback;
1341     return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1342 }
1343
1344 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType, 
1345     const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1346 {
1347     Widget* widget = 0;
1348
1349     if (renderer && !useFallback) {
1350         Element* pluginElement = 0;
1351         if (renderer->node() && renderer->node()->isElementNode())
1352             pluginElement = static_cast<Element*>(renderer->node());
1353
1354         widget = createPlugin(pluginElement, url, paramNames, paramValues, mimeType);
1355         if (widget) {
1356             renderer->setWidget(widget);
1357             m_containsPlugIns = true;
1358         }
1359     }
1360
1361     checkEmitLoadEvent();
1362     return widget != 0;
1363 }
1364
1365 void FrameLoader::clearRecordedFormValues()
1366 {
1367     m_formAboutToBeSubmitted = 0;
1368     m_formValuesAboutToBeSubmitted.clear();
1369 }
1370
1371 void FrameLoader::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1372 {
1373     m_formAboutToBeSubmitted = element;
1374     m_formValuesAboutToBeSubmitted.set(name, value);
1375 }
1376
1377 void FrameLoader::parentCompleted()
1378 {
1379     if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1380         startRedirectionTimer();
1381 }
1382
1383 String FrameLoader::outgoingReferrer() const
1384 {
1385     return m_outgoingReferrer;
1386 }
1387
1388 String FrameLoader::lastModified() const
1389 {
1390     return m_responseModifiedHeader;
1391 }
1392
1393 Frame* FrameLoader::opener()
1394 {
1395     return m_opener;
1396 }
1397
1398 void FrameLoader::setOpener(Frame* opener)
1399 {
1400     if (m_opener)
1401         m_opener->loader()->m_openedFrames.remove(m_frame);
1402     if (opener)
1403         opener->loader()->m_openedFrames.add(m_frame);
1404     m_opener = opener;
1405 }
1406
1407 bool FrameLoader::openedByJavaScript()
1408 {
1409     return m_openedByJavaScript;
1410 }
1411
1412 void FrameLoader::setOpenedByJavaScript()
1413 {
1414     m_openedByJavaScript = true;
1415 }
1416
1417 void FrameLoader::handleFallbackContent()
1418 {
1419     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1420     if (!owner || !owner->hasTagName(objectTag))
1421         return;
1422     static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1423 }
1424
1425 void FrameLoader::provisionalLoadStarted()
1426 {
1427     m_firstLayoutDone = false;
1428     cancelRedirection(true);
1429     FrameLoadType loadType = this->loadType();
1430     m_client->provisionalLoadStarted();
1431
1432     // Cache the page, if possible.
1433     // Don't write to the cache if in the middle of a redirect, since we will want to
1434     // store the final page we end up on.
1435     // No point writing to the cache on a reload or loadSame, since we will just write
1436     // over it again when we leave that page.
1437     // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1438     // are the most interesting pages on the web, and often those that would benefit the most from caching!
1439     if (m_frame->page() && m_frame->page()->backForwardList()->usesPageCache() 
1440         && canCachePage()
1441         && m_currentHistoryItem
1442         && !isQuickRedirectComing()
1443         && loadType != FrameLoadTypeReload 
1444         && loadType != FrameLoadTypeReloadAllowingStaleData
1445         && loadType != FrameLoadTypeSame
1446         && !documentLoader()->isLoading()
1447         && !documentLoader()->isStopping()) {
1448         
1449         if (!m_currentHistoryItem->pageCache()) {
1450             // Add the items to this page's cache.
1451             if (createPageCache(m_currentHistoryItem.get())) {
1452                 // See if any page caches need to be purged after the addition of this new page cache.
1453                 purgePageCache();
1454             }
1455         }
1456     }
1457 }
1458
1459 bool FrameLoader::userGestureHint()
1460 {
1461     Frame* rootFrame = m_frame;
1462     while (rootFrame->tree()->parent())
1463         rootFrame = rootFrame->tree()->parent();
1464
1465     if (rootFrame->scriptProxy())
1466         return rootFrame->scriptProxy()->interpreter()->wasRunByUserGesture();
1467
1468     return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
1469 }
1470
1471 #ifdef MULTIPLE_FORM_SUBMISSION_PROTECTION
1472 void FrameLoader::didNotOpenURL(const KURL& URL)
1473 {
1474     if (m_submittedFormURL == URL)
1475         m_submittedFormURL = KURL();
1476 }
1477
1478 void FrameLoader::resetMultipleFormSubmissionProtection()
1479 {
1480     m_submittedFormURL = KURL();
1481 }
1482 #endif
1483
1484 void FrameLoader::setEncoding(const String& name, bool userChosen)
1485 {
1486     if (!m_workingURL.isEmpty())
1487         receivedFirstData();
1488     m_encoding = name;
1489     m_encodingWasChosenByUser = userChosen;
1490 }
1491
1492 void FrameLoader::addData(const char* bytes, int length)
1493 {
1494     ASSERT(m_workingURL.isEmpty());
1495     ASSERT(m_frame->document());
1496     ASSERT(m_frame->document()->parsing());
1497     write(bytes, length);
1498 }
1499
1500 bool FrameLoader::canCachePage()
1501 {
1502     if (!m_client->canCachePage())
1503         return false;
1504         
1505     return m_frame->document()
1506         && !m_frame->tree()->childCount()
1507         && !m_frame->tree()->parent()
1508         && !m_containsPlugIns
1509         && !m_URL.protocol().startsWith("https")
1510         && !m_frame->document()->applets()->length()
1511         && !m_frame->document()->hasWindowEventListener(unloadEvent)
1512         && !m_frame->document()->hasPasswordField();
1513 }
1514
1515 void FrameLoader::updatePolicyBaseURL()
1516 {
1517     if (m_frame->tree()->parent() && m_frame->tree()->parent()->document())
1518         setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
1519     else
1520         setPolicyBaseURL(m_URL.url());
1521 }
1522
1523 void FrameLoader::setPolicyBaseURL(const String& s)
1524 {
1525     if (m_frame->document())
1526         m_frame->document()->setPolicyBaseURL(s);
1527     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1528         child->loader()->setPolicyBaseURL(s);
1529 }
1530
1531 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
1532 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1533 void FrameLoader::scrollToAnchor(const KURL& URL)
1534 {
1535     m_URL = URL;
1536     started();
1537
1538     gotoAnchor();
1539
1540     // It's important to model this as a load that starts and immediately finishes.
1541     // Otherwise, the parent frame may think we never finished loading.
1542     m_isComplete = false;
1543     checkCompleted();
1544 }
1545
1546 bool FrameLoader::isComplete() const
1547 {
1548     return m_isComplete;
1549 }
1550
1551 bool FrameLoader::isLoadingMainResource() const
1552 {
1553     return m_isLoadingMainResource;
1554 }
1555
1556 KURL FrameLoader::url() const
1557 {
1558     return m_URL;
1559 }
1560
1561 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
1562 {
1563     stopRedirectionTimer();
1564     m_scheduledRedirection.set(redirection);
1565     if (m_isComplete)
1566         startRedirectionTimer();
1567 }
1568
1569 void FrameLoader::startRedirectionTimer()
1570 {
1571     ASSERT(m_scheduledRedirection);
1572
1573     m_redirectionTimer.stop();
1574     m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
1575
1576     switch (m_scheduledRedirection->type) {
1577         case ScheduledRedirection::redirection:
1578         case ScheduledRedirection::locationChange:
1579         case ScheduledRedirection::locationChangeDuringLoad:
1580             clientRedirected(m_scheduledRedirection->URL.deprecatedString(),
1581                 m_scheduledRedirection->delay,
1582                 currentTime() + m_redirectionTimer.nextFireInterval(),
1583                 m_scheduledRedirection->lockHistory,
1584                 m_isExecutingJavaScriptFormAction);
1585             return;
1586         case ScheduledRedirection::historyNavigation:
1587             // Don't report history navigations.
1588             return;
1589     }
1590     ASSERT_NOT_REACHED();
1591 }
1592
1593 void FrameLoader::stopRedirectionTimer()
1594 {
1595     if (!m_redirectionTimer.isActive())
1596         return;
1597
1598     m_redirectionTimer.stop();
1599
1600     if (m_scheduledRedirection) {
1601         switch (m_scheduledRedirection->type) {
1602             case ScheduledRedirection::redirection:
1603             case ScheduledRedirection::locationChange:
1604             case ScheduledRedirection::locationChangeDuringLoad:
1605                 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
1606                 return;
1607             case ScheduledRedirection::historyNavigation:
1608                 // Don't report history navigations.
1609                 return;
1610         }
1611         ASSERT_NOT_REACHED();
1612     }
1613 }
1614
1615 void FrameLoader::updateBaseURLForEmptyDocument()
1616 {
1617     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1618     // FIXME: Should embed be included?
1619     if (owner && (owner->hasTagName(iframeTag) || owner->hasTagName(objectTag) || owner->hasTagName(embedTag)))
1620         m_frame->document()->setBaseURL(m_frame->tree()->parent()->document()->baseURL());
1621 }
1622
1623 void FrameLoader::completed()
1624 {
1625     RefPtr<Frame> protect(m_frame);
1626     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1627         child->loader()->parentCompleted();
1628     if (Frame* parent = m_frame->tree()->parent())
1629         parent->loader()->checkCompleted();
1630     submitFormAgain();
1631 }
1632
1633 void FrameLoader::started()
1634 {
1635     for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1636         frame->loader()->m_isComplete = false;
1637 }
1638
1639 bool FrameLoader::containsPlugins() const 
1640
1641     return m_containsPlugIns;
1642 }
1643
1644 void FrameLoader::prepareForLoadStart()
1645 {
1646     if (m_frame->page())
1647         m_frame->page()->progress()->progressStarted(m_frame);
1648     m_client->dispatchDidStartProvisionalLoad();
1649 }
1650
1651 void FrameLoader::setupForReplace()
1652 {
1653     setState(FrameStateProvisional);
1654     m_provisionalDocumentLoader = m_documentLoader;
1655     m_documentLoader = 0;
1656     detachChildren();
1657 }
1658
1659 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
1660 {
1661     activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
1662 }
1663
1664 void FrameLoader::finalSetupForReplace(DocumentLoader* loader)
1665 {
1666     m_client->clearUnarchivingState(loader);
1667 }
1668
1669 void FrameLoader::load(const KURL& URL, Event* event)
1670 {
1671     load(ResourceRequest(URL), true, event, 0, HashMap<String, String>());
1672 }
1673
1674 void FrameLoader::load(const FrameLoadRequest& request, bool userGesture, Event* event,
1675     HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
1676 {
1677     String referrer;
1678     String argsReferrer = request.resourceRequest().httpReferrer();
1679     if (!argsReferrer.isEmpty())
1680         referrer = argsReferrer;
1681     else
1682         referrer = m_outgoingReferrer;
1683  
1684     bool hideReferrer;
1685     if (!canLoad(request.resourceRequest().url(), referrer, hideReferrer))
1686         return;
1687     if (hideReferrer)
1688         referrer = String();
1689     
1690     Frame* targetFrame = m_frame->tree()->find(request.frameName());
1691     if (!canTarget(targetFrame))
1692         return;
1693         
1694     if (request.resourceRequest().httpMethod() != "POST") {
1695         FrameLoadType loadType;
1696         if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1697             loadType = FrameLoadTypeReload;
1698         else if (!userGesture)
1699             loadType = FrameLoadTypeInternal;
1700         else
1701             loadType = FrameLoadTypeStandard;    
1702     
1703         load(request.resourceRequest().url(), referrer, loadType, 
1704             request.frameName(), event, submitForm, formValues);
1705     } else
1706         post(request.resourceRequest().url(), referrer, request.frameName(), 
1707             request.resourceRequest().httpBody(), request.resourceRequest().httpContentType(), event, submitForm, formValues);
1708
1709     if (targetFrame && targetFrame != m_frame)
1710         targetFrame->page()->chrome()->focus();
1711 }
1712
1713 void FrameLoader::load(const KURL& URL, const String& referrer, FrameLoadType newLoadType,
1714     const String& frameName, Event* event, HTMLFormElement* form, const HashMap<String, String>& values)
1715 {
1716     bool isFormSubmission = !values.isEmpty();
1717     
1718     ResourceRequest request(URL);
1719     if (!referrer.isEmpty())
1720         request.setHTTPReferrer(referrer);
1721     addExtraFieldsToRequest(request, true, event || isFormSubmission);
1722     if (newLoadType == FrameLoadTypeReload)
1723         request.setCachePolicy(ReloadIgnoringCacheData);
1724
1725     ASSERT(newLoadType != FrameLoadTypeSame);
1726
1727     NavigationAction action(URL, newLoadType, isFormSubmission, event);
1728
1729     RefPtr<FormState> formState;
1730     if (form && !values.isEmpty())
1731         formState = FormState::create(form, values, m_frame);
1732     
1733     if (!frameName.isEmpty()) {
1734         if (Frame* targetFrame = m_frame->tree()->find(frameName))
1735             targetFrame->loader()->load(URL, referrer, newLoadType, String(), event, form, values);
1736         else
1737             checkNewWindowPolicy(action, request, formState.release(), frameName);
1738         return;
1739     }
1740
1741     RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1742
1743     bool sameURL = shouldTreatURLAsSameAsCurrent(URL);
1744     
1745     // Make sure to do scroll to anchor processing even if the URL is
1746     // exactly the same so pages with '#' links and DHTML side effects
1747     // work properly.
1748     if (!isFormSubmission
1749         && newLoadType != FrameLoadTypeReload
1750         && newLoadType != FrameLoadTypeSame
1751         && !shouldReload(URL, url())
1752         // We don't want to just scroll if a link from within a
1753         // frameset is trying to reload the frameset into _top.
1754         && !m_frame->isFrameSet()) {
1755
1756         // Just do anchor navigation within the existing content.
1757         
1758         // We don't do this if we are submitting a form, explicitly reloading,
1759         // currently displaying a frameset, or if the new URL does not have a fragment.
1760         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
1761         
1762         // FIXME: What about load types other than Standard and Reload?
1763         
1764         oldDocumentLoader->setTriggeringAction(action);
1765         stopPolicyCheck();
1766         checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
1767             callContinueFragmentScrollAfterNavigationPolicy, this);
1768     } else {
1769         // must grab this now, since this load may stop the previous load and clear this flag
1770         bool isRedirect = m_quickRedirectComing;
1771         load(request, action, newLoadType, formState.release());
1772         if (isRedirect) {
1773             m_quickRedirectComing = false;
1774             if (m_provisionalDocumentLoader)
1775                 m_provisionalDocumentLoader->setIsClientRedirect(true);
1776         } else if (sameURL)
1777             // Example of this case are sites that reload the same URL with a different cookie
1778             // driving the generated content, or a master frame with links that drive a target
1779             // frame, where the user has clicked on the same link repeatedly.
1780             m_loadType = FrameLoadTypeSame;
1781     }
1782 }
1783
1784 void FrameLoader::load(const ResourceRequest& request)
1785 {
1786     // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
1787     m_loadType = FrameLoadTypeStandard;
1788     load(m_client->createDocumentLoader(request).get());
1789 }
1790
1791 void FrameLoader::load(const ResourceRequest& request, const String& frameName)
1792 {
1793     if (frameName.isEmpty()) {
1794         load(request);
1795         return;
1796     }
1797
1798     Frame* frame = m_frame->tree()->find(frameName);
1799     if (frame) {
1800         frame->loader()->load(request);
1801         return;
1802     }
1803
1804     checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
1805 }
1806
1807 void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
1808 {
1809     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request);
1810     setPolicyDocumentLoader(loader.get());
1811
1812     loader->setTriggeringAction(action);
1813     if (m_documentLoader)
1814         loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1815
1816     load(loader.get(), type, formState);
1817 }
1818
1819 void FrameLoader::load(DocumentLoader* newDocumentLoader)
1820 {
1821     stopPolicyCheck();
1822     setPolicyDocumentLoader(newDocumentLoader);
1823
1824     ResourceRequest& r = newDocumentLoader->request();
1825     addExtraFieldsToRequest(r, true, false);
1826     FrameLoadType type;
1827
1828     if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
1829         r.setCachePolicy(ReloadIgnoringCacheData);
1830         type = FrameLoadTypeSame;
1831     } else
1832         type = FrameLoadTypeStandard;
1833
1834     if (m_documentLoader)
1835         newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
1836     
1837     // When we loading alternate content for an unreachable URL that we're
1838     // visiting in the b/f list, we treat it as a reload so the b/f list 
1839     // is appropriately maintained.
1840     if (shouldReloadToHandleUnreachableURL(newDocumentLoader->originalRequest())) {
1841         ASSERT(type == FrameLoadTypeStandard);
1842         type = FrameLoadTypeReload;
1843     }
1844
1845     load(newDocumentLoader, type, 0);
1846 }
1847
1848 void FrameLoader::load(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> formState)
1849 {
1850     ASSERT(m_client->hasWebView());
1851
1852     // Unfortunately the view must be non-nil, this is ultimately due
1853     // to parser requiring a FrameView.  We should fix this dependency.
1854
1855     ASSERT(m_client->hasFrameView());
1856
1857     m_policyLoadType = type;
1858
1859     if (Frame* parent = m_frame->tree()->parent())
1860         loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
1861
1862     stopPolicyCheck();
1863     setPolicyDocumentLoader(loader);
1864
1865     checkNavigationPolicy(loader->request(), loader, formState,
1866         callContinueLoadAfterNavigationPolicy, this);
1867 }
1868
1869 bool FrameLoader::canLoad(const KURL& url, const String& referrer, bool& hideReferrer)
1870 {
1871     bool referrerIsWebURL = referrer.startsWith("http:", false) || referrer.startsWith("https:", false);
1872     bool referrerIsLocalURL = referrer.startsWith("file:", false) || referrer.startsWith("applewebdata:");
1873     bool URLIsFileURL = url.protocol().startsWith("file", false);
1874     bool referrerIsSecureURL = referrer.startsWith("https:", false);
1875     bool URLIsSecureURL = url.protocol().startsWith("https", false);
1876     
1877     hideReferrer = !referrerIsWebURL || (referrerIsSecureURL && !URLIsSecureURL);
1878     return !URLIsFileURL || referrerIsLocalURL;
1879 }
1880
1881 const ResourceRequest& FrameLoader::initialRequest() const
1882 {
1883     return activeDocumentLoader()->initialRequest();
1884 }
1885
1886 void FrameLoader::receivedData(const char* data, int length)
1887 {
1888     activeDocumentLoader()->receivedData(data, length);
1889 }
1890
1891 void FrameLoader::setRequest(const ResourceRequest& request)
1892 {
1893     activeDocumentLoader()->setRequest(request);
1894 }
1895
1896 void FrameLoader::setResponse(const ResourceResponse& response)
1897 {
1898     activeDocumentLoader()->setResponse(response);
1899 }
1900
1901 bool FrameLoader::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
1902 {
1903     return m_client->willUseArchive(loader, request, originalURL);
1904 }
1905
1906 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
1907 {
1908     m_delegateIsHandlingUnimplementablePolicy = true;
1909     m_client->dispatchUnableToImplementPolicy(error);
1910     m_delegateIsHandlingUnimplementablePolicy = false;
1911 }
1912
1913 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
1914 {
1915     handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
1916 }
1917
1918 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
1919 {
1920     return m_client->interruptForPolicyChangeError(request);
1921 }
1922
1923 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
1924 {
1925     checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
1926 }
1927
1928 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
1929 {
1930     m_policyCheck.set(function, argument);
1931     m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
1932         MIMEType, activeDocumentLoader()->request());
1933 }
1934
1935 bool FrameLoader::shouldReloadToHandleUnreachableURL(const ResourceRequest& request)
1936 {
1937     KURL unreachableURL;
1938 #if PLATFORM(MAC)
1939     unreachableURL = [request.nsURLRequest() _webDataRequestUnreachableURL];
1940 #endif
1941
1942     if (unreachableURL.isEmpty())
1943         return false;
1944
1945     if (!isBackForwardLoadType(m_policyLoadType))
1946         return false;
1947
1948     // We only treat unreachableURLs specially during the delegate callbacks
1949     // for provisional load errors and navigation policy decisions. The former
1950     // case handles well-formed URLs that can't be loaded, and the latter
1951     // case handles malformed URLs and unknown schemes. Loading alternate content
1952     // at other times behaves like a standard load.
1953     DocumentLoader* compareDocumentLoader = 0;
1954     if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
1955         compareDocumentLoader = m_policyDocumentLoader.get();
1956     else if (m_delegateIsHandlingProvisionalLoadError)
1957         compareDocumentLoader = m_provisionalDocumentLoader.get();
1958
1959     return compareDocumentLoader && unreachableURL != compareDocumentLoader->request().url();
1960 }
1961
1962 void FrameLoader::reloadAllowingStaleData(const String& encoding)
1963 {
1964     if (!m_documentLoader)
1965         return;
1966
1967     ResourceRequest request = m_documentLoader->request();
1968     KURL unreachableURL = m_documentLoader->unreachableURL();
1969     if (!unreachableURL.isEmpty())
1970         request.setURL(unreachableURL);
1971
1972     request.setCachePolicy(ReturnCacheDataElseLoad);
1973
1974     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request);
1975     setPolicyDocumentLoader(loader.get());
1976
1977     loader->setOverrideEncoding(encoding);
1978
1979     load(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0);
1980 }
1981
1982 void FrameLoader::reload()
1983 {
1984     if (!m_documentLoader)
1985         return;
1986
1987     ResourceRequest& initialRequest = m_documentLoader->request();
1988     
1989     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1990     // Reloading in this case will lose the current contents (see 4151001).
1991     if (initialRequest.url().isEmpty())
1992         return;
1993
1994     // Replace error-page URL with the URL we were trying to reach.
1995     KURL unreachableURL;
1996 #if PLATFORM(MAC)
1997     unreachableURL = [initialRequest.nsURLRequest() _webDataRequestUnreachableURL];
1998 #endif
1999     if (!unreachableURL.isEmpty())
2000         initialRequest = ResourceRequest(unreachableURL);
2001     
2002     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest);
2003     setPolicyDocumentLoader(loader.get());
2004
2005     ResourceRequest& request = loader->request();
2006
2007     request.setCachePolicy(ReloadIgnoringCacheData);
2008
2009     // If we're about to re-post, set up action so the application can warn the user.
2010     if (request.httpMethod() == "POST")
2011         loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2012
2013     loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2014     
2015     load(loader.get(), FrameLoadTypeReload, 0);
2016 }
2017
2018 bool FrameLoader::canTarget(Frame* target) const
2019 {
2020     // This method prevents this exploit:
2021     // <rdar://problem/3715785> multiple frame injection vulnerability reported by Secunia, affects almost all browsers
2022
2023     if (!target)
2024         return true;
2025
2026     // Allow with navigation within the same page/frameset.
2027     if (m_frame->page() == target->page())
2028         return true;
2029
2030     String domain;
2031     if (Document* document = m_frame->document())
2032         domain = document->domain();
2033     // Allow if the request is made from a local file.
2034     if (domain.isEmpty())
2035         return true;
2036     
2037     Frame* parent = target->tree()->parent();
2038     // Allow if target is an entire window.
2039     if (!parent)
2040         return true;
2041     
2042     String parentDomain;
2043     if (Document* parentDocument = parent->document())
2044         domain = parentDocument->domain();
2045     // Allow if the domain of the parent of the targeted frame equals this domain.
2046     return equalIgnoringCase(parentDomain, domain);
2047 }
2048
2049 void FrameLoader::stopLoadingPlugIns()
2050 {
2051     cancelAll(m_plugInStreamLoaders);
2052 }
2053
2054 void FrameLoader::stopLoadingSubresources()
2055 {
2056     cancelAll(m_subresourceLoaders);
2057 }
2058
2059 void FrameLoader::stopLoadingSubframes()
2060 {
2061     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2062         child->loader()->stopAllLoaders();
2063 }
2064
2065 void FrameLoader::stopAllLoaders()
2066 {
2067     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2068     if (m_inStopAllLoaders)
2069         return;
2070
2071     m_inStopAllLoaders = true;
2072
2073     stopPolicyCheck();
2074
2075     stopLoadingSubframes();
2076     if (m_provisionalDocumentLoader)
2077         m_provisionalDocumentLoader->stopLoading();
2078     if (m_documentLoader)
2079         m_documentLoader->stopLoading();
2080     setProvisionalDocumentLoader(0);
2081     m_client->clearArchivedResources();
2082
2083     m_inStopAllLoaders = false;    
2084 }
2085
2086 void FrameLoader::cancelMainResourceLoad()
2087 {
2088     if (m_mainResourceLoader)
2089         m_mainResourceLoader->cancel();
2090 }
2091
2092 void FrameLoader::cancelPendingArchiveLoad(ResourceLoader* loader)
2093 {
2094     m_client->cancelPendingArchiveLoad(loader);
2095 }
2096
2097 DocumentLoader* FrameLoader::activeDocumentLoader() const
2098 {
2099     if (m_state == FrameStateProvisional)
2100         return m_provisionalDocumentLoader.get();
2101     return m_documentLoader.get();
2102 }
2103
2104 void FrameLoader::addPlugInStreamLoader(ResourceLoader* loader)
2105 {
2106     m_plugInStreamLoaders.add(loader);
2107     activeDocumentLoader()->setLoading(true);
2108 }
2109
2110 void FrameLoader::removePlugInStreamLoader(ResourceLoader* loader)
2111 {
2112     m_plugInStreamLoaders.remove(loader);
2113     activeDocumentLoader()->updateLoading();
2114 }
2115
2116 bool FrameLoader::hasMainResourceLoader() const
2117 {
2118     return m_mainResourceLoader != 0;
2119 }
2120
2121 bool FrameLoader::isLoadingSubresources() const
2122 {
2123     return !m_subresourceLoaders.isEmpty();
2124 }
2125
2126 bool FrameLoader::isLoadingPlugIns() const
2127 {
2128     return !m_plugInStreamLoaders.isEmpty();
2129 }
2130
2131 bool FrameLoader::isLoading() const
2132 {
2133     return isLoadingMainResource() || isLoadingSubresources() || isLoadingPlugIns();
2134 }
2135
2136 void FrameLoader::addSubresourceLoader(ResourceLoader* loader)
2137 {
2138     ASSERT(!m_provisionalDocumentLoader);
2139     m_subresourceLoaders.add(loader);
2140     activeDocumentLoader()->setLoading(true);
2141 }
2142
2143 void FrameLoader::removeSubresourceLoader(ResourceLoader* loader)
2144 {
2145     m_subresourceLoaders.remove(loader);
2146     activeDocumentLoader()->updateLoading();
2147     checkLoadComplete();
2148 }
2149
2150 void FrameLoader::releaseMainResourceLoader()
2151 {
2152     m_mainResourceLoader = 0;
2153 }
2154
2155 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2156 {
2157     if (!loader && !m_documentLoader)
2158         return;
2159     
2160     ASSERT(loader != m_documentLoader);
2161     ASSERT(!loader || loader->frameLoader() == this);
2162
2163     m_client->prepareForDataSourceReplacement();
2164     if (m_documentLoader)
2165         m_documentLoader->detachFromFrame();
2166
2167     m_documentLoader = loader;
2168 }
2169
2170 DocumentLoader* FrameLoader::documentLoader() const
2171 {
2172     return m_documentLoader.get();
2173 }
2174
2175 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2176 {
2177     if (m_policyDocumentLoader == loader)
2178         return;
2179
2180     ASSERT(m_frame);
2181     if (loader)
2182         loader->setFrame(m_frame);
2183     if (m_policyDocumentLoader
2184             && m_policyDocumentLoader != m_provisionalDocumentLoader
2185             && m_policyDocumentLoader != m_documentLoader)
2186         m_policyDocumentLoader->detachFromFrame();
2187
2188     m_policyDocumentLoader = loader;
2189 }
2190    
2191 DocumentLoader* FrameLoader::provisionalDocumentLoader()
2192 {
2193     return m_provisionalDocumentLoader.get();
2194 }
2195
2196 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2197 {
2198     ASSERT(!loader || !m_provisionalDocumentLoader);
2199     ASSERT(!loader || loader->frameLoader() == this);
2200
2201     if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2202         m_provisionalDocumentLoader->detachFromFrame();
2203
2204     m_provisionalDocumentLoader = loader;
2205 }
2206
2207 FrameState FrameLoader::state() const
2208 {
2209     return m_state;
2210 }
2211
2212 double FrameLoader::timeOfLastCompletedLoad()
2213 {
2214     return storedTimeOfLastCompletedLoad;
2215 }
2216
2217 void FrameLoader::setState(FrameState newState)
2218 {    
2219     m_state = newState;
2220     
2221     if (newState == FrameStateProvisional)
2222         provisionalLoadStarted();
2223     else if (newState == FrameStateComplete) {
2224         frameLoadCompleted();
2225         storedTimeOfLastCompletedLoad = currentTime();
2226         if (m_documentLoader)
2227             m_documentLoader->stopRecordingResponses();
2228     }
2229 }
2230
2231 void FrameLoader::clearProvisionalLoad()
2232 {
2233     setProvisionalDocumentLoader(0);
2234     if (m_frame->page())
2235         m_frame->page()->progress()->progressCompleted(m_frame);
2236     setState(FrameStateComplete);
2237 }
2238
2239 void FrameLoader::markLoadComplete()
2240 {
2241     setState(FrameStateComplete);
2242 }
2243
2244 void FrameLoader::commitProvisionalLoad()
2245 {
2246     stopLoadingSubresources();
2247     stopLoadingPlugIns();
2248
2249     setDocumentLoader(m_provisionalDocumentLoader.get());
2250     setProvisionalDocumentLoader(0);
2251     setState(FrameStateCommittedPage);
2252 }
2253
2254 void FrameLoader::commitProvisionalLoad(PassRefPtr<PageCache> prpPageCache)
2255 {
2256     RefPtr<PageCache> pageCache = prpPageCache;
2257     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2258     
2259     if (m_loadType != FrameLoadTypeReplace)
2260         closeOldDataSources();
2261     
2262     if (!pageCache)
2263         m_client->makeRepresentation(pdl.get());
2264     
2265     transitionToCommitted(pageCache);
2266     
2267     // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
2268     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
2269     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
2270     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2271     if (m_sentRedirectNotification)
2272         clientRedirectCancelledOrFinished(false);
2273     
2274     RefPtr<PageState> pageState;
2275     if (pageCache)
2276         pageState = pageCache->pageState();
2277     if (pageState) {
2278         open(*pageState);
2279         pageState->clear();
2280     } else {        
2281         KURL url = pdl->URL();
2282         KURL dataURLBase = dataURLBaseFromRequest(pdl->request());
2283         if (!dataURLBase.isEmpty())
2284             url = dataURLBase;
2285             
2286         if (url.isEmpty())
2287             url = pdl->responseURL();
2288         if (url.isEmpty())
2289             url = "about:blank";
2290
2291         m_responseMIMEType = pdl->responseMIMEType();
2292
2293         if (didOpenURL(url)) {
2294             m_responseRefreshHeader = pdl->response().httpHeaderField("Refresh");
2295             if (!pdl->getResponseModifiedHeader(m_responseModifiedHeader))
2296                 m_responseModifiedHeader = "";
2297         }
2298     }
2299     opened();
2300 }
2301
2302 void FrameLoader::transitionToCommitted(PassRefPtr<PageCache> pageCache)
2303 {
2304     ASSERT(m_client->hasWebView());
2305     ASSERT(m_state == FrameStateProvisional);
2306
2307     if (m_state != FrameStateProvisional)
2308         return;
2309
2310     m_client->setCopiesOnScroll();
2311     updateHistoryForCommit();
2312
2313     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2314     // JavaScript. If the script initiates a new load, we need to abandon the current load,
2315     // or the two will stomp each other.
2316     DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2317     closeURL();
2318     if (pdl != m_provisionalDocumentLoader)
2319         return;
2320
2321     commitProvisionalLoad();
2322
2323     // Handle adding the URL to the back/forward list.
2324     DocumentLoader* dl = m_documentLoader.get();
2325     String ptitle = dl->title();
2326
2327     switch (m_loadType) {
2328         case FrameLoadTypeForward:
2329         case FrameLoadTypeBack:
2330         case FrameLoadTypeIndexedBackForward:
2331             if (m_frame->page()->backForwardList()) {
2332                 updateHistoryForBackForwardNavigation();
2333
2334                 // Create a document view for this document, or used the cached view.
2335                 if (pageCache)
2336                     m_client->setDocumentViewFromPageCache(pageCache.get());
2337                 else
2338                     m_client->makeDocumentView();
2339             }
2340             break;
2341
2342         case FrameLoadTypeReload:
2343         case FrameLoadTypeSame:
2344         case FrameLoadTypeReplace:
2345             updateHistoryForReload();
2346             m_client->makeDocumentView();
2347             break;
2348
2349         // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
2350         case FrameLoadTypeReloadAllowingStaleData:
2351             m_client->makeDocumentView();
2352             break;
2353
2354         case FrameLoadTypeStandard:
2355             updateHistoryForStandardLoad();
2356             m_client->makeDocumentView();
2357             break;
2358
2359         case FrameLoadTypeInternal:
2360             updateHistoryForInternalLoad();
2361             m_client->makeDocumentView();
2362             break;
2363
2364         // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2365         // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2366         default:
2367             ASSERT_NOT_REACHED();
2368     }
2369
2370     // Tell the client we've committed this URL.
2371     ASSERT(m_client->hasFrameView());
2372     m_client->dispatchDidCommitLoad();
2373     
2374     // If we have a title let the WebView know about it.
2375     if (!ptitle.isNull())
2376         m_client->dispatchDidReceiveTitle(ptitle);
2377 }
2378
2379 bool FrameLoader::privateBrowsingEnabled() const
2380 {
2381     return m_client->privateBrowsingEnabled();
2382 }
2383
2384 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2385 {
2386     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2387     // the redirect succeeded.  We should either rename this API, or add a new method, like
2388     // -webView:didFinishClientRedirectForFrame:
2389     m_client->dispatchDidCancelClientRedirect();
2390
2391     if (!cancelWithLoadInProgress)
2392         m_quickRedirectComing = false;
2393
2394     m_sentRedirectNotification = false;
2395 }
2396
2397 void FrameLoader::clientRedirected(const KURL& URL, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction)
2398 {
2399     m_client->dispatchWillPerformClientRedirect(URL, seconds, fireDate);
2400     
2401     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2402     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2403     m_sentRedirectNotification = true;
2404     
2405     // If a "quick" redirect comes in an, we set a special mode so we treat the next
2406     // load as part of the same navigation. If we don't have a document loader, we have
2407     // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2408     m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction;
2409 }
2410
2411 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2412 {
2413     // This function implements the rule: "Don't reload if navigating by fragment within
2414     // the same URL, but do reload if going to a new URL or to the same URL with no
2415     // fragment identifier at all."
2416     if (!currentURL.hasRef() && !destinationURL.hasRef())
2417         return true;
2418     return !equalIgnoringRef(currentURL, destinationURL);
2419 }
2420
2421 void FrameLoader::closeOldDataSources()
2422 {
2423     // FIXME: Is it important for this traversal to be postorder instead of preorder?
2424     // If so, add helpers for postorder traversal, and use them. If not, then lets not
2425     // use a recursive algorithm here.
2426     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2427         child->loader()->closeOldDataSources();
2428     
2429     if (m_documentLoader)
2430         m_client->dispatchWillClose();
2431
2432     m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2433 }
2434
2435 void FrameLoader::open(PageState& state)
2436 {
2437     ASSERT(m_frame->page()->mainFrame() == m_frame);
2438
2439     cancelRedirection();
2440
2441     // We still have to close the previous part page.
2442     closeURL();
2443
2444     m_isComplete = false;
2445     
2446     // Don't re-emit the load event.
2447     m_wasLoadEventEmitted = true;
2448     
2449     // Delete old status bar messages (if it _was_ activated on last URL).
2450     if (m_frame->settings()->isJavaScriptEnabled()) {
2451         m_frame->d->m_kjsStatusBarText = String();
2452         m_frame->d->m_kjsDefaultStatusBarText = String();
2453     }
2454
2455     KURL URL = state.URL();
2456
2457     if (URL.protocol().startsWith("http") && !URL.host().isEmpty() && URL.path().isEmpty())
2458         URL.setPath("/");
2459     
2460     m_URL = URL;
2461     m_workingURL = URL;
2462
2463     started();
2464
2465     clear();
2466
2467     Document* document = state.document();
2468     ASSERT(document);
2469     document->setInPageCache(false);
2470
2471     m_needsClear = true;
2472     m_isComplete = false;
2473     m_wasLoadEventEmitted = false;
2474     m_outgoingReferrer = URL.url();
2475     
2476     m_frame->setView(document->view());
2477     
2478     m_frame->d->m_doc = document;
2479     m_decoder = document->decoder();
2480
2481     updatePolicyBaseURL();
2482
2483     state.restore(m_frame->page());
2484
2485     checkCompleted();
2486 }
2487
2488 bool FrameLoader::isStopping() const
2489 {
2490     return activeDocumentLoader()->isStopping();
2491 }
2492
2493 void FrameLoader::finishedLoading()
2494 {
2495     // Retain because the stop may release the last reference to it.
2496     RefPtr<Frame> protect(m_frame);
2497
2498     RefPtr<DocumentLoader> dl = activeDocumentLoader();
2499     dl->finishedLoading();
2500     if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
2501         return;
2502     dl->setPrimaryLoadComplete(true);
2503     m_client->dispatchDidLoadMainResource(dl.get());
2504     checkLoadComplete();
2505 }
2506
2507 KURL FrameLoader::URL() const
2508 {
2509     return activeDocumentLoader()->URL();
2510 }
2511
2512 bool FrameLoader::isArchiveLoadPending(ResourceLoader* loader) const
2513 {
2514     return m_client->isArchiveLoadPending(loader);
2515 }
2516
2517 bool FrameLoader::isHostedByObjectElement() const
2518 {
2519     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2520     return owner && owner->hasTagName(objectTag);
2521 }
2522
2523 bool FrameLoader::isLoadingMainFrame() const
2524 {
2525     Page* page = m_frame->page();
2526     return page && m_frame == page->mainFrame();
2527 }
2528
2529 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
2530 {
2531     return m_client->canShowMIMEType(MIMEType);
2532 }
2533
2534 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
2535 {
2536     return m_client->representationExistsForURLScheme(URLScheme);
2537 }
2538
2539 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
2540 {
2541     return m_client->generatedMIMETypeForURLScheme(URLScheme);
2542 }
2543
2544 void FrameLoader::cancelContentPolicyCheck()
2545 {
2546     m_client->cancelPolicyCheck();
2547     m_policyCheck.clear();
2548 }
2549
2550 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
2551 {
2552     m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
2553 }
2554
2555 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
2556 {
2557     m_client->finishedLoading(loader);
2558 }
2559
2560 bool FrameLoader::isReplacing() const
2561 {
2562     return m_loadType == FrameLoadTypeReplace;
2563 }
2564
2565 void FrameLoader::setReplacing()
2566 {
2567     m_loadType = FrameLoadTypeReplace;
2568 }
2569
2570 void FrameLoader::revertToProvisional(DocumentLoader* loader)
2571 {
2572     m_client->revertToProvisionalState(loader);
2573 }
2574
2575 bool FrameLoader::subframeIsLoading() const
2576 {
2577     // It's most likely that the last added frame is the last to load so we walk backwards.
2578     for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2579         FrameLoader* childLoader = child->loader();
2580         DocumentLoader* documentLoader = childLoader->documentLoader();
2581         if (documentLoader && documentLoader->isLoadingInAPISense())
2582             return true;
2583         documentLoader = childLoader->provisionalDocumentLoader();
2584         if (documentLoader && documentLoader->isLoadingInAPISense())
2585             return true;
2586     }
2587     return false;
2588 }
2589
2590 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2591 {
2592     m_client->willChangeTitle(loader);
2593 }
2594
2595 FrameLoadType FrameLoader::loadType() const
2596 {
2597     return m_loadType;
2598 }
2599
2600 void FrameLoader::stopPolicyCheck()
2601 {
2602     m_client->cancelPolicyCheck();
2603     PolicyCheck check = m_policyCheck;
2604     m_policyCheck.clear();
2605     check.clearRequest();
2606     check.call(false);
2607 }
2608
2609 void FrameLoader::checkLoadCompleteForThisFrame()
2610 {
2611     ASSERT(m_client->hasWebView());
2612
2613     switch (m_state) {
2614         case FrameStateProvisional: {
2615             if (m_delegateIsHandlingProvisionalLoadError)
2616                 return;
2617
2618             RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2619             if (!pdl)
2620                 return;
2621                 
2622             // If we've received any errors we may be stuck in the provisional state and actually complete.
2623             const ResourceError& error = pdl->mainDocumentError();
2624             if (error.isNull())
2625                 return;
2626
2627             // Check all children first.
2628             RefPtr<HistoryItem> item;
2629             if (isBackForwardLoadType(loadType()) && m_frame == m_frame->page()->mainFrame())
2630                 item = m_currentHistoryItem;
2631                 
2632             bool shouldReset = true;
2633             if (!pdl->isLoadingInAPISense()) {
2634                 m_delegateIsHandlingProvisionalLoadError = true;
2635                 m_client->dispatchDidFailProvisionalLoad(error);
2636                 m_delegateIsHandlingProvisionalLoadError = false;
2637
2638                 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
2639                 // which it must be to be in this branch of the if? And is it OK to just do a full-on
2640                 // stopAllLoaders instead of stopLoadingSubframes?
2641                 stopLoadingSubframes();
2642                 pdl->stopLoading();
2643
2644                 // Finish resetting the load state, but only if another load hasn't been started by the
2645                 // delegate callback.
2646                 if (pdl == m_provisionalDocumentLoader)
2647                     clearProvisionalLoad();
2648                 else if (m_documentLoader) {
2649                     KURL unreachableURL = m_documentLoader->unreachableURL();
2650                     if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2651                         shouldReset = false;
2652                 }
2653             }
2654             if (shouldReset && item && m_frame->page())
2655                  m_frame->page()->backForwardList()->goToItem(item.get());
2656
2657             return;
2658         }
2659         
2660         case FrameStateCommittedPage: {
2661             DocumentLoader* dl = m_documentLoader.get();            
2662             if (dl->isLoadingInAPISense())
2663                 return;
2664
2665             markLoadComplete();
2666
2667             // FIXME: Is this subsequent work important if we already navigated away?
2668             // Maybe there are bugs because of that, or extra work we can skip because
2669             // the new page is ready.
2670
2671             m_client->forceLayoutForNonHTML();
2672              
2673             // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2674             if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload)
2675                     && m_frame->page() && m_frame->page()->backForwardList())
2676                 restoreScrollPositionAndViewState();
2677
2678             const ResourceError& error = dl->mainDocumentError();
2679             if (!error.isNull())
2680                 m_client->dispatchDidFailLoad(error);
2681             else
2682                 m_client->dispatchDidFinishLoad();
2683
2684             if (m_frame->page())
2685                 m_frame->page()->progress()->progressCompleted(m_frame);
2686             return;
2687         }
2688         
2689         case FrameStateComplete:
2690             // Even if already complete, we might have set a previous item on a frame that
2691             // didn't do any data loading on the past transaction. Make sure to clear these out.
2692             m_client->frameLoadCompleted();
2693             return;
2694     }
2695
2696     ASSERT_NOT_REACHED();
2697 }
2698 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
2699 {
2700     PolicyCheck check = m_policyCheck;
2701     m_policyCheck.clear();
2702     check.call(policy);
2703 }
2704
2705 void FrameLoader::continueAfterWillSubmitForm(PolicyAction)
2706 {
2707     startLoading();
2708 }
2709
2710 void FrameLoader::didFirstLayout()
2711 {
2712     if (isBackForwardLoadType(m_loadType) && m_frame->page() && m_frame->page()->backForwardList())
2713         restoreScrollPositionAndViewState();
2714
2715     m_firstLayoutDone = true;
2716     m_client->dispatchDidFirstLayout();
2717 }
2718
2719 void FrameLoader::frameLoadCompleted()
2720 {
2721     m_client->frameLoadCompleted();
2722
2723     // After a canceled provisional load, firstLayoutDone is false.
2724     // Reset it to true if we're displaying a page.
2725     if (m_documentLoader)
2726         m_firstLayoutDone = true;
2727 }
2728
2729 bool FrameLoader::firstLayoutDone() const
2730 {
2731     return m_firstLayoutDone;
2732 }
2733
2734 bool FrameLoader::isQuickRedirectComing() const
2735 {
2736     return m_quickRedirectComing;
2737 }
2738
2739 void FrameLoader::detachChildren()
2740 {
2741     // FIXME: Is it really necessary to do this in reverse order?
2742     Frame* previous;
2743     for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
2744         previous = child->tree()->previousSibling();
2745         child->loader()->detachFromParent();
2746     }
2747 }
2748
2749 // Called every time a resource is completely loaded, or an error is received.
2750 void FrameLoader::checkLoadComplete()
2751 {
2752     ASSERT(m_client->hasWebView());
2753     for (RefPtr<Frame> frame = m_frame; frame; frame = frame->tree()->parent())
2754         frame->loader()->checkLoadCompleteForThisFrame();
2755 }
2756
2757 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
2758 {
2759     if (!recurse)
2760         return numRequests(m_frame->document());
2761
2762     int count = 0;
2763     for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
2764         count += numRequests(frame->document());
2765     return count;
2766 }
2767
2768 FrameLoaderClient* FrameLoader::client() const
2769 {
2770     return m_client;
2771 }
2772
2773 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
2774 {
2775 #ifdef MULTIPLE_FORM_SUBMISSION_PROTECTION
2776     // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
2777     // We do not want to submit more than one form from the same page,
2778     // nor do we want to submit a single form more than once.
2779     // This flag prevents these from happening; not sure how other browsers prevent this.
2780     // The flag is reset in each time we start handle a new mouse or key down event, and
2781     // also in setView since this part may get reused for a page from the back/forward cache.
2782     // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
2783     // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
2784     // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
2785     // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
2786     Frame* target = m_frame->tree()->find(request.frameName());
2787     if (m_frame->tree()->isDescendantOf(target)) {
2788         if (m_submittedFormURL == request.resourceRequest().url())
2789             return;
2790         m_submittedFormURL = request.resourceRequest().url();
2791     }
2792 #endif
2793
2794     // FIXME: Why do we always pass true for userGesture?
2795     load(request, true, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
2796
2797     clearRecordedFormValues();
2798 }
2799
2800 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event)
2801 {
2802     FrameLoadRequest copy = request;
2803     if (copy.resourceRequest().httpReferrer().isEmpty())
2804         copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
2805
2806     // FIXME: Why do we always pass true for userGesture?
2807     load(copy, true, event, 0, HashMap<String, String>());
2808 }
2809     
2810 String FrameLoader::userAgent() const
2811 {
2812     return m_client->userAgent();
2813 }
2814
2815 void FrameLoader::createEmptyDocument()
2816 {
2817     // Although it's not completely clear from the name of this function,
2818     // it does nothing if we already have a document, and just creates an
2819     // empty one if we have no document at all.
2820     if (!m_frame->document()) {
2821         loadEmptyDocumentSynchronously();
2822         updateBaseURLForEmptyDocument();
2823     }
2824 }
2825
2826 void FrameLoader::tokenizerProcessedData()
2827 {
2828     if (m_frame->document())
2829         checkCompleted();
2830     checkLoadComplete();
2831 }
2832
2833 void FrameLoader::didTellBridgeAboutLoad(const String& URL)
2834 {
2835     m_urlsBridgeKnowsAbout.add(URL);
2836 }
2837
2838 bool FrameLoader::haveToldBridgeAboutLoad(const String& URL)
2839 {
2840     return m_urlsBridgeKnowsAbout.contains(URL);
2841 }
2842
2843 void FrameLoader::handledOnloadEvents()
2844 {
2845     m_client->dispatchDidHandleOnloadEvents();
2846 }
2847
2848 void FrameLoader::frameDetached()
2849 {
2850     stopAllLoaders();
2851     detachFromParent();
2852 }
2853
2854 void FrameLoader::detachFromParent()
2855 {
2856     RefPtr<Frame> protect(m_frame);
2857
2858     closeURL();
2859     stopAllLoaders();
2860     m_client->detachedFromParent1();
2861     detachChildren();
2862     m_client->detachedFromParent2();
2863     setDocumentLoader(0);
2864     m_client->detachedFromParent3();
2865     if (Frame* parent = m_frame->tree()->parent())
2866         parent->tree()->removeChild(m_frame);
2867     else {
2868         m_frame->setView(0);
2869         m_frame->pageDestroyed();
2870     }
2871 #if PLATFORM(MAC)
2872     closeBridge();
2873 #endif
2874     m_client->detachedFromParent4();
2875 }
2876
2877 void FrameLoader::dispatchDidChangeLocationWithinPage()
2878 {
2879     m_client->dispatchDidChangeLocationWithinPage();
2880 }
2881
2882 void FrameLoader::dispatchDidFinishLoadToClient()
2883 {
2884     m_client->didFinishLoad();
2885 }
2886
2887 void FrameLoader::updateGlobalHistoryForStandardLoad(const KURL& url)
2888 {
2889     m_client->updateGlobalHistoryForStandardLoad(url);
2890 }
2891
2892 void FrameLoader::updateGlobalHistoryForReload(const KURL& url)
2893 {
2894     m_client->updateGlobalHistoryForReload(url);
2895 }
2896
2897 bool FrameLoader::shouldGoToHistoryItem(HistoryItem* item) const
2898 {
2899     return m_client->shouldGoToHistoryItem(item);
2900 }
2901
2902 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest)
2903 {
2904     applyUserAgent(request);
2905     
2906     if (m_loadType == FrameLoadTypeReload)
2907         request.setHTTPHeaderField("Cache-Control", "max-age=0");
2908     
2909     // Don't set the cookie policy URL if it's already been set.
2910     if (request.mainDocumentURL().isEmpty()) {
2911         if (mainResource && (isLoadingMainFrame() || alwaysFromRequest))
2912             request.setMainDocumentURL(request.url());
2913         else
2914             request.setMainDocumentURL(m_frame->page()->mainFrame()->loader()->url());
2915     }
2916     
2917     if (mainResource)
2918         request.setHTTPAccept("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
2919 }
2920
2921 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
2922 {
2923     m_client->committedLoad(loader, data, length);
2924 }
2925
2926 void FrameLoader::post(const KURL& URL, const String& referrer, const String& frameName, PassRefPtr<FormData> formData, 
2927     const String& contentType, Event* event, HTMLFormElement* form, const HashMap<String, String>& formValues)
2928 {
2929     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
2930     // This prevents a potential bug which may cause a page with a form that uses itself
2931     // as an action to be returned from the cache without submitting.
2932
2933     // FIXME: Where's the code that implements what the comment above says?
2934
2935     ResourceRequest request(URL);
2936     addExtraFieldsToRequest(request, true, true);
2937
2938     if (!referrer.isEmpty())
2939         request.setHTTPReferrer(referrer);
2940     request.setHTTPMethod("POST");
2941     request.setHTTPBody(formData);
2942     request.setHTTPContentType(contentType);
2943
2944     NavigationAction action(URL, FrameLoadTypeStandard, true, event);
2945
2946     RefPtr<FormState> formState;
2947     if (form && !formValues.isEmpty())
2948         formState = FormState::create(form, formValues, m_frame);
2949
2950     if (!frameName.isEmpty()) {
2951         if (Frame* targetFrame = m_frame->tree()->find(frameName))
2952             targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release());
2953         else
2954             checkNewWindowPolicy(action, request, formState.release(), frameName);
2955     } else
2956         load(request, action, FrameLoadTypeStandard, formState.release());
2957 }
2958
2959 bool FrameLoader::isReloading() const
2960 {
2961     return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData;
2962 }
2963
2964 void FrameLoader::loadEmptyDocumentSynchronously()
2965 {
2966     ResourceRequest request(KURL(""));
2967     load(request);
2968 }
2969
2970 void FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
2971 {
2972     // Since this is a subresource, we can load any URL (we ignore the return value).
2973     // But we still want to know whether we should hide the referrer or not, so we call the canLoad method.
2974     String referrer = m_outgoingReferrer;
2975     bool hideReferrer;
2976     canLoad(request.url(), referrer, hideReferrer);
2977     if (hideReferrer)
2978         referrer = String();
2979     
2980     ResourceRequest initialRequest = request;
2981     initialRequest.setTimeoutInterval(10);
2982     
2983     if (initialRequest.isConditional())
2984         initialRequest.setCachePolicy(ReloadIgnoringCacheData);
2985     else
2986         initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
2987     
2988     if (!referrer.isEmpty())
2989         initialRequest.setHTTPReferrer(referrer);
2990     
2991     initialRequest.setMainDocumentURL(m_frame->page()->mainFrame()->loader()->documentLoader()->request().url());
2992     initialRequest.setHTTPUserAgent(client()->userAgent());
2993     
2994     unsigned long identifier = 0;    
2995     ResourceRequest newRequest(initialRequest);
2996     requestFromDelegate(newRequest, identifier, error);
2997
2998     if (error.isNull()) {
2999         ASSERT(!newRequest.isNull());
3000         didTellBridgeAboutLoad(newRequest.url().url());
3001         ResourceHandle::loadResourceSynchronously(newRequest, error, response, data);
3002     }
3003     
3004     sendRemainingDelegateMessages(identifier, response, data.size(), error);
3005 }
3006
3007 bool FrameLoader::startLoadingMainResource(ResourceRequest& request, unsigned long identifier)
3008 {
3009     ASSERT(!m_mainResourceLoader);
3010     m_mainResourceLoader = MainResourceLoader::create(m_frame);
3011     m_mainResourceLoader->setIdentifier(identifier);
3012     
3013     // FIXME: is there any way the extra fields could have not been added by now?
3014     addExtraFieldsToRequest(request, true, false);
3015     if (!m_mainResourceLoader->load(request)) {
3016         // FIXME: If this should really be caught, we should just ASSERT this doesn't happen;
3017         // should it be caught by other parts of WebKit or other parts of the app?
3018 #if PLATFORM(MAC)
3019         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", request.url().getNSURL());
3020 #endif
3021         m_mainResourceLoader = 0;
3022         return false;
3023     }
3024     return true;
3025 }
3026
3027 // FIXME: Poor method name; also, why is this not part of startProvisionalLoad:?
3028 void FrameLoader::startLoading()
3029 {
3030     if (!m_provisionalDocumentLoader)
3031         return;
3032
3033     m_provisionalDocumentLoader->prepareForLoadStart();
3034
3035     if (m_mainResourceLoader)
3036         return;
3037
3038     m_provisionalDocumentLoader->setLoadingFromPageCache(false);
3039
3040     unsigned long identifier = m_frame->page()->progress()->createUniqueIdentifier();
3041     m_client->assignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3042
3043     if (!startLoadingMainResource(m_provisionalDocumentLoader->actualRequest(), identifier))
3044         m_provisionalDocumentLoader->updateLoading();
3045 }
3046
3047 void FrameLoader::cancelMainResourceLoad(const ResourceError& error)
3048 {
3049     m_mainResourceLoader->cancel(error);
3050 }
3051
3052 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3053 {
3054     return m_client->assignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3055 }
3056
3057 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3058 {
3059     applyUserAgent(clientRequest);
3060     m_client->dispatchWillSendRequest(activeDocumentLoader(), loader->identifier(), clientRequest, redirectResponse);
3061 }
3062
3063 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3064 {
3065     activeDocumentLoader()->addResponse(r);
3066     
3067     if (m_frame->page())
3068         m_frame->page()->progress()->incrementProgress(loader->identifier(), r);
3069     m_client->dispatchDidReceiveResponse(activeDocumentLoader(), loader->identifier(), r);
3070 }
3071
3072 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3073 {
3074     if (m_frame->page())
3075         m_frame->page()->progress()->incrementProgress(loader->identifier(), data, length);
3076     m_client->dispatchDidReceiveContentLength(activeDocumentLoader(), loader->identifier(), lengthReceived);
3077 }
3078
3079 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3080 {
3081     if (m_frame->page())
3082         m_frame->page()->progress()->completeProgress(loader->identifier());
3083     if (!error.isNull())
3084         m_client->dispatchDidFailLoading(activeDocumentLoader(), loader->identifier(), error);
3085 }
3086
3087 const ResourceRequest& FrameLoader::originalRequest() const
3088 {
3089     return activeDocumentLoader()->originalRequestCopy();
3090 }
3091
3092 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3093 {
3094     // Retain because the stop may release the last reference to it.
3095     RefPtr<Frame> protect(m_frame);
3096
3097     RefPtr<DocumentLoader> loader = activeDocumentLoader();
3098     
3099     if (isComplete) {
3100         // FIXME: Don't want to do this if an entirely new load is going, so should check
3101         // that both data sources on the frame are either this or nil.
3102         stop();
3103         if (m_client->shouldFallBack(error))
3104             handleFallbackContent();
3105     }
3106     
3107     if (m_state == FrameStateProvisional) {
3108 #ifdef MULTIPLE_FORM_SUBMISSION_PROTECTION
3109         KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url();
3110         didNotOpenURL(failedURL);
3111 #endif
3112         // We might have made a page cache item, but now we're bailing out due to an error before we ever
3113         // transitioned to the new page (before WebFrameState == commit).  The goal here is to restore any state
3114         // so that the existing view (that wenever got far enough to replace) can continue being used.
3115         Document* document = m_frame->document();
3116         if (document)
3117             document->setInPageCache(false);
3118         invalidateCurrentItemPageCache();
3119         
3120         // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3121         // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3122         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3123         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3124         // has ended.
3125         if (m_sentRedirectNotification)
3126             clientRedirectCancelledOrFinished(false);
3127     }
3128     
3129     
3130     loader->mainReceivedError(error, isComplete);
3131 }
3132
3133 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3134     const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3135 {
3136     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3137     loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3138 }
3139
3140 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3141 {
3142     bool isRedirect = m_quickRedirectComing;
3143     m_quickRedirectComing = false;
3144
3145     if (!shouldContinue)
3146         return;
3147
3148     KURL URL = request.url();
3149     
3150     m_documentLoader->replaceRequestURLForAnchorScroll(URL);
3151     if (!isRedirect && !shouldTreatURLAsSameAsCurrent(URL)) {
3152         // NB: must happen after _setURL, since we add based on the current request.
3153         // Must also happen before we openURL and displace the scroll position, since
3154         // adding the BF item will save away scroll state.
3155         
3156         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
3157         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3158         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
3159         // though its load is not yet done.  I think this all works out OK, for one because
3160         // we have already saved away the scroll and doc state for the long slow load,
3161         // but it's not an obvious case.
3162
3163         addHistoryItemForFragmentScroll();
3164     }
3165     
3166     scrollToAnchor(URL);
3167     
3168     if (!isRedirect)
3169         // This will clear previousItem from the rest of the frame tree that didn't
3170         // doing any loading. We need to make a pass on this now, since for anchor nav
3171         // we'll not go through a real load and reach Completed state.
3172         checkLoadComplete();
3173  
3174     dispatchDidChangeLocationWithinPage();
3175     m_client->didFinishLoad();
3176 }
3177
3178 void FrameLoader::opened()
3179 {
3180     if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
3181         updateHistoryForClientRedirect();
3182
3183     if (m_documentLoader->isLoadingFromPageCache()) {
3184         // Force a layout to update view size and thereby update scrollbars.
3185         m_client->forceLayout();
3186
3187         const ResponseVector& responses = m_documentLoader->responses();
3188         size_t count = responses.size();
3189         for (size_t i = 0; i < count; i++) {
3190             const ResourceResponse& response = responses[i];
3191             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
3192             ResourceError error;
3193             unsigned long identifier;
3194             ResourceRequest request(response.url());
3195             requestFromDelegate(request, identifier, error);
3196             sendRemainingDelegateMessages(identifier, response, response.expectedContentLength(), error);
3197         }
3198         
3199         m_client->loadedFromPageCache();
3200
3201         m_documentLoader->setPrimaryLoadComplete(true);
3202
3203         // FIXME: Why only this frame and not parent frames?
3204         checkLoadCompleteForThisFrame();
3205     }
3206 }
3207
3208 KURL FrameLoader::dataURLBaseFromRequest(const ResourceRequest& request) const
3209 {
3210 #if PLATFORM(MAC)
3211     if (WebDataRequestParameters* params = [request.nsURLRequest() _webDataRequestParametersForReading])
3212         return params->baseURL;
3213 #endif
3214     return KURL();
3215 }
3216
3217 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3218     PassRefPtr<FormState> formState, const String& frameName)
3219 {
3220     m_policyCheck.set(request, formState, frameName,
3221         callContinueLoadAfterNewWindowPolicy, this);
3222     m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3223         action, request, frameName);
3224 }
3225
3226 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3227 {
3228     PolicyCheck check = m_policyCheck;
3229     m_policyCheck.clear();
3230
3231     switch (policy) {
3232         case PolicyIgnore:
3233             check.clearRequest();
3234             break;
3235         case PolicyDownload:
3236             m_client->startDownload(check.request());
3237             check.clearRequest();
3238             break;
3239         case PolicyUse:
3240             break;
3241     }
3242
3243     check.call(policy == PolicyUse);
3244 }
3245
3246 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3247     PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3248 {
3249     NavigationAction action = loader->triggeringAction();
3250     if (action.isEmpty()) {
3251         action = NavigationAction(request.url(), NavigationTypeOther);
3252         loader->setTriggeringAction(action);
3253     }
3254         
3255     // Don't ask more than once for the same request or if we are loading an empty URL.
3256     // This avoids confusion on the part of the client.
3257     if (request == loader->lastCheckedRequest() || request.url().isEmpty()) {
3258         function(argument, request, 0, true);
3259         return;
3260     }
3261     
3262     // We are always willing to show alternate content for unreachable URLs;
3263     // treat it like a reload so it maintains the right state for b/f list.
3264 #if PLATFORM(MAC)
3265     if ([request.nsURLRequest() _webDataRequestUnreachableURL]) {
3266         if (isBackForwardLoadType(m_policyLoadType))
3267             m_policyLoadType = FrameLoadTypeReload;
3268         function(argument, request, 0, true);
3269         return;
3270     }
3271 #endif
3272     
3273     loader->setLastCheckedRequest(request);
3274
3275     m_policyCheck.set(request, formState, function, argument);
3276
3277     m_delegateIsDecidingNavigationPolicy = true;
3278     m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
3279         action, request);
3280     m_delegateIsDecidingNavigationPolicy = false;
3281 }
3282
3283 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
3284 {
3285     PolicyCheck check = m_policyCheck;
3286     m_policyCheck.clear();
3287
3288     switch (policy) {
3289         case PolicyIgnore:
3290             check.clearRequest();
3291             break;
3292         case PolicyDownload:
3293             m_client->startDownload(check.request());
3294             check.clearRequest();
3295             break;
3296         case PolicyUse: {
3297             ResourceRequest request(check.request());
3298             if (!m_client->canHandleRequest(request)) {
3299                 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
3300                 check.clearRequest();
3301             }
3302             break;
3303         }
3304     }
3305
3306     check.call(policy == PolicyUse);
3307 }
3308
3309 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3310     const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3311 {
3312     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3313     loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3314 }
3315
3316 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3317 {
3318     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3319     // nil policyDataSource because loading the alternate page will have passed
3320     // through this method already, nested; otherwise, policyDataSource should still be set.
3321     ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3322
3323     bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
3324
3325     // Two reasons we can't continue:
3326     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
3327     //       is the user responding Cancel to the form repost nag sheet.
3328     //    2) User responded Cancel to an alert popped up by the before unload event handler.
3329     // The "before unload" event handler runs only for the main frame.
3330     bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3331
3332     if (!canContinue) {
3333         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
3334         // need to report that the client redirect was cancelled.
3335         if (m_quickRedirectComing)
3336             clientRedirectCancelledOrFinished(false);
3337
3338         setPolicyDocumentLoader(0);
3339
3340         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
3341         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
3342         // we only do this when punting a navigation for the target frame or top-level frame.  
3343         if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType) && m_frame->page()) {
3344             Frame* mainFrame = m_frame->page()->mainFrame();
3345             if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get())
3346                 m_frame->page()->backForwardList()->goToItem(resetItem);
3347         }
3348         return;
3349     }
3350
3351     FrameLoadType type = m_policyLoadType;
3352     stopAllLoaders();
3353     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
3354     m_loadType = type;
3355     setState(FrameStateProvisional);
3356
3357     setPolicyDocumentLoader(0);
3358
3359     if (isBackForwardLoadType(type) && loadProvisionalItemFromPageCache())
3360         return;
3361
3362     if (formState)
3363         m_client->dispatchWillSubmitForm(&FrameLoader::continueAfterWillSubmitForm, formState);
3364     else
3365         continueAfterWillSubmitForm();
3366 }
3367
3368
3369 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
3370     const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3371 {
3372     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3373     loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
3374 }
3375
3376 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
3377     PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3378 {
3379     if (!shouldContinue)
3380         return;
3381
3382     RefPtr<Frame> frame = m_frame;
3383     RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
3384     if (!mainFrame)
3385         return;
3386
3387     mainFrame->tree()->setName(frameName);
3388     mainFrame->loader()->m_client->dispatchShow();
3389     mainFrame->loader()->setOpener(frame.get());
3390     mainFrame->loader()->load(request, NavigationAction(), FrameLoadTypeStandard, formState);
3391 }
3392
3393 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, unsigned length, const ResourceError& error)
3394 {    
3395     if (!response.isNull())
3396         m_client->dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response);
3397     
3398     if (length > 0)
3399         m_client->dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length);
3400     
3401     if (error.isNull())
3402         m_client->dispatchDidFinishLoading(m_documentLoader.get(), identifier);
3403     else
3404         m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error);
3405 }
3406
3407 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
3408 {
3409     ASSERT(!request.isNull());
3410
3411     identifier = m_frame->page()->progress()->createUniqueIdentifier();
3412     m_client->assignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
3413
3414     ResourceRequest newRequest(request);
3415     m_client->dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3416
3417     if (newRequest.isNull())
3418         error = m_client->cancelledError(request);
3419     else
3420         error = ResourceError();
3421
3422     request = newRequest;
3423 }
3424
3425 void FrameLoader::loadedResourceFromMemoryCache(const ResourceRequest& request, const ResourceResponse& response, int length)
3426 {
3427     if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length))
3428         return;
3429
3430     unsigned long identifier;
3431     ResourceError error;
3432     ResourceRequest r(request);
3433     requestFromDelegate(r, identifier, error);
3434     sendRemainingDelegateMessages(identifier, response, length, error);
3435 }
3436
3437 void FrameLoader::applyUserAgent(ResourceRequest& request)
3438 {
3439     String userAgent = client()->userAgent();
3440     ASSERT(!userAgent.isNull());
3441     request.setHTTPUserAgent(userAgent);
3442 }
3443
3444 bool FrameLoader::canGoBackOrForward(int distance) const
3445 {
3446     if (distance == 0)
3447         return true;
3448     if (distance > 0 && distance <= m_frame->page()->backForwardList()->forwardListCount())
3449         return true;
3450     if (distance < 0 && -distance <= m_frame->page()->backForwardList()->backListCount())
3451         return true;
3452     return false;
3453 }
3454
3455 int FrameLoader::getHistoryLength()
3456 {
3457     return m_frame->page()->backForwardList()->backListCount() + 1;
3458 }
3459
3460 KURL FrameLoader::historyURL(int distance)
3461 {
3462     BackForwardList *list = m_frame->page()->backForwardList();
3463     HistoryItem* item = list->itemAtIndex(distance);
3464     if (!item) {
3465         if (distance > 0) {
3466             int forwardListCount = list->forwardListCount();
3467             if (forwardListCount > 0)
3468                 item = list->itemAtIndex(forwardListCount);
3469         } else {
3470             int backListCount = list->backListCount();
3471             if (backListCount > 0)
3472                 item = list->itemAtIndex(-backListCount);
3473         }
3474     }
3475     if (item)
3476         return item->url();
3477
3478     return KURL();
3479 }
3480
3481 void FrameLoader::addHistoryItemForFragmentScroll()
3482 {
3483     addBackForwardItemClippedAtTarget(false);
3484 }
3485
3486 bool FrameLoader::loadProvisionalItemFromPageCache()
3487 {
3488     if (!m_provisionalHistoryItem || !m_provisionalHistoryItem->hasPageCache())
3489         return false;
3490
3491     RefPtr<PageState> state = m_provisionalHistoryItem->pageCache()->pageState();
3492     if (!state)
3493         return false;
3494     
3495     provisionalDocumentLoader()->loadFromPageCache(m_provisionalHistoryItem->pageCache());
3496     return true;
3497 }
3498
3499 bool FrameLoader::createPageCache(HistoryItem* item)
3500 {
3501     RefPtr<PageState> pageState = PageState::create(m_frame->page());
3502     
3503     if (!pageState) {
3504         item->setHasPageCache(false);
3505         return false;
3506     }
3507     
3508     item->setHasPageCache(true);
3509     RefPtr<PageCache> pageCache = item->pageCache();
3510
3511     pageCache->setPageState(pageState.release());
3512     pageCache->setTimeStampToNow();
3513     pageCache->setDocumentLoader(documentLoader());
3514     m_client->saveDocumentViewToPageCache(pageCache.get());
3515
3516     return true;
3517 }
3518
3519 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& URL) const
3520 {
3521     if (!m_currentHistoryItem)
3522         return false;
3523     return URL == m_currentHistoryItem->url() || URL == m_currentHistoryItem->originalURL();
3524 }
3525
3526 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
3527 {
3528     DocumentLoader* docLoader = documentLoader();
3529     
3530     KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL();
3531     
3532     KURL url;
3533     KURL originalURL;
3534
3535     if (!unreachableURL.isEmpty()) {
3536         url = unreachableURL;
3537         originalURL = unreachableURL;
3538     } else {
3539         originalURL = docLoader ? docLoader->originalURL() : KURL();
3540         if (useOriginal)
3541             url = originalURL;
3542         else if (docLoader)
3543             url = docLoader->requestURL();                
3544     }
3545
3546     LOG (History, "WebCoreHistory - Creating item for %s", url.url().ascii());
3547     
3548     // Frames that have never successfully loaded any content
3549     // may have no URL at all. Currently our history code can't
3550     // deal with such things, so we nip that in the bud here.
3551     // Later we may want to learn to live with nil for URL.
3552     // See bug 3368236 and related bugs for more information.
3553     if (url.isEmpty()) 
3554         url = KURL("about:blank");
3555     if (originalURL.isEmpty())
3556         originalURL = KURL("about:blank");
3557     
3558     RefPtr<HistoryItem> item = new HistoryItem(url, m_frame->tree()->name(), m_frame->tree()->parent() ? m_frame->tree()->parent()->tree()->name() : "", docLoader ? docLoader->title() : "");
3559     item->setOriginalURLString(originalURL.url());
3560     
3561     // Save form state if this is a POST
3562     if (docLoader) {
3563         if (useOriginal)
3564             item->setFormInfoFromRequest(docLoader->originalRequest());
3565         else
3566             item->setFormInfoFromRequest(docLoader->request());
3567     }
3568     
3569     // Set the item for which we will save document state
3570     m_previousHistoryItem = m_currentHistoryItem;
3571     m_currentHistoryItem = item;
3572     
3573     return item.release();
3574 }
3575
3576 void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
3577 {
3578     if (!documentLoader()->urlForHistory().isEmpty()) {
3579         Frame* mainFrame = m_frame->page()->mainFrame();
3580         ASSERT(mainFrame);
3581         RefPtr<HistoryItem> item = mainFrame->loader()->createHistoryItemTree(m_frame, doClip);
3582         LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), documentLoader()->URL().url().ascii());
3583         ASSERT(m_frame->page());
3584         m_frame->page()->backForwardList()->addItem(item);
3585     }
3586 }
3587
3588 PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, bool clipAtTarget)
3589 {
3590     RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? true : false);
3591     if (m_previousHistoryItem)
3592         saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
3593     if (!(clipAtTarget && m_frame == targetFrame)) {
3594         // save frame state for items that aren't loading (khtml doesn't save those)
3595         saveDocumentState();
3596         for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3597             bfItem->addChildItem(child->loader()->createHistoryItemTree(targetFrame, clipAtTarget));
3598     }
3599     if (m_frame == targetFrame)
3600         bfItem->setIsTargetItem(true);
3601     return bfItem;
3602 }
3603
3604 void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item)
3605 {
3606     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
3607     m_client->saveScrollPositionAndViewStateToItem(item);
3608 }
3609
3610 void FrameLoader::restoreScrollPositionAndViewState()
3611 {
3612     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
3613     m_client->restoreScrollPositionAndViewState();
3614 }
3615
3616 void FrameLoader::purgePageCache()
3617 {
3618     // This method implements the rule for purging the page cache.
3619     if (!m_frame->page())
3620         return;
3621         
3622     BackForwardList* bfList = m_frame->page()->backForwardList();
3623     unsigned sizeLimit = bfList->pageCacheSize();
3624     unsigned pagesCached = 0;
3625
3626     HistoryItemVector items;
3627     bfList->backListWithLimit(INT_MAX, items);
3628     RefPtr<HistoryItem> oldestNonSnapbackItem;
3629     
3630     unsigned int i = 0;
3631     
3632     for (; i < items.size(); ++i) {
3633         if (items[i]->hasPageCache()) {
3634             if (!oldestNonSnapbackItem && !items[i]->alwaysAttemptToUsePageCache())
3635                 oldestNonSnapbackItem = items[i];
3636             pagesCached++;
3637         }
3638     }
3639     
3640     // Snapback items are never directly purged here.
3641     if (pagesCached >= sizeLimit && oldestNonSnapbackItem) {
3642         LOG(PageCache, "Purging back/forward cache, %s\n", oldestNonSnapbackItem->url().url().ascii());
3643         oldestNonSnapbackItem->setHasPageCache(false);
3644     }
3645 }
3646
3647 void FrameLoader::invalidateCurrentItemPageCache()
3648 {
3649     // When we are pre-commit, the currentItem is where the pageCache data resides    
3650     PageCache* pageCache = m_currentHistoryItem ? m_currentHistoryItem->pageCache() : 0;
3651     PageState* pageState = pageCache ? pageCache->pageState() : 0;
3652
3653     // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach
3654     // Somehow the PageState object is not properly updated, and is holding onto a stale document.
3655     // Both Xcode and FileMaker see this crash, Safari does not.
3656     
3657     ASSERT(!pageState || pageState->document() == m_frame->document());
3658     if (pageState && pageState->document() == m_frame->document())
3659         pageState->clear();
3660     
3661     if (m_currentHistoryItem)
3662         m_currentHistoryItem->setHasPageCache(false);
3663 }
3664
3665 void FrameLoader::saveDocumentState()
3666 {
3667     // Do not save doc state if the page has a password field and a form that would be submitted via https.
3668     Document* document = m_frame->document();
3669     if (document && document->hasPasswordField() && document->hasSecureForm())
3670         return;
3671         
3672     // For a standard page load, we will have a previous item set, which will be used to
3673     // store the form state.  However, in some cases we will have no previous item, and
3674     // the current item is the right place to save the state.  One example is when we
3675     // detach a bunch of frames because we are navigating from a site with frames to
3676     // another site.  Another is when saving the frame state of a frame that is not the
3677     // target of the current navigation (if we even decide to save with that granularity).
3678
3679     // Because of previousItem's "masking" of currentItem for this purpose, it's important
3680     // that previousItem be cleared at the end of a page transition.  We leverage the
3681     // checkLoadComplete recursion to achieve this goal.
3682
3683     HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_currentHistoryItem.get();
3684     if (!item)
3685         return;
3686         
3687     if (document) {
3688         LOG(Loading, "WebCoreLoading %s: saving form state to %p", ((String&)m_frame->tree()->name()).ascii().data(), item);
3689         item->setDocumentState(document->formElementsState());
3690     }
3691 }
3692
3693 // Loads content into this frame, as specified by history item
3694 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3695 {
3696     KURL itemURL = item->url();
3697     KURL itemOriginalURL = item->originalURL();
3698     KURL currentURL = documentLoader()->URL();
3699     RefPtr<FormData> formData = item->formData();
3700
3701     // Are we navigating to an anchor within the page?
3702     // Note if we have child frames we do a real reload, since the child frames might not
3703     // match our current frame structure, or they might not have the right content.  We could
3704     // check for all that as an additional optimization.
3705     // We also do not do anchor-style navigation if we're posting a form.
3706     
3707     // FIXME: These checks don't match the ones in _loadURL:referrer:loadType:target:triggeringEvent:isFormSubmission:
3708     // Perhaps they should.
3709     if (!formData && !shouldReload(itemURL, currentURL) && urlsMatchItem(item)) {
3710 #if 0
3711         // FIXME:  We need to normalize the code paths for anchor navigation.  Something
3712         // like the following line of code should be done, but also accounting for correct
3713         // updates to the back/forward list and scroll position.
3714         // rjw 4/9/03 See 3223929.
3715         [self _loadURL:itemURL referrer:[[[self dataSource] request] HTTPReferrer] loadType:loadType target:nil triggeringEvent:nil form:nil formValues:nil];
3716 #endif
3717
3718         // Must do this maintenance here, since we don't go through a real page reload
3719         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
3720
3721         // FIXME: form state might want to be saved here too
3722
3723         // We always call scrollToAnchor here, even if the URL doesn't have an
3724         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
3725         scrollToAnchor(item->url());
3726     
3727         // must do this maintenance here, since we don't go through a real page reload
3728         m_currentHistoryItem = item;
3729         restoreScrollPositionAndViewState();
3730         
3731         // Fake the URL change by updating the data source's request.  This will no longer
3732         // be necessary if we do the better fix described above.
3733         documentLoader()->replaceRequestURLForAnchorScroll(itemURL);
3734
3735         dispatchDidChangeLocationWithinPage();
3736         
3737         // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
3738         dispatchDidFinishLoadToClient();
3739     } else {
3740         // Remember this item so we can traverse any child items as child frames load
3741         m_provisionalHistoryItem = item;
3742
3743         bool inPageCache = false;
3744         
3745         // Check if we'll be using the page cache.  We only use the page cache
3746         // if one exists and it is less than _backForwardCacheExpirationInterval
3747         // seconds old.  If the cache is expired it gets flushed here.
3748         if (item->hasPageCache()) {
3749             RefPtr<PageCache> pageCache = item->pageCache();
3750             double interval = currentTime() - pageCache->timeStamp();
3751             
3752             // FIXME: 1800 is the current backforwardcache expiration time, but we actually store as a pref -
3753             // previously, this code was -
3754             //if (interval <= [[getWebView(self) preferences] _backForwardCacheExpirationInterval]) {
3755             if (interval <= 1800) {
3756                 load(pageCache->documentLoader(), loadType, 0);   
3757                 inPageCache = true;
3758             } else {
3759                 LOG (PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", m_provisionalHistoryItem->url().url().ascii());
3760                 item->setHasPageCache(false);
3761             }
3762         }
3763         
3764         if (!inPageCache) {
3765             ResourceRequest request(itemURL);
3766
3767             addExtraFieldsToRequest(request, true, formData);
3768
3769             // If this was a repost that failed the page cache, we might try to repost the form.
3770             NavigationAction action;
3771             if (formData) {
3772                 request.setHTTPMethod("POST");
3773                 request.setHTTPReferrer(item->formReferrer());
3774                 request.setHTTPBody(formData);
3775                 request.setHTTPContentType(item->formContentType());
3776         
3777                 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
3778                 // We want to know this before talking to the policy delegate, since it affects whether 
3779                 // we show the DoYouReallyWantToRepost nag.
3780                 //
3781                 // This trick has a small bug (3123893) where we might find a cache hit, but then
3782                 // have the item vanish when we try to use it in the ensuing nav.  This should be
3783                 // extremely rare, but in that case the user will get an error on the navigation.
3784                 
3785                 if (ResourceHandle::willLoadFromCache(request))
3786                     action = NavigationAction(itemURL, loadType, false);
3787                 else {
3788                     request.setCachePolicy(ReloadIgnoringCacheData);
3789                     action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
3790                 }
3791             } else {
3792                 switch (loadType) {
3793                     case FrameLoadTypeReload:
3794                         request.setCachePolicy(ReloadIgnoringCacheData);
3795                         break;
3796                     case FrameLoadTypeBack:
3797                     case FrameLoadTypeForward:
3798                     case FrameLoadTypeIndexedBackForward:
3799                         if (itemURL.protocol() == "https")
3800                             request.setCachePolicy(ReturnCacheDataElseLoad);
3801                         break;
3802                     case FrameLoadTypeStandard:
3803                     case FrameLoadTypeInternal:
3804                         // no-op: leave as protocol default
3805                         // FIXME:  I wonder if we ever hit this case
3806                         break;
3807                     case FrameLoadTypeSame:
3808                     case FrameLoadTypeReloadAllowingStaleData:
3809                     default:
3810                         ASSERT_NOT_REACHED();
3811                 }
3812
3813                 action = NavigationAction(itemOriginalURL, loadType, false);
3814             }
3815
3816             load(request, action, loadType, 0);
3817         }
3818     }
3819 }
3820
3821 // Walk the frame tree and ensure that the URLs match the URLs in the item.
3822 bool FrameLoader::urlsMatchItem(HistoryItem* item) const
3823 {
3824     KURL currentURL = documentLoader()->URL();
3825     
3826     if (!equalIgnoringRef(currentURL, item->url()))
3827         return false;
3828     
3829     const HistoryItemVector& childItems = item->children();
3830     
3831     unsigned size = childItems.size();
3832     for (unsigned i = 0; i < size; ++i) {
3833         Frame* childFrame = m_frame->tree()->child(childItems[i]->target());
3834         if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get()))
3835             return false;
3836     }
3837
3838     return true;
3839 }
3840
3841 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
3842 // This includes recursion to handle loading into framesets properly
3843 void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type)
3844 {
3845     ASSERT(!m_frame->tree()->parent());
3846     
3847     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
3848     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
3849     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
3850     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
3851     if (shouldGoToHistoryItem(targetItem)) {
3852         BackForwardList* bfList = m_frame->page()->backForwardList();
3853         HistoryItem* currentItem = bfList->currentItem();
3854         
3855         // Set the BF cursor before commit, which lets the user quickly click back/forward again.
3856         // - plus, it only makes sense for the top level of the operation through the frametree,
3857         // as opposed to happening for some/one of the page commits that might happen soon
3858         bfList->goToItem(targetItem);
3859         recursiveGoToItem(targetItem, currentItem, type);
3860     }
3861 }
3862
3863 // The general idea here is to traverse the frame tree and the item tree in parallel,
3864 // tracking whether each frame already has the content the item requests.  If there is
3865 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
3866 // reload that frame, and all its kids.
3867 void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type)
3868 {
3869     ASSERT(item);
3870     ASSERT(fromItem);
3871     
3872     KURL itemURL = item->url();
3873     KURL currentURL = documentLoader()->URL();
3874     
3875     // Always reload the target frame of the item we're going to.  This ensures that we will
3876     // do -some- load for the transition, which means a proper notification will be posted
3877     // to the app.
3878     // The exact URL has to match, including fragment.  We want to go through the _load
3879     // method, even if to do a within-page navigation.
3880     // The current frame tree and the frame tree snapshot in the item have to match.
3881     if (!item->isTargetItem() &&
3882         itemURL == currentURL &&
3883         ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target()) &&
3884         childFramesMatchItem(item))
3885     {
3886         // This content is good, so leave it alone and look for children that need reloading
3887         // Save form state (works from currentItem, since prevItem is nil)
3888         ASSERT(!m_previousHistoryItem);
3889         saveDocumentState();
3890         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
3891         m_currentHistoryItem = item;
3892                 
3893         // Restore form state (works from currentItem)
3894         restoreDocumentState();
3895         
3896         // Restore the scroll position (taken in favor of going back to the anchor)
3897         restoreScrollPositionAndViewState();
3898         
3899         const HistoryItemVector& childItems = item->children();
3900         
3901         int size = childItems.size();
3902         for (int i = 0; i < size; ++i) {
3903             String childName = childItems[i]->target();
3904             HistoryItem* fromChildItem = fromItem->childItemWithName(childName);
3905             ASSERT(fromChildItem || fromItem->isTargetItem());
3906             Frame* childFrame = m_frame->tree()->child(childName);
3907             ASSERT(childFrame);
3908             childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChildItem, type);
3909         }
3910     } else {
3911         loadItem(item, type);
3912     }
3913 }
3914
3915 // helper method that determines whether the subframes described by the item's subitems
3916 // match our own current frameset
3917 bool FrameLoader::childFramesMatchItem(HistoryItem* item) const
3918 {
3919     const HistoryItemVector& childItems = item->children();
3920     if (childItems.size() != m_frame->tree()->childCount())
3921         return false;
3922     
3923     unsigned size = childItems.size();
3924     for (unsigned i = 0; i < size; ++i)
3925         if (!m_frame->tree()->child(childItems[i]->target()))
3926             return false;
3927     
3928     // Found matches for all item targets
3929     return true;
3930 }
3931
3932 void FrameLoader::updateHistoryForStandardLoad()
3933 {
3934     LOG(History, "WebCoreHistory - Updating History for Standard Load in frame %s", documentLoader()->URL().url().ascii());
3935
3936     if (!documentLoader()->isClientRedirect()) {
3937         KURL url = documentLoader()->urlForHistory();
3938         if (!url.isEmpty()) {
3939             if (!privateBrowsingEnabled()) {
3940                 // FIXME: <rdar://problem/4880065> - This will be a hook into the WebCore global history, and this loader/client call will be removed
3941                 updateGlobalHistoryForStandardLoad(url);
3942             }
3943             addBackForwardItemClippedAtTarget(true);
3944         }
3945     } else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryItem) {
3946         m_currentHistoryItem->setURL(documentLoader()->URL());
3947         m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request());
3948     }
3949 }
3950
3951 void FrameLoader::updateHistoryForClientRedirect()
3952 {
3953 #if !LOG_DISABLED
3954     if (documentLoader())
3955         LOG(History, "WebCoreHistory - Updating History for client redirect in frame %s", documentLoader()->title().utf8().data());
3956 #endif
3957
3958     // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
3959     // webcore has closed the URL and saved away the form state.
3960     if (m_currentHistoryItem) {
3961         m_currentHistoryItem->clearDocumentState();
3962         m_currentHistoryItem->clearScrollPoint();
3963     }
3964 }
3965
3966 void FrameLoader::updateHistoryForBackForwardNavigation()
3967 {
3968 #if !LOG_DISABLED
3969     if (documentLoader())
3970         LOG(History, "WebCoreHistory - Updating History for back/forward navigation in frame %s", documentLoader()->title().utf8().data());
3971 #endif
3972
3973     // Must grab the current scroll position before disturbing it
3974     saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
3975 }
3976
3977 void FrameLoader::updateHistoryForReload()
3978 {
3979 #if !LOG_DISABLED
3980     if (documentLoader())
3981         LOG(History, "WebCoreHistory - Updating History for reload in frame %s", documentLoader()->title().utf8().data());
3982 #endif
3983
3984     if (m_previousHistoryItem) {
3985         m_previousHistoryItem->setHasPageCache(false);
3986     
3987         if (loadType() == FrameLoadTypeReload)
3988             saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
3989     
3990         // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
3991         if (documentLoader()->unreachableURL().isEmpty())
3992             m_previousHistoryItem->setURL(documentLoader()->requestURL());
3993     }
3994     
3995     // FIXME: <rdar://problem/4880065> - This will be a hook into the WebCore global history, and this loader/client call will be removed
3996     // Update the last visited time. Mostly interesting for URL autocompletion statistics.
3997     updateGlobalHistoryForReload(documentLoader()->originalURL());
3998 }
3999
4000 void FrameLoader::updateHistoryForInternalLoad()
4001 {
4002 #if !LOG_DISABLED
4003     if (documentLoader())
4004         LOG(History, "WebCoreHistory - Updating History for internal load in frame %s", documentLoader()->title().utf8().data());
4005 #endif
4006
4007     // Add an item to the item tree for this frame
4008     ASSERT(!documentLoader()->isClientRedirect());
4009     Frame* parentFrame = m_frame->tree()->parent();
4010     // The only case where parentItem is NULL should be when a parent frame loaded an
4011     // empty URL, which doesn't set up a current item in that parent.
4012     if (parentFrame) {
4013         if (parentFrame->loader()->m_currentHistoryItem)
4014             parentFrame->loader()->m_currentHistoryItem->addChildItem(createHistoryItem(true));
4015     } else {
4016         // See 3556159. It's not clear if it's valid to be in FrameLoadTypeOnLoadEvent
4017         // for a top-level frame, but that was a likely explanation for those crashes,
4018         // so let's guard against it.
4019         // ...and all FrameLoadTypeOnLoadEvent uses were folded to WebFrameLoadTypeInternal
4020         LOG_ERROR("No parent frame in transitionToCommitted:, FrameLoadTypeInternal");
4021     }
4022 }
4023
4024 void FrameLoader::updateHistoryForCommit()
4025 {
4026 #if !LOG_DISABLED
4027     if (documentLoader())
4028         LOG(History, "WebCoreHistory - Updating History for commit in frame %s", documentLoader()->title().utf8().data());
4029 #endif
4030     FrameLoadType type = loadType();
4031     if (isBackForwardLoadType(type) ||
4032         (type == FrameLoadTypeReload && documentLoader() && !documentLoader()->unreachableURL().isEmpty())) {
4033         // Once committed, we want to use current item for saving DocState, and
4034         // the provisional item for restoring state.
4035         // Note previousItem must be set before we close the URL, which will
4036         // happen when the data source is made non-provisional below
4037         m_previousHistoryItem = m_currentHistoryItem;
4038         ASSERT(m_provisionalHistoryItem);
4039         m_currentHistoryItem = m_provisionalHistoryItem;
4040         m_provisionalHistoryItem = 0;
4041     }
4042 }
4043
4044 // Walk the frame tree, telling all frames to save their form state into their current
4045 // history item.
4046 void FrameLoader::saveDocumentAndScrollState()
4047 {
4048     for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) {
4049         frame->loader()->saveDocumentState();
4050         frame->loader()->saveScrollPositionAndViewStateToItem(frame->loader()->currentHistoryItem());
4051     }
4052 }
4053
4054 // FIXME: These 6 setter/getters are here for a dwindling number of users in WebKit, WebFrame
4055 // being the primary one.  After they're no longer needed there, they can be removed!
4056 HistoryItem* FrameLoader::currentHistoryItem()
4057 {
4058     return m_currentHistoryItem.get();
4059 }
4060
4061 HistoryItem* FrameLoader::previousHistoryItem()
4062 {
4063     return m_previousHistoryItem.get();
4064 }
4065
4066 HistoryItem* FrameLoader::provisionalHistoryItem()
4067 {
4068     return m_provisionalHistoryItem.get();
4069 }
4070
4071 void FrameLoader::setCurrentHistoryItem(PassRefPtr<HistoryItem> item)
4072 {
4073     m_currentHistoryItem = item;
4074 }
4075
4076 void FrameLoader::setPreviousHistoryItem(PassRefPtr<HistoryItem> item)
4077 {
4078     m_previousHistoryItem = item;
4079 }
4080
4081 void FrameLoader::setProvisionalHistoryItem(PassRefPtr<HistoryItem> item)
4082 {
4083     m_provisionalHistoryItem = item;
4084 }
4085
4086 void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceError& error)
4087 {
4088     m_client->setMainDocumentError(loader, error);
4089 }
4090
4091 void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError& error)
4092 {
4093     loader->setPrimaryLoadComplete(true);
4094     m_client->dispatchDidLoadMainResource(activeDocumentLoader());
4095     checkLoadComplete();
4096 }
4097
4098 void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete)
4099 {
4100     activeDocumentLoader()->mainReceivedError(error, isComplete);
4101 }
4102
4103 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
4104 {
4105     return m_client->cancelledError(request);
4106 }
4107
4108 ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& response) const
4109 {
4110     return m_client->fileDoesNotExistError(response);    
4111 }
4112
4113 void FrameLoader::didFinishLoad(ResourceLoader* loader)
4114 {    
4115     if (m_frame->page())
4116         m_frame->page()->progress()->completeProgress(loader->identifier());
4117     m_client->dispatchDidFinishLoading(activeDocumentLoader(), loader->identifier());
4118 }
4119
4120 PassRefPtr<SharedBuffer> FrameLoader::mainResourceData() const
4121 {
4122     if (!m_mainResourceLoader)
4123         return 0;
4124     return m_mainResourceLoader->resourceData();
4125 }
4126
4127 void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
4128 {
4129     m_client->dispatchDidReceiveAuthenticationChallenge(activeDocumentLoader(), loader->identifier(), currentWebChallenge);
4130 }
4131
4132 void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
4133 {
4134     m_client->dispatchDidCancelAuthenticationChallenge(activeDocumentLoader(), loader->identifier(), currentWebChallenge);
4135 }
4136
4137 PolicyCheck::PolicyCheck()
4138     : m_navigationFunction(0)
4139     , m_newWindowFunction(0)
4140     , m_contentFunction(0)
4141 {
4142 }
4143
4144 void PolicyCheck::clear()
4145 {
4146     clearRequest();
4147     m_navigationFunction = 0;
4148     m_newWindowFunction = 0;
4149     m_contentFunction = 0;
4150 }
4151
4152 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
4153     NavigationPolicyDecisionFunction function, void* argument)
4154 {
4155     m_request = request;
4156     m_formState = formState;
4157     m_frameName = String();
4158
4159     m_navigationFunction = function;
4160     m_newWindowFunction = 0;
4161     m_contentFunction = 0;
4162     m_argument = argument;
4163 }
4164
4165 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
4166     const String& frameName, NewWindowPolicyDecisionFunction function, void* argument)
4167 {
4168     m_request = request;
4169     m_formState = formState;
4170     m_frameName = frameName;
4171
4172     m_navigationFunction = 0;
4173     m_newWindowFunction = function;
4174     m_contentFunction = 0;
4175     m_argument = argument;
4176 }
4177
4178 void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument)
4179 {
4180     m_request = ResourceRequest();
4181     m_formState = 0;
4182     m_frameName = String();
4183
4184     m_navigationFunction = 0;
4185     m_newWindowFunction = 0;
4186     m_contentFunction = function;
4187     m_argument = argument;
4188 }
4189
4190 void PolicyCheck::call(bool shouldContinue)
4191 {
4192     if (m_navigationFunction)
4193         m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue);
4194     if (m_newWindowFunction)
4195         m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue);
4196     ASSERT(!m_contentFunction);
4197 }
4198
4199 void PolicyCheck::call(PolicyAction action)
4200 {
4201     ASSERT(!m_navigationFunction);
4202     ASSERT(!m_newWindowFunction);
4203     ASSERT(m_contentFunction);
4204     m_contentFunction(m_argument, action);
4205 }
4206
4207 void PolicyCheck::clearRequest()
4208 {
4209     m_request = ResourceRequest();
4210     m_formState = 0;
4211     m_frameName = String();
4212 }
4213
4214 void FrameLoader::setTitle(const String& title)
4215 {
4216     documentLoader()->setTitle(title);
4217 }
4218
4219 KURL FrameLoader::originalRequestURL() const
4220 {
4221     return activeDocumentLoader()->initialRequest().url();
4222 }
4223
4224 String FrameLoader::referrer() const
4225 {
4226     return documentLoader()->request().httpReferrer();
4227 }
4228
4229
4230 } // namespace WebCore