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