2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "FrameLoader.h"
35 #include "ArchiveFactory.h"
38 #include "CachedPage.h"
40 #include "DOMImplementation.h"
41 #include "DOMWindow.h"
42 #include "DocLoader.h"
44 #include "DocumentLoader.h"
46 #include "EditorClient.h"
49 #include "EventNames.h"
50 #include "FloatRect.h"
51 #include "FormState.h"
53 #include "FrameLoadRequest.h"
54 #include "FrameLoaderClient.h"
55 #include "FrameTree.h"
56 #include "FrameView.h"
57 #include "HTMLAnchorElement.h"
58 #include "HTMLFormElement.h"
59 #include "HTMLFrameElement.h"
60 #include "HTMLNames.h"
61 #include "HTMLObjectElement.h"
62 #include "HTTPParsers.h"
63 #include "HistoryItem.h"
64 #include "IconDatabase.h"
65 #include "IconLoader.h"
66 #include "InspectorController.h"
68 #include "MIMETypeRegistry.h"
69 #include "MainResourceLoader.h"
71 #include "PageCache.h"
72 #include "PageGroup.h"
73 #include "PluginData.h"
74 #include "PluginDocument.h"
75 #include "ProgressTracker.h"
76 #include "RenderPart.h"
77 #include "RenderView.h"
78 #include "RenderWidget.h"
79 #include "ResourceHandle.h"
80 #include "ResourceRequest.h"
81 #include "ScriptController.h"
82 #include "ScriptSourceCode.h"
83 #include "ScriptValue.h"
84 #include "SecurityOrigin.h"
85 #include "SegmentedString.h"
87 #include "TextResourceDecoder.h"
88 #include "WindowFeatures.h"
89 #include "XMLHttpRequest.h"
90 #include "XMLTokenizer.h"
91 #include <wtf/CurrentTime.h>
92 #include <wtf/StdLibExtras.h>
94 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
95 #include "ApplicationCache.h"
96 #include "ApplicationCacheResource.h"
100 #include "SVGDocument.h"
101 #include "SVGLocatable.h"
102 #include "SVGNames.h"
103 #include "SVGPreserveAspectRatio.h"
104 #include "SVGSVGElement.h"
105 #include "SVGViewElement.h"
106 #include "SVGViewSpec.h"
112 using namespace SVGNames;
114 using namespace HTMLNames;
116 #if USE(LOW_BANDWIDTH_DISPLAY)
117 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
120 typedef HashSet<String, CaseFoldingHash> LocalSchemesMap;
122 struct FormSubmission {
123 FormSubmission(const char* action, const String& url, PassRefPtr<FormData> formData,
124 const String& target, const String& contentType, const String& boundary,
125 PassRefPtr<Event> event, bool lockHistory, bool lockBackForwardList)
130 , contentType(contentType)
133 , lockHistory(lockHistory)
134 , lockBackForwardList(lockBackForwardList)
140 RefPtr<FormData> formData;
146 bool lockBackForwardList;
149 struct ScheduledRedirection {
150 enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
157 bool lockBackForwardList;
161 ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
166 , lockHistory(lockHistory)
167 , lockBackForwardList(lockBackForwardList)
168 , wasUserGesture(wasUserGesture)
169 , wasRefresh(refresh)
173 ScheduledRedirection(Type locationChangeType, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
174 : type(locationChangeType)
179 , lockHistory(lockHistory)
180 , lockBackForwardList(lockBackForwardList)
181 , wasUserGesture(wasUserGesture)
182 , wasRefresh(refresh)
186 explicit ScheduledRedirection(int historyNavigationSteps)
187 : type(historyNavigation)
189 , historySteps(historyNavigationSteps)
191 , wasUserGesture(false)
197 static double storedTimeOfLastCompletedLoad;
198 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
200 bool isBackForwardLoadType(FrameLoadType type)
203 case FrameLoadTypeStandard:
204 case FrameLoadTypeReload:
205 case FrameLoadTypeReloadFromOrigin:
206 case FrameLoadTypeSame:
207 case FrameLoadTypeRedirectWithLockedBackForwardList:
208 case FrameLoadTypeReplace:
210 case FrameLoadTypeBack:
211 case FrameLoadTypeForward:
212 case FrameLoadTypeIndexedBackForward:
215 ASSERT_NOT_REACHED();
219 static int numRequests(Document* document)
224 return document->docLoader()->requestCount();
227 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
230 , m_state(FrameStateCommittedPage)
231 , m_loadType(FrameLoadTypeStandard)
232 , m_policyLoadType(FrameLoadTypeStandard)
233 , m_delegateIsHandlingProvisionalLoadError(false)
234 , m_delegateIsDecidingNavigationPolicy(false)
235 , m_delegateIsHandlingUnimplementablePolicy(false)
236 , m_firstLayoutDone(false)
237 , m_quickRedirectComing(false)
238 , m_sentRedirectNotification(false)
239 , m_inStopAllLoaders(false)
240 , m_navigationDuringLoad(false)
241 , m_isExecutingJavaScriptFormAction(false)
242 , m_isRunningScript(false)
243 , m_didCallImplicitClose(false)
244 , m_wasUnloadEventEmitted(false)
245 , m_isComplete(false)
246 , m_isLoadingMainResource(false)
247 , m_cancellingWithLoadInProgress(false)
248 , m_needsClear(false)
249 , m_receivedData(false)
250 , m_encodingWasChosenByUser(false)
251 , m_containsPlugIns(false)
252 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
253 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
254 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
256 , m_openedByDOM(false)
257 , m_creatingInitialEmptyDocument(false)
258 , m_isDisplayingInitialEmptyDocument(false)
259 , m_committedFirstRealDocumentLoad(false)
260 , m_didPerformFirstNavigation(false)
262 , m_didDispatchDidCommitLoad(false)
264 #if USE(LOW_BANDWIDTH_DISPLAY)
265 , m_useLowBandwidthDisplay(true)
266 , m_finishedParsingDuringLowBandwidthDisplay(false)
267 , m_needToSwitchOutLowBandwidthDisplay(false)
270 , m_forceReloadWmlDeck(false)
275 FrameLoader::~FrameLoader()
279 HashSet<Frame*>::iterator end = m_openedFrames.end();
280 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
281 (*it)->loader()->m_opener = 0;
283 m_client->frameLoaderDestroyed();
286 void FrameLoader::init()
288 // this somewhat odd set of steps is needed to give the frame an initial empty document
289 m_isDisplayingInitialEmptyDocument = false;
290 m_creatingInitialEmptyDocument = true;
291 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
292 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
293 setState(FrameStateProvisional);
294 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
295 m_provisionalDocumentLoader->finishedLoading();
296 begin(KURL(), false);
298 m_frame->document()->cancelParsing();
299 m_creatingInitialEmptyDocument = false;
300 m_didCallImplicitClose = true;
303 void FrameLoader::setDefersLoading(bool defers)
305 if (m_documentLoader)
306 m_documentLoader->setDefersLoading(defers);
307 if (m_provisionalDocumentLoader)
308 m_provisionalDocumentLoader->setDefersLoading(defers);
309 if (m_policyDocumentLoader)
310 m_policyDocumentLoader->setDefersLoading(defers);
313 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
315 ASSERT(!features.dialog || request.frameName().isEmpty());
317 if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
318 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
319 if (frame && shouldAllowNavigation(frame)) {
320 if (!request.resourceRequest().url().isEmpty())
321 frame->loader()->loadFrameRequestWithFormAndValues(request, false, false, 0, 0, HashMap<String, String>());
322 if (Page* page = frame->page())
323 page->chrome()->focus();
329 // FIXME: Setting the referrer should be the caller's responsibility.
330 FrameLoadRequest requestWithReferrer = request;
331 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
332 addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
334 Page* oldPage = m_frame->page();
338 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
342 Frame* frame = page->mainFrame();
343 if (request.frameName() != "_blank")
344 frame->tree()->setName(request.frameName());
346 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
347 page->chrome()->setStatusbarVisible(features.statusBarVisible);
348 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
349 page->chrome()->setMenubarVisible(features.menuBarVisible);
350 page->chrome()->setResizable(features.resizable);
352 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
353 // specify the size of the page. We can only resize the window, so
354 // adjust for the difference between the window size and the page size.
356 FloatRect windowRect = page->chrome()->windowRect();
357 FloatSize pageSize = page->chrome()->pageRect().size();
359 windowRect.setX(features.x);
361 windowRect.setY(features.y);
362 if (features.widthSet)
363 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
364 if (features.heightSet)
365 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
366 page->chrome()->setWindowRect(windowRect);
368 page->chrome()->show();
374 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
376 return m_client->canHandleRequest(request);
379 void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
381 changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, userGesture, refresh);
385 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
387 RefPtr<Frame> protect(m_frame);
389 ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
391 if (executeIfJavaScriptURL(request.url(), userGesture))
394 urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
397 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
399 FrameLoadRequest copy = request;
400 if (copy.resourceRequest().httpReferrer().isEmpty())
401 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
402 addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
404 loadFrameRequestWithFormAndValues(copy, lockHistory, lockBackForwardList, event, 0, HashMap<String, String>());
407 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
409 if (executeIfJavaScriptURL(request.url(), userGesture, false))
412 String target = _target;
413 if (target.isEmpty())
414 target = m_frame->document()->baseTarget();
416 FrameLoadRequest frameRequest(request, target);
418 urlSelected(frameRequest, triggeringEvent, lockHistory, lockBackForwardList);
421 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
423 #if USE(LOW_BANDWIDTH_DISPLAY)
424 // don't create sub-frame during low bandwidth display
425 if (frame()->document()->inLowBandwidthDisplay()) {
426 m_needToSwitchOutLowBandwidthDisplay = true;
431 // Support for <frame src="javascript:string">
434 if (protocolIs(urlString, "javascript")) {
435 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
438 url = completeURL(urlString);
440 Frame* frame = ownerElement->contentFrame();
442 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint());
444 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
449 if (!scriptURL.isEmpty())
450 frame->loader()->executeIfJavaScriptURL(scriptURL);
455 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
457 bool allowsScrolling = true;
458 int marginWidth = -1;
459 int marginHeight = -1;
460 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
461 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
462 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
463 marginWidth = o->getMarginWidth();
464 marginHeight = o->getMarginHeight();
467 if (!canLoad(url, referrer)) {
468 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
472 bool hideReferrer = shouldHideReferrer(url, referrer);
473 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
474 allowsScrolling, marginWidth, marginHeight);
477 checkCallImplicitClose();
481 frame->loader()->m_isComplete = false;
483 RenderObject* renderer = ownerElement->renderer();
484 FrameView* view = frame->view();
485 if (renderer && renderer->isWidget() && view)
486 static_cast<RenderWidget*>(renderer)->setWidget(view);
488 checkCallImplicitClose();
490 // In these cases, the synchronous load would have finished
491 // before we could connect the signals, so make sure to send the
492 // completed() signal for the child by hand
493 // FIXME: In this case the Frame will have finished loading before
494 // it's being added to the child list. It would be a good idea to
495 // create the child first, then invoke the loader separately.
496 if (url.isEmpty() || url == blankURL()) {
497 frame->loader()->completed();
498 frame->loader()->checkCompleted();
504 void FrameLoader::submitFormAgain()
506 if (m_isRunningScript)
508 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
511 submitForm(form->action, form->url, form->formData, form->target, form->contentType, form->boundary, form->event.get(), form->lockHistory, form->lockBackForwardList);
514 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
515 const String& target, const String& contentType, const String& boundary, Event* event, bool lockHistory, bool lockBackForwardList)
519 if (!m_frame->page())
522 KURL u = completeURL(url.isNull() ? "" : url);
523 // FIXME: Do we really need to special-case an empty URL?
524 // Would it be better to just go on with the form submisson and let the I/O fail?
528 if (u.protocolIs("javascript")) {
529 m_isExecutingJavaScriptFormAction = true;
530 executeIfJavaScriptURL(u, false, false);
531 m_isExecutingJavaScriptFormAction = false;
535 if (m_isRunningScript) {
536 if (m_deferredFormSubmission)
538 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, contentType, boundary, event, lockHistory, lockBackForwardList));
542 formData->generateFiles(m_frame->page()->chrome()->client());
544 FrameLoadRequest frameRequest;
546 if (!m_outgoingReferrer.isEmpty())
547 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
549 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
551 // Handle mailto: forms
552 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto");
553 if (isMailtoForm && strcmp(action, "GET") != 0) {
554 // Append body= for POST mailto, replace the whole query string for GET one.
555 String body = formData->flattenToString();
556 String query = u.query();
557 if (!query.isEmpty())
559 u.setQuery(query + body);
562 if (strcmp(action, "GET") == 0) {
563 u.setQuery(formData->flattenToString());
566 frameRequest.resourceRequest().setHTTPBody(formData.get());
567 frameRequest.resourceRequest().setHTTPMethod("POST");
569 // construct some user headers if necessary
570 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
571 frameRequest.resourceRequest().setHTTPContentType(contentType);
572 else // contentType must be "multipart/form-data"
573 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
576 frameRequest.resourceRequest().setURL(u);
577 addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
579 submitForm(frameRequest, event, lockHistory, lockBackForwardList);
582 void FrameLoader::stopLoading(bool sendUnload)
584 if (m_frame->document() && m_frame->document()->tokenizer())
585 m_frame->document()->tokenizer()->stopParsing();
588 if (m_frame->document()) {
589 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
590 Node* currentFocusedNode = m_frame->document()->focusedNode();
591 if (currentFocusedNode)
592 currentFocusedNode->aboutToUnload();
593 m_frame->document()->dispatchWindowEvent(eventNames().unloadEvent, false, false);
594 if (m_frame->document())
595 m_frame->document()->updateRendering();
596 m_wasUnloadEventEmitted = true;
597 if (m_frame->eventHandler()->pendingFrameUnloadEventCount())
598 m_frame->eventHandler()->clearPendingFrameUnloadEventCount();
599 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount())
600 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount();
603 if (m_frame->document() && !m_frame->document()->inPageCache())
604 m_frame->document()->removeAllEventListenersFromAllNodes();
607 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
608 m_isLoadingMainResource = false;
609 m_didCallImplicitClose = true; // don't want that one either
611 if (m_frame->document() && m_frame->document()->parsing()) {
613 m_frame->document()->setParsing(false);
616 m_workingURL = KURL();
618 if (Document* doc = m_frame->document()) {
619 if (DocLoader* docLoader = doc->docLoader())
620 cache()->loader()->cancelRequests(docLoader);
623 doc->stopDatabases();
627 // tell all subframes to stop as well
628 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
629 child->loader()->stopLoading(sendUnload);
633 #if USE(LOW_BANDWIDTH_DISPLAY)
634 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) {
635 // Since loading is forced to stop, reset the state without really switching.
636 m_needToSwitchOutLowBandwidthDisplay = false;
637 switchOutLowBandwidthDisplayIfReady();
642 void FrameLoader::stop()
644 // http://bugs.webkit.org/show_bug.cgi?id=10854
645 // The frame's last ref may be removed and it will be deleted by checkCompleted().
646 RefPtr<Frame> protector(m_frame);
648 if (m_frame->document()->tokenizer())
649 m_frame->document()->tokenizer()->stopParsing();
650 m_frame->document()->finishParsing();
653 m_iconLoader->stopLoading();
656 bool FrameLoader::closeURL()
660 m_frame->editor()->clearUndoRedoOperations();
664 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
666 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
668 stopRedirectionTimer();
670 m_scheduledRedirection.clear();
673 KURL FrameLoader::iconURL()
675 // If this isn't a top level frame, return nothing
676 if (m_frame->tree() && m_frame->tree()->parent())
679 // If we have an iconURL from a Link element, return that
680 if (!m_frame->document()->iconURL().isEmpty())
681 return KURL(m_frame->document()->iconURL());
683 // Don't return a favicon iconURL unless we're http or https
684 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https"))
688 url.setProtocol(m_URL.protocol());
689 url.setHost(m_URL.host());
690 if (int port = m_URL.port())
692 url.setPath("/favicon.ico");
696 bool FrameLoader::didOpenURL(const KURL& url)
698 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
699 // A redirect was scheduled before the document was created.
700 // This can happen when one frame changes another frame's location.
704 m_frame->editor()->clearLastEditCommand();
707 m_isComplete = false;
708 m_isLoadingMainResource = true;
709 m_didCallImplicitClose = false;
711 m_frame->setJSStatusBarText(String());
712 m_frame->setJSDefaultStatusBarText(String());
715 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
717 m_workingURL = m_URL;
724 void FrameLoader::didExplicitOpen()
726 m_isComplete = false;
727 m_didCallImplicitClose = false;
729 // Calling document.open counts as committing the first real document load.
730 m_committedFirstRealDocumentLoad = true;
732 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
733 // from a subsequent window.document.open / window.document.write call.
734 // Cancelling redirection here works for all cases because document.open
735 // implicitly precedes document.write.
737 if (m_frame->document()->url() != blankURL())
738 m_URL = m_frame->document()->url();
741 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
743 if (!url.protocolIs("javascript"))
746 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
747 ScriptValue result = executeScript(script, userGesture);
750 if (!result.getString(scriptResult))
753 SecurityOrigin* currentSecurityOrigin = 0;
754 currentSecurityOrigin = m_frame->document()->securityOrigin();
756 // FIXME: We should always replace the document, but doing so
757 // synchronously can cause crashes:
758 // http://bugs.webkit.org/show_bug.cgi?id=16782
759 if (replaceDocument) {
760 begin(m_URL, true, currentSecurityOrigin);
768 ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
770 return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
773 ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
775 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
776 return ScriptValue();
778 bool wasRunningScript = m_isRunningScript;
779 m_isRunningScript = true;
781 ScriptValue result = m_frame->script()->evaluate(sourceCode);
783 if (!wasRunningScript) {
784 m_isRunningScript = false;
786 Document::updateDocumentsRendering();
792 void FrameLoader::cancelAndClear()
800 m_frame->script()->updatePlatformScriptObjects();
803 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
805 m_frame->editor()->clear();
809 m_needsClear = false;
811 if (!m_frame->document()->inPageCache()) {
812 m_frame->document()->cancelParsing();
813 m_frame->document()->stopActiveDOMObjects();
814 if (m_frame->document()->attached()) {
815 m_frame->document()->willRemove();
816 m_frame->document()->detach();
818 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document());
822 // Do this after detaching the document so that the unload event works.
823 if (clearWindowProperties) {
824 m_frame->clearDOMWindow();
825 m_frame->script()->clearWindowShell();
828 m_frame->selection()->clear();
829 m_frame->eventHandler()->clear();
831 m_frame->view()->clear();
833 m_frame->setSelectionGranularity(CharacterGranularity);
835 // Do not drop the document before the ScriptController and view are cleared
836 // as some destructors might still try to access the document.
837 m_frame->setDocument(0);
840 m_containsPlugIns = false;
842 if (clearScriptObjects)
843 m_frame->script()->clearScriptObjects();
845 m_redirectionTimer.stop();
846 m_scheduledRedirection.clear();
848 m_checkCompletedTimer.stop();
849 m_checkLoadCompleteTimer.stop();
851 m_receivedData = false;
852 m_isDisplayingInitialEmptyDocument = false;
854 if (!m_encodingWasChosenByUser)
855 m_encoding = String();
858 void FrameLoader::receivedFirstData()
860 begin(m_workingURL, false);
862 dispatchDidCommitLoad();
863 dispatchWindowObjectAvailable();
865 String ptitle = m_documentLoader->title();
866 // If we have a title let the WebView know about it.
867 if (!ptitle.isNull())
868 m_client->dispatchDidReceiveTitle(ptitle);
870 m_workingURL = KURL();
874 if (!m_documentLoader)
876 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url))
880 url = m_URL.string();
882 url = m_frame->document()->completeURL(url).string();
884 scheduleHTTPRedirection(delay, url);
887 const String& FrameLoader::responseMIMEType() const
889 return m_responseMIMEType;
892 void FrameLoader::setResponseMIMEType(const String& type)
894 m_responseMIMEType = type;
897 void FrameLoader::begin()
902 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
904 // We need to take a reference to the security origin because |clear|
905 // might destroy the document that owns it.
906 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
908 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
909 clear(resetScripting, resetScripting);
911 m_frame->script()->updatePlatformScriptObjects();
914 m_isComplete = false;
915 m_didCallImplicitClose = false;
916 m_isLoadingMainResource = true;
917 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
920 ref.setUser(String());
921 ref.setPass(String());
922 ref.setRef(String());
923 m_outgoingReferrer = ref.string();
926 RefPtr<Document> document;
928 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
929 document = PluginDocument::create(m_frame);
931 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
932 m_frame->setDocument(document);
935 dispatchWindowObjectAvailable();
937 document->setURL(m_URL);
939 document->setDecoder(m_decoder.get());
940 if (forcedSecurityOrigin)
941 document->setSecurityOrigin(forcedSecurityOrigin.get());
943 m_frame->domWindow()->setURL(document->url());
944 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
946 updatePolicyBaseURL();
948 Settings* settings = document->settings();
949 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
951 if (m_documentLoader) {
952 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
953 if (!dnsPrefetchControl.isEmpty())
954 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
957 #if FRAME_LOADS_USER_STYLESHEET
958 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
959 if (!userStyleSheet.isEmpty())
960 m_frame->setUserStyleSheetLocation(userStyleSheet);
963 restoreDocumentState();
965 document->implicitOpen();
968 m_frame->view()->setContentsSize(IntSize());
970 #if USE(LOW_BANDWIDTH_DISPLAY)
971 // Low bandwidth display is a first pass display without external resources
972 // used to give an instant visual feedback. We currently only enable it for
973 // HTML documents in the top frame.
974 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
975 m_pendingSourceInLowBandwidthDisplay = String();
976 m_finishedParsingDuringLowBandwidthDisplay = false;
977 m_needToSwitchOutLowBandwidthDisplay = false;
978 document->setLowBandwidthDisplay(true);
983 void FrameLoader::write(const char* str, int len, bool flush)
985 if (len == 0 && !flush)
991 Tokenizer* tokenizer = m_frame->document()->tokenizer();
992 if (tokenizer && tokenizer->wantsRawData()) {
994 tokenizer->writeRawData(str, len);
999 Settings* settings = m_frame->settings();
1000 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
1001 if (m_encoding.isEmpty()) {
1002 Frame* parentFrame = m_frame->tree()->parent();
1003 if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin()))
1004 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::DefaultEncoding);
1006 m_decoder->setEncoding(m_encoding,
1007 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
1009 m_frame->document()->setDecoder(m_decoder.get());
1012 String decoded = m_decoder->decode(str, len);
1014 decoded += m_decoder->flush();
1015 if (decoded.isEmpty())
1018 #if USE(LOW_BANDWIDTH_DISPLAY)
1019 if (m_frame->document()->inLowBandwidthDisplay())
1020 m_pendingSourceInLowBandwidthDisplay.append(decoded);
1023 if (!m_receivedData) {
1024 m_receivedData = true;
1025 if (m_decoder->encoding().usesVisualOrdering())
1026 m_frame->document()->setVisuallyOrdered();
1027 m_frame->document()->recalcStyle(Node::Force);
1031 ASSERT(!tokenizer->wantsRawData());
1032 tokenizer->write(decoded, true);
1036 void FrameLoader::write(const String& str)
1041 if (!m_receivedData) {
1042 m_receivedData = true;
1043 m_frame->document()->setParseMode(Document::Strict);
1046 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1047 tokenizer->write(str, true);
1050 void FrameLoader::end()
1052 m_isLoadingMainResource = false;
1053 endIfNotLoadingMainResource();
1056 void FrameLoader::endIfNotLoadingMainResource()
1058 if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
1061 // http://bugs.webkit.org/show_bug.cgi?id=10854
1062 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1063 // so we'll add a protective refcount
1064 RefPtr<Frame> protector(m_frame);
1066 // make sure nothing's left in there
1068 m_frame->document()->finishParsing();
1069 #if USE(LOW_BANDWIDTH_DISPLAY)
1070 if (m_frame->document()->inLowBandwidthDisplay()) {
1071 m_finishedParsingDuringLowBandwidthDisplay = true;
1072 switchOutLowBandwidthDisplayIfReady();
1077 void FrameLoader::iconLoadDecisionAvailable()
1079 if (!m_mayLoadIconLater)
1081 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1083 m_mayLoadIconLater = false;
1086 void FrameLoader::startIconLoader()
1088 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1089 // But we should instead do it when we're done parsing the head element.
1090 if (!isLoadingMainFrame())
1093 if (!iconDatabase() || !iconDatabase()->isEnabled())
1096 KURL url(iconURL());
1097 String urlString(url.string());
1098 if (urlString.isEmpty())
1101 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1102 if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
1103 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1104 if (decision == IconLoadNo) {
1105 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1106 commitIconURLToIconDatabase(url);
1108 // We were told not to load this icon - that means this icon is already known by the database
1109 // If the icon data hasn't been read in from disk yet, kick off the read of the icon from the database to make sure someone
1110 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1111 // Otherwise if the icon data *is* available, notify the delegate
1112 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1113 LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data());
1114 m_client->registerForIconNotification();
1115 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0));
1116 iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0));
1118 m_client->dispatchDidReceiveIcon();
1123 if (decision == IconLoadUnknown) {
1124 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1125 // just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal
1126 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1127 // icon is later read in from disk
1128 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1129 m_mayLoadIconLater = true;
1130 m_client->registerForIconNotification();
1131 commitIconURLToIconDatabase(url);
1136 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1138 m_iconLoader.set(IconLoader::create(m_frame).release());
1140 m_iconLoader->startLoading();
1143 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy)
1145 localLoadPolicy = policy;
1148 bool FrameLoader::restrictAccessToLocal()
1150 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll;
1153 bool FrameLoader::allowSubstituteDataAccessToLocal()
1155 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
1158 static LocalSchemesMap& localSchemes()
1160 DEFINE_STATIC_LOCAL(LocalSchemesMap, localSchemes, ());
1162 if (localSchemes.isEmpty()) {
1163 localSchemes.add("file");
1165 localSchemes.add("applewebdata");
1168 localSchemes.add("qrc");
1172 return localSchemes;
1175 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1177 ASSERT(iconDatabase());
1178 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestURL().string().ascii().data());
1179 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string());
1180 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string());
1183 void FrameLoader::restoreDocumentState()
1185 Document* doc = m_frame->document();
1187 HistoryItem* itemToRestore = 0;
1189 switch (loadType()) {
1190 case FrameLoadTypeReload:
1191 case FrameLoadTypeReloadFromOrigin:
1192 case FrameLoadTypeSame:
1193 case FrameLoadTypeReplace:
1195 case FrameLoadTypeBack:
1196 case FrameLoadTypeForward:
1197 case FrameLoadTypeIndexedBackForward:
1198 case FrameLoadTypeRedirectWithLockedBackForwardList:
1199 case FrameLoadTypeStandard:
1200 itemToRestore = m_currentHistoryItem.get();
1206 LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
1207 doc->setStateForNewFormElements(itemToRestore->documentState());
1210 void FrameLoader::gotoAnchor()
1212 // If our URL has no ref, then we have no place we need to jump to.
1213 // OTOH If CSS target was set previously, we want to set it to 0, recalc
1214 // and possibly repaint because :target pseudo class may have been
1215 // set (see bug 11321).
1216 if (!m_URL.hasRef() && !m_frame->document()->cssTarget())
1219 String ref = m_URL.ref();
1220 if (gotoAnchor(ref))
1223 // Try again after decoding the ref, based on the document's encoding.
1225 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding()));
1228 void FrameLoader::finishedParsing()
1230 if (m_creatingInitialEmptyDocument)
1233 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1234 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1235 // Null-checking the FrameView indicates whether or not we're in the destructor.
1236 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
1238 m_client->dispatchDidFinishDocumentLoad();
1242 if (!m_frame->view())
1243 return; // We are being destroyed by something checkCompleted called.
1245 // Check if the scrollbars are really needed for the content.
1246 // If not, remove them, relayout, and repaint.
1247 m_frame->view()->restoreScrollbar();
1252 void FrameLoader::loadDone()
1257 void FrameLoader::checkCompleted()
1259 // Any frame that hasn't completed yet?
1260 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1261 if (!child->loader()->m_isComplete)
1264 // Have we completed before?
1268 // Are we still parsing?
1269 if (m_frame->document()->parsing())
1272 // Still waiting for images/scripts?
1273 if (numRequests(m_frame->document()))
1276 #if USE(LOW_BANDWIDTH_DISPLAY)
1277 // as switch will be called, don't complete yet
1278 if (m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay)
1283 m_isComplete = true;
1285 RefPtr<Frame> protect(m_frame);
1286 checkCallImplicitClose(); // if we didn't do it before
1288 // Do not start a redirection timer for subframes here.
1289 // That is deferred until the parent is completed.
1290 if (m_scheduledRedirection && !m_frame->tree()->parent())
1291 startRedirectionTimer();
1294 if (m_frame->page())
1295 checkLoadComplete();
1298 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1303 void FrameLoader::scheduleCheckCompleted()
1305 if (!m_checkCompletedTimer.isActive())
1306 m_checkCompletedTimer.startOneShot(0);
1309 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1311 if (!m_frame->page())
1313 checkLoadComplete();
1316 void FrameLoader::scheduleCheckLoadComplete()
1318 if (!m_checkLoadCompleteTimer.isActive())
1319 m_checkLoadCompleteTimer.startOneShot(0);
1322 void FrameLoader::checkCallImplicitClose()
1324 if (m_didCallImplicitClose || m_frame->document()->parsing())
1327 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1328 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1331 m_didCallImplicitClose = true;
1332 m_wasUnloadEventEmitted = false;
1333 m_frame->document()->implicitClose();
1336 KURL FrameLoader::baseURL() const
1338 ASSERT(m_frame->document());
1339 return m_frame->document()->baseURL();
1342 String FrameLoader::baseTarget() const
1344 ASSERT(m_frame->document());
1345 return m_frame->document()->baseTarget();
1348 KURL FrameLoader::completeURL(const String& url)
1350 ASSERT(m_frame->document());
1351 return m_frame->document()->completeURL(url);
1354 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1356 if (delay < 0 || delay > INT_MAX / 1000)
1359 if (!m_frame->page())
1362 // We want a new history item if the refresh timeout is > 1 second.
1363 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1364 scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
1367 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
1369 if (!m_frame->page())
1372 // If the URL we're going to navigate to is the same as the current one, except for the
1373 // fragment part, we don't need to schedule the location change.
1374 KURL parsedURL(url);
1375 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) {
1376 changeLocation(url, referrer, lockHistory, lockBackForwardList, wasUserGesture);
1380 // Handle a location change of a page with no document as a special case.
1381 // This may happen when a frame changes the location of another frame.
1382 bool duringLoad = !m_committedFirstRealDocumentLoad;
1384 // If a redirect was scheduled during a load, then stop the current load.
1385 // Otherwise when the current load transitions from a provisional to a
1386 // committed state, pending redirects may be cancelled.
1388 if (m_provisionalDocumentLoader)
1389 m_provisionalDocumentLoader->stopLoading();
1393 ScheduledRedirection::Type type = duringLoad
1394 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1395 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false));
1398 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1400 if (!m_frame->page())
1403 ScheduledRedirection::Type type = ScheduledRedirection::locationChange;
1404 scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true));
1407 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1409 switch (redirection.type) {
1410 case ScheduledRedirection::redirection:
1412 case ScheduledRedirection::historyNavigation:
1413 case ScheduledRedirection::locationChange:
1414 case ScheduledRedirection::locationChangeDuringLoad:
1417 ASSERT_NOT_REACHED();
1421 void FrameLoader::scheduleHistoryNavigation(int steps)
1423 if (!m_frame->page())
1426 // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.
1427 if (!canGoBackOrForward(steps)) {
1428 cancelRedirection();
1432 // If the steps to navigate is not zero (which needs to force a reload), and if we think the navigation is going to be a fragment load
1433 // (when the URL we're going to navigate to is the same as the current one, except for the fragment part - but not exactly the same because that's a reload),
1434 // then we don't need to schedule the navigation.
1436 KURL destination = historyURL(steps);
1437 // FIXME: This doesn't seem like a reliable way to tell whether or not the load will be a fragment load.
1438 if (equalIgnoringRef(m_URL, destination) && m_URL != destination) {
1439 goBackOrForward(steps);
1444 scheduleRedirection(new ScheduledRedirection(steps));
1447 void FrameLoader::goBackOrForward(int distance)
1452 Page* page = m_frame->page();
1455 BackForwardList* list = page->backForwardList();
1459 HistoryItem* item = list->itemAtIndex(distance);
1462 int forwardListCount = list->forwardListCount();
1463 if (forwardListCount > 0)
1464 item = list->itemAtIndex(forwardListCount);
1466 int backListCount = list->backListCount();
1467 if (backListCount > 0)
1468 item = list->itemAtIndex(-backListCount);
1472 ASSERT(item); // we should not reach this line with an empty back/forward list
1474 page->goToItem(item, FrameLoadTypeIndexedBackForward);
1477 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1479 ASSERT(m_frame->page());
1481 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1483 switch (redirection->type) {
1484 case ScheduledRedirection::redirection:
1485 case ScheduledRedirection::locationChange:
1486 case ScheduledRedirection::locationChangeDuringLoad:
1487 changeLocation(redirection->url, redirection->referrer,
1488 redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh);
1490 case ScheduledRedirection::historyNavigation:
1491 if (redirection->historySteps == 0) {
1492 // Special case for go(0) from a frame -> reload only the frame
1493 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture);
1496 // go(i!=0) from a frame navigates into the history of the frame only,
1497 // in both IE and NS (but not in Mozilla). We can't easily do that.
1498 goBackOrForward(redirection->historySteps);
1502 ASSERT_NOT_REACHED();
1506 In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree.
1507 The item that was the target of the user's navigation is designated as the "targetItem".
1508 When this method is called with doClip=YES we're able to create the whole tree except for the target's children,
1509 which will be loaded in the future. That part of the tree will be filled out as the child loads are committed.
1511 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame)
1514 HistoryItem* parentItem = currentHistoryItem();
1515 FrameLoadType loadType = this->loadType();
1516 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
1518 KURL workingURL = url;
1520 // If we're moving in the backforward list, we might want to replace the content
1521 // of this child frame with whatever was there at that point.
1522 if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
1523 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
1525 // Use the original URL to ensure we get all the side-effects, such as
1526 // onLoad handlers, of any redirects that happened. An example of where
1527 // this is needed is Radar 3213556.
1528 workingURL = KURL(childItem->originalURLString());
1529 childLoadType = loadType;
1530 childFrame->loader()->setProvisionalHistoryItem(childItem);
1534 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
1536 if (subframeArchive)
1537 childFrame->loader()->loadArchive(subframeArchive.release());
1539 childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
1542 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
1544 RefPtr<Archive> archive = prpArchive;
1546 ArchiveResource* mainResource = archive->mainResource();
1547 ASSERT(mainResource);
1551 SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
1553 ResourceRequest request(mainResource->url());
1555 request.applyWebArchiveHackForMail();
1558 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData);
1559 documentLoader->addAllArchiveResources(archive.get());
1560 load(documentLoader.get());
1563 String FrameLoader::encoding() const
1565 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1567 if (m_decoder && m_decoder->encoding().isValid())
1568 return m_decoder->encoding().name();
1569 Settings* settings = m_frame->settings();
1570 return settings ? settings->defaultTextEncodingName() : String();
1573 bool FrameLoader::gotoAnchor(const String& name)
1575 ASSERT(m_frame->document());
1577 if (!m_frame->document()->haveStylesheetsLoaded()) {
1578 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1582 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1584 Element* anchorNode = m_frame->document()->findAnchor(name);
1587 if (m_frame->document()->isSVGDocument()) {
1588 if (name.startsWith("xpointer(")) {
1589 // We need to parse the xpointer reference here
1590 } else if (name.startsWith("svgView(")) {
1591 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1592 if (!svg->currentView()->parseViewSpec(name))
1594 svg->setUseCurrentView(true);
1596 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1597 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1598 if (viewElement.get()) {
1599 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1600 svg->inheritViewAttributes(viewElement.get());
1604 // FIXME: need to decide which <svg> to focus on, and zoom to that one
1605 // FIXME: need to actually "highlight" the viewTarget(s)
1609 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1611 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1612 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1615 // We need to update the layout before scrolling, otherwise we could
1616 // really mess things up if an anchor scroll comes at a bad moment.
1617 m_frame->document()->updateRendering();
1618 // Only do a layout if changes have occurred that make it necessary.
1619 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
1620 m_frame->view()->layout();
1622 // Scroll nested layers and frames to reveal the anchor.
1623 // Align to the top and to the closest side (this matches other browsers).
1624 RenderObject* renderer;
1627 renderer = m_frame->document()->renderer(); // top of document
1629 renderer = anchorNode->renderer();
1630 rect = anchorNode->getRect();
1633 renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1638 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1639 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1641 if (url.isEmpty() && mimeType.isEmpty())
1644 #if USE(LOW_BANDWIDTH_DISPLAY)
1645 // don't care object during low bandwidth display
1646 if (frame()->document()->inLowBandwidthDisplay()) {
1647 m_needToSwitchOutLowBandwidthDisplay = true;
1654 completedURL = completeURL(url);
1657 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1658 Settings* settings = m_frame->settings();
1659 if (!settings || !settings->arePluginsEnabled() ||
1660 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1662 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1665 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1666 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1668 // FIXME: OK to always make a new frame? When does the old frame get removed?
1669 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1672 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1674 if (m_client->shouldUsePluginDocument(mimeType)) {
1675 useFallback = false;
1679 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
1680 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
1681 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
1682 const PluginData* pluginData = m_frame->page()->pluginData();
1683 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
1684 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
1688 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1689 // If an object's content can't be handled and it has no fallback, let
1690 // it be handled as a plugin to show the broken plugin icon.
1691 useFallback = objectType == ObjectContentNone && hasFallback;
1692 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1695 static HTMLPlugInElement* toPlugInElement(Node* node)
1700 ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
1701 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
1702 || node->hasTagName(videoTag) || node->hasTagName(audioTag)
1704 || node->hasTagName(appletTag));
1706 return static_cast<HTMLPlugInElement*>(node);
1709 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1710 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1714 if (renderer && !useFallback) {
1715 HTMLPlugInElement* element = toPlugInElement(renderer->node());
1717 if (!canLoad(url, String(), frame()->document())) {
1718 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
1722 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1723 element, url, paramNames, paramValues, mimeType,
1724 m_frame->document()->isPluginDocument());
1726 renderer->setWidget(widget);
1727 m_containsPlugIns = true;
1734 void FrameLoader::clearRecordedFormValues()
1736 m_formAboutToBeSubmitted = 0;
1737 m_formValuesAboutToBeSubmitted.clear();
1740 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element)
1742 m_formAboutToBeSubmitted = element;
1745 void FrameLoader::recordFormValue(const String& name, const String& value)
1747 m_formValuesAboutToBeSubmitted.set(name, value);
1750 void FrameLoader::parentCompleted()
1752 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1753 startRedirectionTimer();
1756 String FrameLoader::outgoingReferrer() const
1758 return m_outgoingReferrer;
1761 String FrameLoader::outgoingOrigin() const
1763 return m_frame->document()->securityOrigin()->toString();
1766 Frame* FrameLoader::opener()
1771 void FrameLoader::setOpener(Frame* opener)
1774 m_opener->loader()->m_openedFrames.remove(m_frame);
1776 opener->loader()->m_openedFrames.add(m_frame);
1779 if (m_frame->document()) {
1780 m_frame->document()->initSecurityContext();
1781 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin());
1785 bool FrameLoader::openedByDOM() const
1787 return m_openedByDOM;
1790 void FrameLoader::setOpenedByDOM()
1792 m_openedByDOM = true;
1795 void FrameLoader::handleFallbackContent()
1797 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1798 if (!owner || !owner->hasTagName(objectTag))
1800 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1803 void FrameLoader::provisionalLoadStarted()
1805 Page* page = m_frame->page();
1807 // this is used to update the current history item
1808 // in the event of a navigation aytime during loading
1809 m_navigationDuringLoad = false;
1811 Document *document = page->mainFrame()->document();
1812 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1815 m_firstLayoutDone = false;
1816 cancelRedirection(true);
1817 m_client->provisionalLoadStarted();
1820 bool FrameLoader::userGestureHint()
1822 Frame* frame = m_frame->tree()->top();
1823 if (!frame->script()->isEnabled())
1824 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
1825 return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
1828 void FrameLoader::didNotOpenURL(const KURL& url)
1830 if (m_submittedFormURL == url)
1831 m_submittedFormURL = KURL();
1834 void FrameLoader::resetMultipleFormSubmissionProtection()
1836 m_submittedFormURL = KURL();
1839 void FrameLoader::setEncoding(const String& name, bool userChosen)
1841 if (!m_workingURL.isEmpty())
1842 receivedFirstData();
1844 m_encodingWasChosenByUser = userChosen;
1847 void FrameLoader::addData(const char* bytes, int length)
1849 ASSERT(m_workingURL.isEmpty());
1850 ASSERT(m_frame->document());
1851 ASSERT(m_frame->document()->parsing());
1852 write(bytes, length);
1855 bool FrameLoader::canCachePageContainingThisFrame()
1857 return m_documentLoader
1858 && m_documentLoader->mainDocumentError().isNull()
1859 && !m_frame->tree()->childCount()
1860 // FIXME: If we ever change this so that frames with plug-ins will be cached,
1861 // we need to make sure that we don't cache frames that have outstanding NPObjects
1862 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1863 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1864 // the right NPObjects. See <rdar://problem/5197041> for more information.
1865 && !m_containsPlugIns
1866 && !m_URL.protocolIs("https")
1867 && !m_frame->document()->hasWindowEventListener(eventNames().unloadEvent)
1868 #if ENABLE(DATABASE)
1869 && !m_frame->document()->hasOpenDatabases()
1871 && !m_frame->document()->usingGeolocation()
1872 && m_currentHistoryItem
1873 && !isQuickRedirectComing()
1874 && !m_documentLoader->isLoadingInAPISense()
1875 && !m_documentLoader->isStopping()
1876 && m_frame->document()->canSuspendActiveDOMObjects()
1877 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
1878 // FIXME: We should investigating caching frames that have an associated
1879 // application cache. <rdar://problem/5917899> tracks that work.
1880 && !m_documentLoader->applicationCache()
1881 && !m_documentLoader->candidateApplicationCacheGroup()
1883 && m_client->canCachePage()
1887 bool FrameLoader::canCachePage()
1890 logCanCachePageDecision();
1893 // Cache the page, if possible.
1894 // Don't write to the cache if in the middle of a redirect, since we will want to
1895 // store the final page we end up on.
1896 // No point writing to the cache on a reload or loadSame, since we will just write
1897 // over it again when we leave that page.
1898 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1899 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1900 FrameLoadType loadType = this->loadType();
1902 return !m_frame->tree()->parent()
1903 && canCachePageContainingThisFrame()
1905 && m_frame->page()->backForwardList()->enabled()
1906 && m_frame->page()->backForwardList()->capacity() > 0
1907 && m_frame->page()->settings()->usesPageCache()
1908 && loadType != FrameLoadTypeReload
1909 && loadType != FrameLoadTypeReloadFromOrigin
1910 && loadType != FrameLoadTypeSame
1915 static String& pageCacheLogPrefix(int indentLevel)
1917 static int previousIndent = -1;
1918 DEFINE_STATIC_LOCAL(String, prefix, ());
1920 if (indentLevel != previousIndent) {
1921 previousIndent = indentLevel;
1923 for (int i = 0; i < previousIndent; ++i)
1930 static void pageCacheLog(const String& prefix, const String& message)
1932 LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
1935 #define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
1937 void FrameLoader::logCanCachePageDecision()
1939 // Only bother logging for main frames that have actually loaded and have content.
1940 if (m_creatingInitialEmptyDocument)
1942 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1943 if (currentURL.isEmpty())
1946 int indentLevel = 0;
1947 PCLOG("--------\n Determining if page can be cached:");
1949 bool cannotCache = !logCanCacheFrameDecision(1);
1951 FrameLoadType loadType = this->loadType();
1953 if (m_frame->tree()->parent())
1954 { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
1955 if (!m_frame->page()) {
1956 PCLOG(" -There is no Page object");
1960 if (!m_frame->page()->backForwardList()->enabled())
1961 { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
1962 if (!(m_frame->page()->backForwardList()->capacity() > 0))
1963 { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
1964 if (!m_frame->page()->settings()->usesPageCache())
1965 { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
1966 if (loadType == FrameLoadTypeReload)
1967 { PCLOG(" -Load type is: Reload"); cannotCache = true; }
1968 if (loadType == FrameLoadTypeReloadFromOrigin)
1969 { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
1970 if (loadType == FrameLoadTypeSame)
1971 { PCLOG(" -Load type is: Same"); cannotCache = true; }
1974 PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
1977 bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
1979 // Only bother logging for frames that have actually loaded and have content.
1980 if (m_creatingInitialEmptyDocument)
1982 KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
1983 if (currentURL.isEmpty())
1987 KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
1988 if (!newURL.isEmpty())
1989 PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
1991 PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
1993 bool cannotCache = false;
1996 if (!m_documentLoader) {
1997 PCLOG(" -There is no DocumentLoader object");
2001 if (!m_documentLoader->mainDocumentError().isNull())
2002 { PCLOG(" -Main document has an error"); cannotCache = true; }
2003 if (m_frame->tree()->childCount())
2004 { PCLOG(" -Frame has child frames"); cannotCache = true; }
2005 if (m_containsPlugIns)
2006 { PCLOG(" -Frame contains plugins"); cannotCache = true; }
2007 if (m_URL.protocolIs("https"))
2008 { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
2009 if (m_frame->document()->hasWindowEventListener(eventNames().unloadEvent))
2010 { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
2011 #if ENABLE(DATABASE)
2012 if (m_frame->document()->hasOpenDatabases())
2013 { PCLOG(" -Frame has open database handles"); cannotCache = true; }
2015 if (m_frame->document()->usingGeolocation())
2016 { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
2017 if (!m_currentHistoryItem)
2018 { PCLOG(" -No current history item"); cannotCache = true; }
2019 if (isQuickRedirectComing())
2020 { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
2021 if (m_documentLoader->isLoadingInAPISense())
2022 { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
2023 if (m_documentLoader->isStopping())
2024 { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
2025 if (!m_frame->document()->canSuspendActiveDOMObjects())
2026 { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
2027 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2028 if (m_documentLoader->applicationCache())
2029 { PCLOG(" -The DocumentLoader has an active application cache"); cannotCache = true; }
2030 if (m_documentLoader->candidateApplicationCacheGroup())
2031 { PCLOG(" -The DocumentLoader has a candidateApplicationCacheGroup"); cannotCache = true; }
2033 if (!m_client->canCachePage())
2034 { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
2037 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2038 if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
2041 PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
2044 return !cannotCache;
2048 void FrameLoader::updatePolicyBaseURL()
2050 if (m_frame->tree()->parent())
2051 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
2053 setPolicyBaseURL(m_URL);
2056 void FrameLoader::setPolicyBaseURL(const KURL& url)
2058 m_frame->document()->setPolicyBaseURL(url);
2059 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2060 child->loader()->setPolicyBaseURL(url);
2063 // This does the same kind of work that didOpenURL does, except it relies on the fact
2064 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
2065 void FrameLoader::scrollToAnchor(const KURL& url)
2068 updateHistoryForAnchorScroll();
2070 // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
2071 m_frame->eventHandler()->stopAutoscrollTimer();
2075 // It's important to model this as a load that starts and immediately finishes.
2076 // Otherwise, the parent frame may think we never finished loading.
2077 m_isComplete = false;
2081 bool FrameLoader::isComplete() const
2083 return m_isComplete;
2086 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
2088 ASSERT(m_frame->page());
2090 stopRedirectionTimer();
2091 m_scheduledRedirection.set(redirection);
2092 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
2094 if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
2095 startRedirectionTimer();
2098 void FrameLoader::startRedirectionTimer()
2100 ASSERT(m_frame->page());
2101 ASSERT(m_scheduledRedirection);
2103 m_redirectionTimer.stop();
2104 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
2106 switch (m_scheduledRedirection->type) {
2107 case ScheduledRedirection::redirection:
2108 case ScheduledRedirection::locationChange:
2109 case ScheduledRedirection::locationChangeDuringLoad:
2110 clientRedirected(KURL(m_scheduledRedirection->url),
2111 m_scheduledRedirection->delay,
2112 currentTime() + m_redirectionTimer.nextFireInterval(),
2113 m_scheduledRedirection->lockBackForwardList,
2114 m_isExecutingJavaScriptFormAction);
2116 case ScheduledRedirection::historyNavigation:
2117 // Don't report history navigations.
2120 ASSERT_NOT_REACHED();
2123 void FrameLoader::stopRedirectionTimer()
2125 if (!m_redirectionTimer.isActive())
2128 m_redirectionTimer.stop();
2130 if (m_scheduledRedirection) {
2131 switch (m_scheduledRedirection->type) {
2132 case ScheduledRedirection::redirection:
2133 case ScheduledRedirection::locationChange:
2134 case ScheduledRedirection::locationChangeDuringLoad:
2135 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
2137 case ScheduledRedirection::historyNavigation:
2138 // Don't report history navigations.
2141 ASSERT_NOT_REACHED();
2145 void FrameLoader::completed()
2147 RefPtr<Frame> protect(m_frame);
2148 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2149 child->loader()->parentCompleted();
2150 if (Frame* parent = m_frame->tree()->parent())
2151 parent->loader()->checkCompleted();
2155 void FrameLoader::started()
2157 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
2158 frame->loader()->m_isComplete = false;
2161 bool FrameLoader::containsPlugins() const
2163 return m_containsPlugIns;
2166 void FrameLoader::prepareForLoadStart()
2168 if (Page* page = m_frame->page())
2169 page->progress()->progressStarted(m_frame);
2170 m_client->dispatchDidStartProvisionalLoad();
2173 void FrameLoader::setupForReplace()
2175 setState(FrameStateProvisional);
2176 m_provisionalDocumentLoader = m_documentLoader;
2177 m_documentLoader = 0;
2181 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
2183 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
2186 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, Event* event,
2187 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
2189 RefPtr<FormState> formState;
2191 formState = FormState::create(submitForm, formValues, m_frame);
2193 KURL url = request.resourceRequest().url();
2196 String argsReferrer = request.resourceRequest().httpReferrer();
2197 if (!argsReferrer.isEmpty())
2198 referrer = argsReferrer;
2200 referrer = m_outgoingReferrer;
2202 ASSERT(frame()->document());
2203 if (url.protocolIs("file")) {
2204 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
2205 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
2210 if (shouldHideReferrer(url, referrer))
2211 referrer = String();
2213 FrameLoadType loadType;
2214 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
2215 loadType = FrameLoadTypeReload;
2216 else if (lockBackForwardList)
2217 loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
2219 loadType = FrameLoadTypeStandard;
2221 if (request.resourceRequest().httpMethod() == "POST")
2222 loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2224 loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
2226 Frame* targetFrame = findFrameForNavigation(request.frameName());
2227 if (targetFrame && targetFrame != m_frame)
2228 if (Page* page = targetFrame->page())
2229 page->chrome()->focus();
2232 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
2233 Event* event, PassRefPtr<FormState> prpFormState)
2235 RefPtr<FormState> formState = prpFormState;
2236 bool isFormSubmission = formState;
2238 ResourceRequest request(newURL);
2239 if (!referrer.isEmpty()) {
2240 request.setHTTPReferrer(referrer);
2241 RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
2242 addHTTPOriginIfNeeded(request, referrerOrigin->toString());
2244 addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
2245 if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
2246 request.setCachePolicy(ReloadIgnoringCacheData);
2248 ASSERT(newLoadType != FrameLoadTypeSame);
2250 NavigationAction action(newURL, newLoadType, isFormSubmission, event);
2252 if (!frameName.isEmpty()) {
2253 if (Frame* targetFrame = findFrameForNavigation(frameName))
2254 targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState);
2256 checkNewWindowPolicy(action, request, formState, frameName);
2260 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2262 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL);
2264 // Make sure to do scroll to anchor processing even if the URL is
2265 // exactly the same so pages with '#' links and DHTML side effects
2267 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
2268 oldDocumentLoader->setTriggeringAction(action);
2270 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2271 callContinueFragmentScrollAfterNavigationPolicy, this);
2273 // must grab this now, since this load may stop the previous load and clear this flag
2274 bool isRedirect = m_quickRedirectComing;
2275 loadWithNavigationAction(request, action, lockHistory, newLoadType, formState);
2277 m_quickRedirectComing = false;
2278 if (m_provisionalDocumentLoader)
2279 m_provisionalDocumentLoader->setIsClientRedirect(true);
2281 // Example of this case are sites that reload the same URL with a different cookie
2282 // driving the generated content, or a master frame with links that drive a target
2283 // frame, where the user has clicked on the same link repeatedly.
2284 m_loadType = FrameLoadTypeSame;
2288 void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
2290 load(request, SubstituteData(), lockHistory);
2293 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
2295 if (m_inStopAllLoaders)
2298 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2299 m_loadType = FrameLoadTypeStandard;
2300 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
2301 if (lockHistory && m_documentLoader)
2302 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2306 void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
2308 if (frameName.isEmpty()) {
2309 load(request, lockHistory);
2313 Frame* frame = findFrameForNavigation(frameName);
2315 frame->loader()->load(request, lockHistory);
2319 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2322 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
2324 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2325 if (lockHistory && m_documentLoader)
2326 loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory() : m_documentLoader->clientRedirectSourceForHistory());
2328 loader->setTriggeringAction(action);
2329 if (m_documentLoader)
2330 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2332 loadWithDocumentLoader(loader.get(), type, formState);
2335 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2337 ResourceRequest& r = newDocumentLoader->request();
2338 addExtraFieldsToMainResourceRequest(r);
2341 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2342 r.setCachePolicy(ReloadIgnoringCacheData);
2343 type = FrameLoadTypeSame;
2345 type = FrameLoadTypeStandard;
2347 if (m_documentLoader)
2348 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2350 // When we loading alternate content for an unreachable URL that we're
2351 // visiting in the history list, we treat it as a reload so the history list
2352 // is appropriately maintained.
2354 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
2355 // shouldn't a more explicit type of reload be defined, that means roughly
2356 // "load without affecting history" ?
2357 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2358 ASSERT(type == FrameLoadTypeStandard);
2359 type = FrameLoadTypeReload;
2362 loadWithDocumentLoader(newDocumentLoader, type, 0);
2365 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
2367 ASSERT(m_client->hasWebView());
2369 // Unfortunately the view must be non-nil, this is ultimately due
2370 // to parser requiring a FrameView. We should fix this dependency.
2372 ASSERT(m_frame->view());
2374 m_policyLoadType = type;
2375 RefPtr<FormState> formState = prpFormState;
2376 bool isFormSubmission = formState;
2378 const KURL& newURL = loader->request().url();
2380 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
2381 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2382 NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
2384 oldDocumentLoader->setTriggeringAction(action);
2386 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
2387 callContinueFragmentScrollAfterNavigationPolicy, this);
2389 if (Frame* parent = m_frame->tree()->parent())
2390 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2393 setPolicyDocumentLoader(loader);
2395 checkNavigationPolicy(loader->request(), loader, formState,
2396 callContinueLoadAfterNavigationPolicy, this);
2400 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc)
2402 // We can always load any URL that isn't considered local (e.g. http URLs)
2403 if (!shouldTreatURLAsLocal(url.string()))
2406 // If we were provided a document, we let its local file policy dictate the result,
2407 // otherwise we allow local loads only if the supplied referrer is also local.
2409 return doc->securityOrigin()->canLoadLocalResources();
2410 else if (!referrer.isEmpty())
2411 return shouldTreatURLAsLocal(referrer);
2416 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url)
2418 ASSERT(!url.isEmpty());
2422 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2425 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2427 bool referrerIsSecureURL = protocolIs(referrer, "https");
2428 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
2430 if (!referrerIsWebURL)
2433 if (!referrerIsSecureURL)
2436 bool URLIsSecureURL = url.protocolIs("https");
2438 return !URLIsSecureURL;
2441 const ResourceRequest& FrameLoader::initialRequest() const
2443 return activeDocumentLoader()->originalRequest();
2446 void FrameLoader::receivedData(const char* data, int length)
2448 activeDocumentLoader()->receivedData(data, length);
2451 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2453 m_delegateIsHandlingUnimplementablePolicy = true;
2454 m_client->dispatchUnableToImplementPolicy(error);
2455 m_delegateIsHandlingUnimplementablePolicy = false;
2458 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2460 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2463 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2465 return m_client->interruptForPolicyChangeError(request);
2468 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2470 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2473 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2475 ASSERT(activeDocumentLoader());
2477 // Always show content with valid substitute data.
2478 if (activeDocumentLoader()->substituteData().isValid()) {
2479 function(argument, PolicyUse);
2484 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2485 Settings* settings = m_frame->settings();
2486 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2487 function(argument, PolicyUse);
2492 m_policyCheck.set(function, argument);
2493 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2494 MIMEType, activeDocumentLoader()->request());
2497 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2499 KURL unreachableURL = docLoader->unreachableURL();
2501 if (unreachableURL.isEmpty())
2504 if (!isBackForwardLoadType(m_policyLoadType))
2507 // We only treat unreachableURLs specially during the delegate callbacks
2508 // for provisional load errors and navigation policy decisions. The former
2509 // case handles well-formed URLs that can't be loaded, and the latter
2510 // case handles malformed URLs and unknown schemes. Loading alternate content
2511 // at other times behaves like a standard load.
2512 DocumentLoader* compareDocumentLoader = 0;
2513 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2514 compareDocumentLoader = m_policyDocumentLoader.get();
2515 else if (m_delegateIsHandlingProvisionalLoadError)
2516 compareDocumentLoader = m_provisionalDocumentLoader.get();
2518 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2521 void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
2523 if (!m_documentLoader)
2526 ResourceRequest request = m_documentLoader->request();
2527 KURL unreachableURL = m_documentLoader->unreachableURL();
2528 if (!unreachableURL.isEmpty())
2529 request.setURL(unreachableURL);
2531 request.setCachePolicy(ReturnCacheDataElseLoad);
2533 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2534 setPolicyDocumentLoader(loader.get());
2536 loader->setOverrideEncoding(encoding);
2538 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
2541 void FrameLoader::reload(bool endToEndReload)
2543 if (!m_documentLoader)
2546 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2547 // Reloading in this case will lose the current contents (see 4151001).
2548 if (m_documentLoader->request().url().isEmpty())
2551 ResourceRequest initialRequest = m_documentLoader->request();
2553 // Replace error-page URL with the URL we were trying to reach.
2554 KURL unreachableURL = m_documentLoader->unreachableURL();
2555 if (!unreachableURL.isEmpty())
2556 initialRequest.setURL(unreachableURL);
2558 // Create a new document loader for the reload, this will become m_documentLoader eventually,
2559 // but first it has to be the "policy" document loader, and then the "provisional" document loader.
2560 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2562 ResourceRequest& request = loader->request();
2564 // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
2565 request.setCachePolicy(ReloadIgnoringCacheData);
2567 // If we're about to re-post, set up action so the application can warn the user.
2568 if (request.httpMethod() == "POST")
2569 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2571 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2573 loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
2576 static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
2578 // targetFrame can be NULL when we're trying to navigate a top-level frame
2579 // that has a NULL opener.
2583 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2584 Document* ancestorDocument = ancestorFrame->document();
2585 if (!ancestorDocument)
2588 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2589 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
2596 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2598 // The navigation change is safe if the active frame is:
2599 // - in the same security origin as the target or one of the target's
2602 // Or the target frame is:
2603 // - a top-level frame in the frame hierarchy and the active frame can
2604 // navigate the target frame's opener per above.
2609 // Performance optimization.
2610 if (m_frame == targetFrame)
2613 // Let a frame navigate the top-level window that contains it. This is
2614 // important to allow because it lets a site "frame-bust" (escape from a
2615 // frame created by another web site).
2616 if (targetFrame == m_frame->tree()->top())
2619 Document* activeDocument = m_frame->document();
2620 ASSERT(activeDocument);
2621 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
2623 // For top-level windows, check the opener.
2624 if (!targetFrame->tree()->parent() && canAccessAncestor(activeSecurityOrigin, targetFrame->loader()->opener()))
2627 // In general, check the frame's ancestors.
2628 if (canAccessAncestor(activeSecurityOrigin, targetFrame))
2631 Settings* settings = targetFrame->settings();
2632 if (settings && !settings->privateBrowsingEnabled()) {
2633 Document* targetDocument = targetFrame->document();
2634 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2635 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2636 targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
2638 // FIXME: should we print to the console of the activeFrame as well?
2639 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String());
2645 void FrameLoader::stopLoadingSubframes()
2647 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2648 child->loader()->stopAllLoaders();
2651 void FrameLoader::stopAllLoaders()
2653 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2654 if (m_inStopAllLoaders)
2657 m_inStopAllLoaders = true;
2661 stopLoadingSubframes();
2662 if (m_provisionalDocumentLoader)
2663 m_provisionalDocumentLoader->stopLoading();
2664 if (m_documentLoader)
2665 m_documentLoader->stopLoading();
2667 setProvisionalDocumentLoader(0);
2669 if (m_documentLoader)
2670 m_documentLoader->clearArchiveResources();
2672 m_inStopAllLoaders = false;
2675 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2679 if (deferCheckLoadComplete)
2680 scheduleCheckLoadComplete();
2681 else if (m_frame->page())
2682 checkLoadComplete();
2685 DocumentLoader* FrameLoader::activeDocumentLoader() const
2687 if (m_state == FrameStateProvisional)
2688 return m_provisionalDocumentLoader.get();
2689 return m_documentLoader.get();
2692 bool FrameLoader::isLoading() const
2694 DocumentLoader* docLoader = activeDocumentLoader();
2697 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2700 bool FrameLoader::frameHasLoaded() const
2702 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2705 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2707 if (!loader && !m_documentLoader)
2710 ASSERT(loader != m_documentLoader);
2711 ASSERT(!loader || loader->frameLoader() == this);
2713 m_client->prepareForDataSourceReplacement();
2715 if (m_documentLoader)
2716 m_documentLoader->detachFromFrame();
2718 m_documentLoader = loader;
2721 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2723 if (m_policyDocumentLoader == loader)
2728 loader->setFrame(m_frame);
2729 if (m_policyDocumentLoader
2730 && m_policyDocumentLoader != m_provisionalDocumentLoader
2731 && m_policyDocumentLoader != m_documentLoader)
2732 m_policyDocumentLoader->detachFromFrame();
2734 m_policyDocumentLoader = loader;
2737 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2739 ASSERT(!loader || !m_provisionalDocumentLoader);
2740 ASSERT(!loader || loader->frameLoader() == this);
2742 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2743 m_provisionalDocumentLoader->detachFromFrame();
2745 m_provisionalDocumentLoader = loader;
2748 double FrameLoader::timeOfLastCompletedLoad()
2750 return storedTimeOfLastCompletedLoad;
2753 void FrameLoader::setState(FrameState newState)
2757 if (newState == FrameStateProvisional)
2758 provisionalLoadStarted();
2759 else if (newState == FrameStateComplete) {
2760 frameLoadCompleted();
2761 storedTimeOfLastCompletedLoad = currentTime();
2762 if (m_documentLoader)
2763 m_documentLoader->stopRecordingResponses();
2767 void FrameLoader::clearProvisionalLoad()
2769 setProvisionalDocumentLoader(0);
2770 if (Page* page = m_frame->page())
2771 page->progress()->progressCompleted(m_frame);
2772 setState(FrameStateComplete);
2775 void FrameLoader::markLoadComplete()
2777 setState(FrameStateComplete);
2780 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2782 RefPtr<CachedPage> cachedPage = prpCachedPage;
2783 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2785 LOG(Loading, "WebCoreLoading %s: About to commit provisional load from previous URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2787 // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
2788 // We are doing this here because we know for sure that a new page is about to be loaded.
2789 cachePageForHistoryItem(m_currentHistoryItem.get());
2791 if (m_loadType != FrameLoadTypeReplace)
2792 closeOldDataSources();
2794 if (!cachedPage && !m_creatingInitialEmptyDocument)
2795 m_client->makeRepresentation(pdl.get());
2797 transitionToCommitted(cachedPage);
2799 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2800 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2801 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2802 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2803 if (m_sentRedirectNotification)
2804 clientRedirectCancelledOrFinished(false);
2806 if (cachedPage && cachedPage->document()) {
2808 cachedPage->clear();
2810 KURL url = pdl->substituteData().responseURL();
2814 url = pdl->responseURL();
2821 LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
2823 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
2824 updateHistoryForClientRedirect();
2826 if (m_documentLoader->isLoadingFromCachedPage()) {
2827 m_frame->document()->documentDidBecomeActive();
2829 // Force a layout to update view size and thereby update scrollbars.
2830 m_client->forceLayout();
2832 const ResponseVector& responses = m_documentLoader->responses();
2833 size_t count = responses.size();
2834 for (size_t i = 0; i < count; i++) {
2835 const ResourceResponse& response = responses[i];
2836 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
2837 ResourceError error;
2838 unsigned long identifier;
2839 ResourceRequest request(response.url());
2840 requestFromDelegate(request, identifier, error);
2841 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
2842 // However, with today's computers and networking speeds, this won't happen in practice.
2843 // Could be an issue with a giant local file.
2844 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
2847 pageCache()->remove(m_currentHistoryItem.get());
2849 m_documentLoader->setPrimaryLoadComplete(true);
2851 // FIXME: Why only this frame and not parent frames?
2852 checkLoadCompleteForThisFrame();
2856 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2858 ASSERT(m_client->hasWebView());
2859 ASSERT(m_state == FrameStateProvisional);
2861 if (m_state != FrameStateProvisional)
2864 m_client->setCopiesOnScroll();
2865 updateHistoryForCommit();
2867 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2868 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2869 // or the two will stomp each other.
2870 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2871 if (m_documentLoader)
2873 if (pdl != m_provisionalDocumentLoader)
2876 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2877 if (m_documentLoader)
2878 m_documentLoader->stopLoadingSubresources();
2879 if (m_documentLoader)
2880 m_documentLoader->stopLoadingPlugIns();
2882 setDocumentLoader(m_provisionalDocumentLoader.get());
2883 setProvisionalDocumentLoader(0);
2884 setState(FrameStateCommittedPage);
2886 // Handle adding the URL to the back/forward list.
2887 DocumentLoader* dl = m_documentLoader.get();
2888 String ptitle = dl->title();
2890 switch (m_loadType) {
2891 case FrameLoadTypeForward:
2892 case FrameLoadTypeBack:
2893 case FrameLoadTypeIndexedBackForward:
2894 if (Page* page = m_frame->page())
2895 if (page->backForwardList()) {
2896 updateHistoryForBackForwardNavigation();
2898 // Create a document view for this document, or used the cached view.
2900 DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
2901 ASSERT(cachedDocumentLoader);
2902 cachedDocumentLoader->setFrame(m_frame);
2903 m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
2906 m_client->transitionToCommittedForNewPage();
2910 case FrameLoadTypeReload:
2911 case FrameLoadTypeReloadFromOrigin:
2912 case FrameLoadTypeSame:
2913 case FrameLoadTypeReplace:
2914 updateHistoryForReload();
2915 m_client->transitionToCommittedForNewPage();
2918 case FrameLoadTypeStandard:
2919 updateHistoryForStandardLoad();
2920 #ifndef BUILDING_ON_TIGER
2921 // This code was originally added for a Leopard performance imporvement. We decided to
2922 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2923 if (m_frame->view())
2924 m_frame->view()->setScrollbarsSuppressed(true);
2926 m_client->transitionToCommittedForNewPage();
2929 case FrameLoadTypeRedirectWithLockedBackForwardList:
2930 updateHistoryForRedirectWithLockedBackForwardList();
2931 m_client->transitionToCommittedForNewPage();
2934 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2935 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2937 ASSERT_NOT_REACHED();
2940 m_responseMIMEType = dl->responseMIMEType();
2942 // Tell the client we've committed this URL.
2943 ASSERT(m_frame->view());
2945 if (m_creatingInitialEmptyDocument)
2948 m_committedFirstRealDocumentLoad = true;
2950 // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2951 if (cachedPage || !m_client->hasHTMLView()) {
2952 dispatchDidCommitLoad();
2954 // If we have a title let the WebView know about it.
2955 if (!ptitle.isNull())
2956 m_client->dispatchDidReceiveTitle(ptitle);
2960 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2962 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2963 // the redirect succeeded. We should either rename this API, or add a new method, like
2964 // -webView:didFinishClientRedirectForFrame:
2965 m_client->dispatchDidCancelClientRedirect();
2967 if (!cancelWithLoadInProgress)
2968 m_quickRedirectComing = false;
2970 m_sentRedirectNotification = false;
2973 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction)
2975 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
2977 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2978 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2979 m_sentRedirectNotification = true;
2981 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2982 // load as part of the same navigation. If we don't have a document loader, we have
2983 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2984 m_quickRedirectComing = lockBackForwardList && m_documentLoader && !isJavaScriptFormAction;
2988 void FrameLoader::setForceReloadWmlDeck(bool reload)
2990 m_forceReloadWmlDeck = reload;
2994 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2997 // As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
2998 if (m_forceReloadWmlDeck)
3002 // This function implements the rule: "Don't reload if navigating by fragment within
3003 // the same URL, but do reload if going to a new URL or to the same URL with no
3004 // fragment identifier at all."
3005 if (!destinationURL.hasRef())
3007 return !equalIgnoringRef(currentURL, destinationURL);
3010 void FrameLoader::closeOldDataSources()
3012 // FIXME: Is it important for this traversal to be postorder instead of preorder?
3013 // If so, add helpers for postorder traversal, and use them. If not, then lets not
3014 // use a recursive algorithm here.
3015 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3016 child->loader()->closeOldDataSources();
3018 if (m_documentLoader)
3019 m_client->dispatchWillClose();
3021 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
3024 void FrameLoader::open(CachedPage& cachedPage)
3026 ASSERT(!m_frame->tree()->parent());
3027 ASSERT(m_frame->page());
3028 ASSERT(m_frame->page()->mainFrame() == m_frame);
3030 cancelRedirection();
3032 // We still have to close the previous part page.
3035 // Delete old status bar messages (if it _was_ activated on last URL).
3036 if (m_frame->script()->isEnabled()) {
3037 m_frame->setJSStatusBarText(String());
3038 m_frame->setJSDefaultStatusBarText(String());
3041 open(*cachedPage.cachedMainFrame());
3046 void FrameLoader::open(CachedFrame& cachedFrame)
3048 m_isComplete = false;
3050 // Don't re-emit the load event.
3051 m_didCallImplicitClose = true;
3053 KURL url = cachedFrame.url();
3055 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmpty() && url.path().isEmpty())
3065 Document* document = cachedFrame.document();
3067 document->setInPageCache(false);
3069 m_needsClear = true;
3070 m_isComplete = false;
3071 m_didCallImplicitClose = false;
3072 m_outgoingReferrer = url.string();
3074 FrameView* view = cachedFrame.view();
3076 // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream.
3079 view->setWasScrolledByUser(false);
3080 m_frame->setView(view);
3082 m_frame->setDocument(document);
3083 m_frame->setDOMWindow(cachedFrame.domWindow());
3084 m_frame->domWindow()->setURL(document->url());
3085 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
3087 m_decoder = document->decoder();
3089 updatePolicyBaseURL();
3091 cachedFrame.restore();
3094 bool FrameLoader::isStopping() const
3096 return activeDocumentLoader()->isStopping();
3099 void FrameLoader::finishedLoading()
3101 // Retain because the stop may release the last reference to it.
3102 RefPtr<Frame> protect(m_frame);
3104 RefPtr<DocumentLoader> dl = activeDocumentLoader();
3105 dl->finishedLoading();
3106 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
3108 dl->setPrimaryLoadComplete(true);
3109 m_client->dispatchDidLoadMainResource(dl.get());
3110 checkLoadComplete();
3113 bool FrameLoader::isHostedByObjectElement() const
3115 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
3116 return owner && owner->hasTagName(objectTag);
3119 bool FrameLoader::isLoadingMainFrame() const
3121 Page* page = m_frame->page();
3122 return page && m_frame == page->mainFrame();
3125 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
3127 return m_client->canShowMIMEType(MIMEType);
3130 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
3132 return m_client->representationExistsForURLScheme(URLScheme);
3135 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
3137 return m_client->generatedMIMETypeForURLScheme(URLScheme);
3140 void FrameLoader::cancelContentPolicyCheck()
3142 m_client->cancelPolicyCheck();
3143 m_policyCheck.clear();
3146 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
3148 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
3151 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
3153 // FIXME: Platforms shouldn't differ here!
3154 #if PLATFORM(WIN) || PLATFORM(CHROMIUM)
3155 if (m_creatingInitialEmptyDocument)
3159 // If loading a webarchive, run through webarchive machinery
3160 const String& responseMIMEType = loader->responseMIMEType();
3162 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads
3163 // so we still need to call it. Other platforms should only call finishLoading for non-archive loads
3164 // That work should be factored out so this #ifdef can be removed
3166 m_client->finishedLoading(loader);
3167 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType))
3170 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) {
3171 m_client->finishedLoading(loader);
3176 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType));
3180 loader->addAllArchiveResources(archive.get());
3182 ArchiveResource* mainResource = archive->mainResource();
3183 loader->setParsedArchiveData(mainResource->data());
3184 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url());
3187 bool FrameLoader::isReplacing() const
3189 return m_loadType == FrameLoadTypeReplace;
3192 void FrameLoader::setReplacing()
3194 m_loadType = FrameLoadTypeReplace;
3197 void FrameLoader::revertToProvisional(DocumentLoader* loader)
3199 m_client->revertToProvisionalState(loader);
3202 bool FrameLoader::subframeIsLoading() const
3204 // It's most likely that the last added frame is the last to load so we walk backwards.
3205 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
3206 FrameLoader* childLoader = child->loader();
3207 DocumentLoader* documentLoader = childLoader->documentLoader();
3208 if (documentLoader && documentLoader->isLoadingInAPISense())
3210 documentLoader = childLoader->provisionalDocumentLoader();
3211 if (documentLoader && documentLoader->isLoadingInAPISense())
3217 void FrameLoader::willChangeTitle(DocumentLoader* loader)
3219 m_client->willChangeTitle(loader);
3222 FrameLoadType FrameLoader::loadType() const
3227 CachePolicy FrameLoader::cachePolicy() const
3230 return CachePolicyVerify;
3232 if (m_loadType == FrameLoadTypeReloadFromOrigin)
3233 return CachePolicyReload;
3235 if (Frame* parentFrame = m_frame->tree()->parent()) {
3236 CachePolicy parentCachePolicy = parentFrame->loader()->cachePolicy();
3237 if (parentCachePolicy != CachePolicyVerify)
3238 return parentCachePolicy;
3241 if (m_loadType == FrameLoadTypeReload)
3242 return CachePolicyRevalidate;
3244 return CachePolicyVerify;
3247 void FrameLoader::stopPolicyCheck()
3249 m_client->cancelPolicyCheck();
3250 PolicyCheck check = m_policyCheck;
3251 m_policyCheck.clear();
3255 void FrameLoader::checkLoadCompleteForThisFrame()
3257 ASSERT(m_client->hasWebView());
3260 case FrameStateProvisional: {
3261 if (m_delegateIsHandlingProvisionalLoadError)
3264 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
3268 // If we've received any errors we may be stuck in the provisional state and actually complete.
3269 const ResourceError& error = pdl->mainDocumentError();
3273 // Check all children first.
3274 RefPtr<HistoryItem> item;
3275 if (Page* page = m_frame->page())
3276 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
3277 item = m_currentHistoryItem;
3279 bool shouldReset = true;
3280 if (!pdl->isLoadingInAPISense()) {
3281 m_delegateIsHandlingProvisionalLoadError = true;
3282 m_client->dispatchDidFailProvisionalLoad(error);
3283 m_delegateIsHandlingProvisionalLoadError = false;
3285 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
3286 // which it must be to be in this branch of the if? And is it OK to just do a full-on
3287 // stopAllLoaders instead of stopLoadingSubframes?
3288 stopLoadingSubframes();
3291 // Finish resetting the load state, but only if another load hasn't been started by the
3292 // delegate callback.
3293 if (pdl == m_provisionalDocumentLoader)
3294 clearProvisionalLoad();
3295 else if (m_provisionalDocumentLoader) {
3296 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
3297 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
3298 shouldReset = false;
3301 if (shouldReset && item)
3302 if (Page* page = m_frame->page()) {
3303 page->backForwardList()->goToItem(item.get());
3304 Settings* settings = m_frame->settings();
3305 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
3310 case FrameStateCommittedPage: {
3311 DocumentLoader* dl = m_documentLoader.get();
3312 if (!dl || dl->isLoadingInAPISense())
3317 // FIXME: Is this subsequent work important if we already navigated away?
3318 // Maybe there are bugs because of that, or extra work we can skip because
3319 // the new page is ready.
3321 m_client->forceLayoutForNonHTML();
3323 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
3324 if (Page* page = m_frame->page())
3325 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
3326 restoreScrollPositionAndViewState();
3328 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
3331 const ResourceError& error = dl->mainDocumentError();
3333 m_didDispatchDidCommitLoad = false;
3335 if (!error.isNull())
3336 m_client->dispatchDidFailLoad(error);
3338 m_client->dispatchDidFinishLoad();
3340 if (Page* page = m_frame->page())
3341 page->progress()->progressCompleted(m_frame);
3345 case FrameStateComplete:
3346 frameLoadCompleted();
3350 ASSERT_NOT_REACHED();
3353 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
3355 PolicyCheck check = m_policyCheck;
3356 m_policyCheck.clear();
3360 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3362 if (!m_provisionalDocumentLoader)
3365 // DocumentLoader calls back to our prepareForLoadStart
3366 m_provisionalDocumentLoader->prepareForLoadStart();
3368 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
3369 // so we need to null check it again.
3370 if (!m_provisionalDocumentLoader)
3373 DocumentLoader* activeDocLoader = activeDocumentLoader();
3374 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3377 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3379 unsigned long identifier = 0;
3381 if (Page* page = m_frame->page()) {
3382 identifier = page->progress()->createUniqueIdentifier();
3383 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3386 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3387 m_provisionalDocumentLoader->updateLoading();
3390 void FrameLoader::didFirstLayout()
3392 if (Page* page = m_frame->page())
3393 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3394 restoreScrollPositionAndViewState();
3396 m_firstLayoutDone = true;
3397 m_client->dispatchDidFirstLayout();
3400 void FrameLoader::didFirstVisuallyNonEmptyLayout()
3402 m_client->dispatchDidFirstVisuallyNonEmptyLayout();
3405 void FrameLoader::frameLoadCompleted()
3407 // Note: Can be called multiple times.
3409 m_client->frameLoadCompleted();
3411 // Even if already complete, we might have set a previous item on a frame that
3412 // didn't do any data loading on the past transaction. Make sure to clear these out.
3413 setPreviousHistoryItem(0);
3415 // After a canceled provisional load, firstLayoutDone is false.
3416 // Reset it to true if we're displaying a page.
3417 if (m_documentLoader)
3418 m_firstLayoutDone = true;
3421 bool FrameLoader::firstLayoutDone() const
3423 return m_firstLayoutDone;
3426 bool FrameLoader::isQuickRedirectComing() const
3428 return m_quickRedirectComing;
3431 void FrameLoader::detachChildren()
3433 // FIXME: Is it really necessary to do this in reverse order?
3435 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3436 previous = child->tree()->previousSibling();
3437 child->loader()->detachFromParent();
3441 void FrameLoader::closeAndRemoveChild(Frame* child)
3443 child->tree()->detachFromParent();
3446 if (child->ownerElement())
3447 child->page()->decrementFrameCount();
3448 child->pageDestroyed();
3450 m_frame->tree()->removeChild(child);
3453 void FrameLoader::recursiveCheckLoadComplete()
3455 Vector<RefPtr<Frame>, 10> frames;
3457 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3458 frames.append(frame);
3460 unsigned size = frames.size();
3461 for (unsigned i = 0; i < size; i++)
3462 frames[i]->loader()->recursiveCheckLoadComplete();
3464 checkLoadCompleteForThisFrame();
3467 // Called every time a resource is completely loaded, or an error is received.
3468 void FrameLoader::checkLoadComplete()
3470 ASSERT(m_client->hasWebView());
3472 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3473 // is currently needed in order to null out the previous history item for all frames.
3474 if (Page* page = m_frame->page())
3475 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3478 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3481 return numRequests(m_frame->document());
3484 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3485 count += numRequests(frame->document());
3489 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
3491 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3492 // We do not want to submit more than one form from the same page,
3493 // nor do we want to submit a single form more than once.
3494 // This flag prevents these from happening; not sure how other browsers prevent this.
3495 // The flag is reset in each time we start handle a new mouse or key down event, and
3496 // also in setView since this part may get reused for a page from the back/forward cache.
3497 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3498 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3499 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3500 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3501 Frame* target = m_frame->tree()->find(request.frameName());
3502 if (m_frame->tree()->isDescendantOf(target)) {
3503 if (m_submittedFormURL == request.resourceRequest().url())
3505 m_submittedFormURL = request.resourceRequest().url();
3508 loadFrameRequestWithFormAndValues(request, lockHistory, lockBackForwardList, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3510 clearRecordedFormValues();
3513 String FrameLoader::userAgent(const KURL& url) const
3515 return m_client->userAgent(url);
3518 void FrameLoader::tokenizerProcessedData()
3520 // ASSERT(m_frame->page());
3521 // ASSERT(m_frame->document());
3526 void FrameLoader::handledOnloadEvents()
3528 m_client->dispatchDidHandleOnloadEvents();
3531 void FrameLoader::frameDetached()
3534 m_frame->document()->stopActiveDOMObjects();
3538 void FrameLoader::detachFromParent()
3540 RefPtr<Frame> protect(m_frame);
3544 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3547 if (Page* page = m_frame->page())
3548 page->inspectorController()->frameDetachedFromParent(m_frame);
3550 m_client->detachedFromParent2();
3551 setDocumentLoader(0);
3552 m_client->detachedFromParent3();
3553 if (Frame* parent = m_frame->tree()->parent()) {
3554 parent->loader()->closeAndRemoveChild(m_frame);
3555 parent->loader()->scheduleCheckCompleted();
3557 m_frame->setView(0);
3558 m_frame->pageDestroyed();
3562 void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
3564 addExtraFieldsToRequest(request, m_loadType, false, false);
3567 void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
3569 addExtraFieldsToRequest(request, m_loadType, true, false);
3572 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
3574 // These modifications are only necessary for HTTP and HTTPS.
3575 if (!request.url().isEmpty() && !request.url().protocolInHTTPFamily())
3578 applyUserAgent(request);
3580 if (loadType == FrameLoadTypeReload) {
3581 request.setCachePolicy(ReloadIgnoringCacheData);
3582 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3583 } else if (loadType == FrameLoadTypeReloadFromOrigin) {
3584 request.setCachePolicy(ReloadIgnoringCacheData);
3585 request.setHTTPHeaderField("Cache-Control", "no-cache");
3586 request.setHTTPHeaderField("Pragma", "no-cache");
3589 // Don't set the cookie policy URL if it's already been set.
3590 if (request.mainDocumentURL().isEmpty()) {
3591 if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
3592 request.setMainDocumentURL(request.url());
3593 else if (Page* page = m_frame->page())
3594 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3598 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3600 // Make sure we send the Origin header.
3601 addHTTPOriginIfNeeded(request, String());
3603 // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
3604 // For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
3605 Settings* settings = m_frame->settings();
3606 request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : Str