summaryrefslogtreecommitdiffstats
path: root/WebCore/loader/FrameLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader/FrameLoader.cpp')
-rw-r--r--WebCore/loader/FrameLoader.cpp1350
1 files changed, 379 insertions, 971 deletions
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index 514f98a..dc2c68c 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
@@ -39,7 +39,7 @@
#include "ArchiveFactory.h"
#endif
#include "BackForwardList.h"
-#include "CString.h"
+#include "BeforeUnloadEvent.h"
#include "Cache.h"
#include "CachedPage.h"
#include "Chrome.h"
@@ -47,6 +47,7 @@
#include "DOMWindow.h"
#include "DocLoader.h"
#include "Document.h"
+#include "DocumentLoadTiming.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "EditorClient.h"
@@ -55,15 +56,17 @@
#include "EventNames.h"
#include "FloatRect.h"
#include "FormState.h"
+#include "FormSubmission.h"
#include "Frame.h"
#include "FrameLoadRequest.h"
#include "FrameLoaderClient.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLAnchorElement.h"
-#include "HTMLAppletElement.h"
#include "HTMLFormElement.h"
-#include "HTMLFrameElement.h"
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#endif
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTTPParsers.h"
@@ -83,31 +86,26 @@
#include "PluginDatabase.h"
#include "PluginDocument.h"
#include "ProgressTracker.h"
-#include "RenderPart.h"
-#include "RenderView.h"
-#include "RenderWidget.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
+#include "SchemeRegistry.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
#include "ScriptString.h"
-#include "ScriptValue.h"
#include "SecurityOrigin.h"
#include "SegmentedString.h"
+#include "SerializedScriptValue.h"
#include "Settings.h"
-
-#if ENABLE(SHARED_WORKERS)
-#include "SharedWorkerRepository.h"
-#endif
-
#include "TextResourceDecoder.h"
#include "WindowFeatures.h"
-#include "XMLHttpRequest.h"
-#include "XMLTokenizer.h"
-#include "XSSAuditor.h"
+#include "XMLDocumentParser.h"
#include <wtf/CurrentTime.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+#if ENABLE(SHARED_WORKERS)
+#include "SharedWorkerRepository.h"
+#endif
#if ENABLE(SVG)
#include "SVGDocument.h"
@@ -126,16 +124,18 @@
namespace WebCore {
+using namespace HTMLNames;
+
#if ENABLE(SVG)
using namespace SVGNames;
#endif
-using namespace HTMLNames;
#if ENABLE(XHTMLMP)
static const char defaultAcceptHeader[] = "application/xml,application/vnd.wap.xhtml+xml,application/xhtml+xml;profile='http://www.wapforum.org/xhtml',text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
#else
static const char defaultAcceptHeader[] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
#endif
+
static double storedTimeOfLastCompletedLoad;
bool isBackForwardLoadType(FrameLoadType type)
@@ -171,40 +171,48 @@ static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame
return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
}
+// This is not in the FrameLoader class to emphasize that it does not depend on
+// private FrameLoader data, and to avoid increasing the number of public functions
+// with access to private data. Since only this .cpp file needs it, making it
+// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
+// API simpler.
+//
+// FIXME: isDocumentSandboxed should eventually replace isSandboxed.
+static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
+{
+ return frame->document() && frame->document()->securityOrigin()->isSandboxed(mask);
+}
+
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
: m_frame(frame)
, m_client(client)
, m_policyChecker(frame)
, m_history(frame)
, m_notifer(frame)
+ , m_writer(frame)
+ , m_subframeLoader(frame)
, m_state(FrameStateCommittedPage)
, m_loadType(FrameLoadTypeStandard)
, m_delegateIsHandlingProvisionalLoadError(false)
- , m_firstLayoutDone(false)
, m_quickRedirectComing(false)
, m_sentRedirectNotification(false)
, m_inStopAllLoaders(false)
, m_isExecutingJavaScriptFormAction(false)
, m_didCallImplicitClose(false)
, m_wasUnloadEventEmitted(false)
- , m_unloadEventBeingDispatched(false)
+ , m_pageDismissalEventBeingDispatched(false)
, m_isComplete(false)
, m_isLoadingMainResource(false)
, m_needsClear(false)
- , m_receivedData(false)
- , m_encodingWasChosenByUser(false)
- , m_containsPlugIns(false)
, m_checkTimer(this, &FrameLoader::checkTimerFired)
, m_shouldCallCheckCompleted(false)
, m_shouldCallCheckLoadComplete(false)
, m_opener(0)
- , m_creatingInitialEmptyDocument(false)
- , m_isDisplayingInitialEmptyDocument(false)
- , m_committedFirstRealDocumentLoad(false)
, m_didPerformFirstNavigation(false)
, m_loadingFromCachedPage(false)
, m_suppressOpenerInNewFrame(false)
, m_sandboxFlags(SandboxAll)
+ , m_forcedSandboxFlags(SandboxNone)
#ifndef NDEBUG
, m_didDispatchDidCommitLoad(false)
#endif
@@ -224,22 +232,22 @@ FrameLoader::~FrameLoader()
void FrameLoader::init()
{
+ // Propagate sandbox attributes to this Frameloader and its descendants.
+ // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
+ updateSandboxFlags();
+
// this somewhat odd set of steps is needed to give the frame an initial empty document
- m_isDisplayingInitialEmptyDocument = false;
- m_creatingInitialEmptyDocument = true;
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
setState(FrameStateProvisional);
m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
m_provisionalDocumentLoader->finishedLoading();
- begin(KURL(), false);
- end();
+ writer()->begin(KURL(), false);
+ writer()->end();
m_frame->document()->cancelParsing();
- m_creatingInitialEmptyDocument = false;
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
m_didCallImplicitClose = true;
-
- // Propagate sandbox attributes to this Frameloader and its descendants.
- updateSandboxFlags();
}
void FrameLoader::setDefersLoading(bool defers)
@@ -257,71 +265,6 @@ void FrameLoader::setDefersLoading(bool defers)
}
}
-Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
-{
- ASSERT(!features.dialog || request.frameName().isEmpty());
-
- if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
- Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
- if (frame && shouldAllowNavigation(frame)) {
- if (!request.resourceRequest().url().isEmpty())
- frame->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
- if (Page* page = frame->page())
-#ifdef ANDROID_USER_GESTURE
- page->chrome()->focus(isProcessingUserGesture());
-#else
- page->chrome()->focus();
-#endif
- created = false;
- return frame;
- }
- }
-
- // FIXME: Setting the referrer should be the caller's responsibility.
- FrameLoadRequest requestWithReferrer = request;
- requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
- addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
-
- Page* oldPage = m_frame->page();
- if (!oldPage)
- return 0;
-
- Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
- if (!page)
- return 0;
-
- Frame* frame = page->mainFrame();
- if (request.frameName() != "_blank")
- frame->tree()->setName(request.frameName());
-
- page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
- page->chrome()->setStatusbarVisible(features.statusBarVisible);
- page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
- page->chrome()->setMenubarVisible(features.menuBarVisible);
- page->chrome()->setResizable(features.resizable);
-
- // 'x' and 'y' specify the location of the window, while 'width' and 'height'
- // specify the size of the page. We can only resize the window, so
- // adjust for the difference between the window size and the page size.
-
- FloatRect windowRect = page->chrome()->windowRect();
- FloatSize pageSize = page->chrome()->pageRect().size();
- if (features.xSet)
- windowRect.setX(features.x);
- if (features.ySet)
- windowRect.setY(features.y);
- if (features.widthSet)
- windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
- if (features.heightSet)
- windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
- page->chrome()->setWindowRect(windowRect);
-
- page->chrome()->show();
-
- created = true;
- return frame;
-}
-
bool FrameLoader::canHandleRequest(const ResourceRequest& request)
{
return m_client->canHandleRequest(request);
@@ -332,21 +275,22 @@ void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool l
RefPtr<Frame> protect(m_frame);
ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
-#ifdef ANDROID_USER_GESTURE
- request.setUserGesture(userGesture);
-#endif
- if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture))
- return;
+ urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture, SendReferrer, ReplaceDocumentIfJavaScriptURL);
+}
- urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture, SendReferrer);
+void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy referrerPolicy)
+{
+ urlSelected(ResourceRequest(url), passedTarget, triggeringEvent, lockHistory, lockBackForwardList, userGesture, referrerPolicy, DoNotReplaceDocumentIfJavaScriptURL);
}
-void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy referrerPolicy)
+// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
+// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
+void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy referrerPolicy, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
{
ASSERT(!m_suppressOpenerInNewFrame);
- if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, false))
+ if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, shouldReplaceDocumentIfJavaScriptURL))
return;
String target = passedTarget;
@@ -366,125 +310,42 @@ void FrameLoader::urlSelected(const ResourceRequest& request, const String& pass
m_suppressOpenerInNewFrame = false;
}
-bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
+void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
{
- // Support for <frame src="javascript:string">
- KURL scriptURL;
- KURL url;
- if (protocolIsJavaScript(urlString)) {
- scriptURL = completeURL(urlString); // completeURL() encodes the URL.
- url = blankURL();
- } else
- url = completeURL(urlString);
-
- Frame* frame = ownerElement->contentFrame();
- if (frame)
- frame->redirectScheduler()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture());
- else
- frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
-
- if (!frame)
- return false;
-
- if (!scriptURL.isEmpty())
- frame->script()->executeIfJavaScriptURL(scriptURL);
-
- return true;
-}
-
-Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
-{
- bool allowsScrolling = true;
- int marginWidth = -1;
- int marginHeight = -1;
- if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
- HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
- allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
- marginWidth = o->getMarginWidth();
- marginHeight = o->getMarginHeight();
- }
-
- if (!SecurityOrigin::canLoad(url, referrer, 0)) {
- FrameLoader::reportLocalLoadFailed(m_frame, url.string());
- return 0;
- }
-
- bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
- RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
+ ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
- if (!frame) {
- checkCallImplicitClose();
- return 0;
- }
-
- // All new frames will have m_isComplete set to true at this point due to synchronously loading
- // an empty document in FrameLoader::init(). But many frames will now be starting an
- // asynchronous load of url, so we set m_isComplete to false and then check if the load is
- // actually completed below. (Note that we set m_isComplete to false even for synchronous
- // loads, so that checkCompleted() below won't bail early.)
- // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
- frame->loader()->m_isComplete = false;
-
- RenderObject* renderer = ownerElement->renderer();
- FrameView* view = frame->view();
- if (renderer && renderer->isWidget() && view)
- toRenderWidget(renderer)->setWidget(view);
-
- checkCallImplicitClose();
-
- // Some loads are performed synchronously (e.g., about:blank and loads
- // cancelled by returning a null ResourceRequest from requestFromDelegate).
- // In these cases, the synchronous load would have finished
- // before we could connect the signals, so make sure to send the
- // completed() signal for the child by hand and mark the load as being
- // complete.
- // FIXME: In this case the Frame will have finished loading before
- // it's being added to the child list. It would be a good idea to
- // create the child first, then invoke the loader separately.
- if (frame->loader()->state() == FrameStateComplete)
- frame->loader()->checkCompleted();
-
- return frame.get();
-}
-
-void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
- const String& target, const String& contentType, const String& boundary,
- bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
-{
- ASSERT(action);
- ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0);
- ASSERT(formData);
- ASSERT(formState);
- ASSERT(formState->sourceFrame() == m_frame);
+ // FIXME: Find a good spot for these.
+ ASSERT(submission->data());
+ ASSERT(submission->state());
+ ASSERT(submission->state()->sourceFrame() == m_frame);
if (!m_frame->page())
return;
- KURL u = completeURL(url.isNull() ? "" : url);
- if (u.isEmpty())
+ if (submission->action().isEmpty())
return;
- if (isDocumentSandboxed(SandboxForms))
+ if (isDocumentSandboxed(m_frame, SandboxForms))
return;
- if (protocolIsJavaScript(u)) {
+ if (protocolIsJavaScript(submission->action())) {
m_isExecutingJavaScriptFormAction = true;
- m_frame->script()->executeIfJavaScriptURL(u, false, false);
+ m_frame->script()->executeIfJavaScriptURL(submission->action(), false, DoNotReplaceDocumentIfJavaScriptURL);
m_isExecutingJavaScriptFormAction = false;
return;
}
- FrameLoadRequest frameRequest;
-#ifdef ANDROID_USER_GESTURE
- frameRequest.resourceRequest().setUserGesture(isProcessingUserGesture());
-#endif
-
- String targetOrBaseTarget = target.isEmpty() ? m_frame->document()->baseTarget() : target;
- Frame* targetFrame = findFrameForNavigation(targetOrBaseTarget);
+ Frame* targetFrame = m_frame->tree()->find(submission->target());
+ if (!shouldAllowNavigation(targetFrame))
+ return;
if (!targetFrame) {
+ if (!DOMWindow::allowPopUp(m_frame) && !isProcessingUserGesture())
+ return;
+
targetFrame = m_frame;
- frameRequest.setFrameName(targetOrBaseTarget);
- }
+ } else
+ submission->clearTarget();
+
if (!targetFrame->page())
return;
@@ -501,39 +362,22 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
// needed any more now that we reset m_submittedFormURL on each mouse or key down event.
if (m_frame->tree()->isDescendantOf(targetFrame)) {
- if (m_submittedFormURL == u)
+ if (m_submittedFormURL == submission->action())
return;
- m_submittedFormURL = u;
- }
-
- formData->generateFiles(m_frame->page()->chrome()->client());
-
- if (!m_outgoingReferrer.isEmpty())
- frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
-
- if (strcmp(action, "GET") == 0)
- u.setQuery(formData->flattenToString());
- else {
- frameRequest.resourceRequest().setHTTPMethod("POST");
- frameRequest.resourceRequest().setHTTPBody(formData);
-
- // construct some user headers if necessary
- if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
- frameRequest.resourceRequest().setHTTPContentType(contentType);
- else // contentType must be "multipart/form-data"
- frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
+ m_submittedFormURL = submission->action();
}
- frameRequest.resourceRequest().setURL(u);
- addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
+ submission->data()->generateFiles(m_frame->document());
+ submission->setReferrer(m_outgoingReferrer);
+ submission->setOrigin(outgoingOrigin());
- targetFrame->redirectScheduler()->scheduleFormSubmission(frameRequest, lockHistory, event, formState);
+ targetFrame->redirectScheduler()->scheduleFormSubmission(submission);
}
void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolicy databasePolicy)
{
- if (m_frame->document() && m_frame->document()->tokenizer())
- m_frame->document()->tokenizer()->stopParsing();
+ if (m_frame->document() && m_frame->document()->parser())
+ m_frame->document()->parser()->stopParsing();
if (unloadEventPolicy != UnloadEventPolicyNone) {
if (m_frame->document()) {
@@ -541,14 +385,23 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
Node* currentFocusedNode = m_frame->document()->focusedNode();
if (currentFocusedNode)
currentFocusedNode->aboutToUnload();
- m_unloadEventBeingDispatched = true;
+ m_pageDismissalEventBeingDispatched = true;
if (m_frame->domWindow()) {
if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide)
m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
- if (!m_frame->document()->inPageCache())
+ if (!m_frame->document()->inPageCache()) {
m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
+
+ if (m_provisionalDocumentLoader) {
+ DocumentLoadTiming* timing = m_provisionalDocumentLoader->timing();
+ ASSERT(timing->navigationStart);
+ ASSERT(!timing->unloadEventEnd);
+ timing->unloadEventEnd = currentTime();
+ ASSERT(timing->unloadEventEnd >= timing->navigationStart);
+ }
+ }
}
- m_unloadEventBeingDispatched = false;
+ m_pageDismissalEventBeingDispatched = false;
if (m_frame->document())
m_frame->document()->updateStyleIfNeeded();
m_wasUnloadEventEmitted = true;
@@ -558,7 +411,7 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
// Dispatching the unload event could have made m_frame->document() null.
if (m_frame->document() && !m_frame->document()->inPageCache()) {
// Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
- bool keepEventListeners = m_isDisplayingInitialEmptyDocument && m_provisionalDocumentLoader
+ bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
&& m_frame->document()->securityOrigin()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
if (!keepEventListeners)
@@ -589,10 +442,7 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
#endif
}
- // tell all subframes to stop as well
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- child->loader()->stopLoading(unloadEventPolicy);
-
+ // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
m_frame->redirectScheduler()->cancel();
}
@@ -602,8 +452,8 @@ void FrameLoader::stop()
// The frame's last ref may be removed and it will be deleted by checkCompleted().
RefPtr<Frame> protector(m_frame);
- if (m_frame->document()->tokenizer())
- m_frame->document()->tokenizer()->stopParsing();
+ if (m_frame->document()->parser())
+ m_frame->document()->parser()->stopParsing();
m_frame->document()->finishParsing();
if (m_iconLoader)
@@ -664,9 +514,11 @@ bool FrameLoader::didOpenURL(const KURL& url)
// If we are still in the process of initializing an empty document then
// its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
// since it may cause clients to attempt to render the frame.
- if (!m_creatingInitialEmptyDocument) {
- m_frame->setJSStatusBarText(String());
- m_frame->setJSDefaultStatusBarText(String());
+ if (!m_stateMachine.creatingInitialEmptyDocument()) {
+ if (DOMWindow* window = m_frame->existingDOMWindow()) {
+ window->setStatus(String());
+ window->setDefaultStatus(String());
+ }
}
m_URL = url;
if (m_URL.protocolInHTTPFamily() && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
@@ -684,7 +536,8 @@ void FrameLoader::didExplicitOpen()
m_didCallImplicitClose = false;
// Calling document.open counts as committing the first real document load.
- m_committedFirstRealDocumentLoad = true;
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
// Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
// from a subsequent window.document.open / window.document.write call.
@@ -707,14 +560,6 @@ void FrameLoader::cancelAndClear()
m_frame->script()->updatePlatformScriptObjects();
}
-void FrameLoader::replaceDocument(const String& html)
-{
- stopAllLoaders();
- begin(m_URL, true, m_frame->document()->securityOrigin());
- write(html);
- end();
-}
-
void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
m_frame->editor()->clear();
@@ -737,7 +582,7 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
// Do this after detaching the document so that the unload event works.
if (clearWindowProperties) {
m_frame->clearDOMWindow();
- m_frame->script()->clearWindowShell();
+ m_frame->script()->clearWindowShell(m_frame->document()->inPageCache());
}
m_frame->selection()->clear();
@@ -745,14 +590,12 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
if (clearFrameView && m_frame->view())
m_frame->view()->clear();
- m_frame->setSelectionGranularity(CharacterGranularity);
-
// Do not drop the document before the ScriptController and view are cleared
// as some destructors might still try to access the document.
m_frame->setDocument(0);
- m_decoder = 0;
+ writer()->clear();
- m_containsPlugIns = false;
+ m_subframeLoader.clear();
if (clearScriptObjects)
m_frame->script()->clearScriptObjects();
@@ -763,16 +606,13 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
m_shouldCallCheckCompleted = false;
m_shouldCallCheckLoadComplete = false;
- m_receivedData = false;
- m_isDisplayingInitialEmptyDocument = false;
-
- if (!m_encodingWasChosenByUser)
- m_encoding = String();
+ if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
}
void FrameLoader::receivedFirstData()
{
- begin(m_workingURL, false);
+ writer()->begin(m_workingURL, false);
dispatchDidCommitLoad();
dispatchDidClearWindowObjectsInAllWorlds();
@@ -803,193 +643,51 @@ void FrameLoader::receivedFirstData()
m_frame->redirectScheduler()->scheduleRedirect(delay, url);
}
-const String& FrameLoader::responseMIMEType() const
-{
- return m_responseMIMEType;
-}
-
-void FrameLoader::setResponseMIMEType(const String& type)
-{
- m_responseMIMEType = type;
-}
-
-void FrameLoader::begin()
-{
- begin(KURL());
-}
-
-void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
+void FrameLoader::setURL(const KURL& url)
{
- // We need to take a reference to the security origin because |clear|
- // might destroy the document that owns it.
- RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
-
- RefPtr<Document> document;
-
- // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
- if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
- document = PluginDocument::create(m_frame);
- else if (!m_client->hasHTMLView())
- document = PlaceholderDocument::create(m_frame);
- else
- document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
-
- bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
- clear(resetScripting, resetScripting);
- if (resetScripting)
- m_frame->script()->updatePlatformScriptObjects();
-
- m_needsClear = true;
- m_isComplete = false;
- m_didCallImplicitClose = false;
- m_isLoadingMainResource = true;
- m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
-
KURL ref(url);
ref.setUser(String());
ref.setPass(String());
ref.removeFragmentIdentifier();
m_outgoingReferrer = ref.string();
m_URL = url;
+}
- document->setURL(m_URL);
- m_frame->setDocument(document);
+void FrameLoader::didBeginDocument(bool dispatch)
+{
+ m_needsClear = true;
+ m_isComplete = false;
+ m_didCallImplicitClose = false;
+ m_isLoadingMainResource = true;
if (m_pendingStateObject) {
- document->statePopped(m_pendingStateObject.get());
+ m_frame->document()->statePopped(m_pendingStateObject.get());
m_pendingStateObject.clear();
}
-
- if (m_decoder)
- document->setDecoder(m_decoder.get());
- if (forcedSecurityOrigin)
- document->setSecurityOrigin(forcedSecurityOrigin.get());
-
- m_frame->domWindow()->setURL(document->url());
- m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
if (dispatch)
dispatchDidClearWindowObjectsInAllWorlds();
-
+
updateFirstPartyForCookies();
- Settings* settings = document->settings();
- document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
+ Settings* settings = m_frame->document()->settings();
+ m_frame->document()->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
- document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
+ m_frame->document()->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
#endif
if (m_documentLoader) {
String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
if (!dnsPrefetchControl.isEmpty())
- document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
+ m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
}
history()->restoreDocumentState();
-
- document->implicitOpen();
-
- if (m_frame->view() && m_client->hasHTMLView())
- m_frame->view()->setContentsSize(IntSize());
-}
-
-void FrameLoader::write(const char* str, int len, bool flush)
-{
- if (len == 0 && !flush)
- return;
-
- if (len == -1)
- len = strlen(str);
-
- Tokenizer* tokenizer = m_frame->document()->tokenizer();
- if (tokenizer && tokenizer->wantsRawData()) {
- if (len > 0)
- tokenizer->writeRawData(str, len);
- return;
- }
-
- if (!m_decoder) {
- if (Settings* settings = m_frame->settings()) {
- m_decoder = TextResourceDecoder::create(m_responseMIMEType,
- settings->defaultTextEncodingName(),
- settings->usesEncodingDetector());
- Frame* parentFrame = m_frame->tree()->parent();
- // Set the hint encoding to the parent frame encoding only if
- // the parent and the current frames share the security origin.
- // We impose this condition because somebody can make a child frame
- // containing a carefully crafted html/javascript in one encoding
- // that can be mistaken for hintEncoding (or related encoding) by
- // an auto detector. When interpreted in the latter, it could be
- // an attack vector.
- // FIXME: This might be too cautious for non-7bit-encodings and
- // we may consider relaxing this later after testing.
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setHintEncoding(parentFrame->document()->decoder());
- } else
- m_decoder = TextResourceDecoder::create(m_responseMIMEType, String());
- Frame* parentFrame = m_frame->tree()->parent();
- if (m_encoding.isEmpty()) {
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
- } else {
- m_decoder->setEncoding(m_encoding,
- m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
- }
- m_frame->document()->setDecoder(m_decoder.get());
- }
-
- String decoded = m_decoder->decode(str, len);
- if (flush)
- decoded += m_decoder->flush();
- if (decoded.isEmpty())
- return;
-
- if (!m_receivedData) {
- m_receivedData = true;
- if (m_decoder->encoding().usesVisualOrdering())
- m_frame->document()->setVisuallyOrdered();
- m_frame->document()->recalcStyle(Node::Force);
- }
-
- if (tokenizer) {
- ASSERT(!tokenizer->wantsRawData());
- tokenizer->write(decoded, true);
- }
-}
-
-void FrameLoader::write(const String& str)
-{
- if (str.isNull())
- return;
-
- if (!m_receivedData) {
- m_receivedData = true;
- m_frame->document()->setParseMode(Document::Strict);
- }
-
- if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
- tokenizer->write(str, true);
}
-void FrameLoader::end()
+void FrameLoader::didEndDocument()
{
m_isLoadingMainResource = false;
- endIfNotLoadingMainResource();
-}
-
-void FrameLoader::endIfNotLoadingMainResource()
-{
- if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
- return;
-
- // http://bugs.webkit.org/show_bug.cgi?id=10854
- // The frame's last ref may be removed and it can be deleted by checkCompleted(),
- // so we'll add a protective refcount
- RefPtr<Frame> protector(m_frame);
-
- // make sure nothing's left in there
- write(0, 0, true);
- m_frame->document()->finishParsing();
}
void FrameLoader::iconLoadDecisionAvailable()
@@ -1059,7 +757,7 @@ void FrameLoader::startIconLoader()
// This is either a reload or the icon database said "yes, load the icon", so kick off the load!
if (!m_iconLoader)
- m_iconLoader.set(IconLoader::create(m_frame).release());
+ m_iconLoader = IconLoader::create(m_frame);
m_iconLoader->startLoading();
}
@@ -1074,7 +772,7 @@ void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
void FrameLoader::finishedParsing()
{
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
m_frame->injectUserScripts(InjectAtDocumentEnd);
@@ -1245,11 +943,7 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
childFrame->loader()->loadArchive(subframeArchive.release());
else
#endif
-#ifdef ANDROID_USER_GESTURE
- childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0, false);
-#else
childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
-#endif
}
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
@@ -1275,74 +969,6 @@ void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
}
#endif
-String FrameLoader::encoding() const
-{
- if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
- return m_encoding;
- if (m_decoder && m_decoder->encoding().isValid())
- return m_decoder->encoding().name();
- Settings* settings = m_frame->settings();
- return settings ? settings->defaultTextEncodingName() : String();
-}
-
-bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
- const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
-{
- if (url.isEmpty() && mimeType.isEmpty())
- return false;
-
- if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
- // It is unsafe to honor the request for this object.
- return false;
- }
-
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = completeURL(url);
-
- bool useFallback;
- if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
- Settings* settings = m_frame->settings();
- if (!m_client->allowPlugins(settings && settings->arePluginsEnabled())
- || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
- return false;
- if (isDocumentSandboxed(SandboxPlugins))
- return false;
- return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
- }
-
- ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
- HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
-
- // If the plug-in element already contains a subframe, requestFrame will re-use it. Otherwise,
- // it will create a new frame and set it as the RenderPart's widget, causing what was previously
- // in the widget to be torn down.
- return requestFrame(element, completedURL, frameName);
-}
-
-bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
-{
- if (m_client->shouldUsePluginDocument(mimeType)) {
- useFallback = false;
- return true;
- }
-
- // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
- // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
- if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
- const PluginData* pluginData = m_frame->page()->pluginData();
- String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
- if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
- return true;
- }
-
- ObjectContentType objectType = m_client->objectContentType(url, mimeType);
- // If an object's content can't be handled and it has no fallback, let
- // it be handled as a plugin to show the broken plugin icon.
- useFallback = objectType == ObjectContentNone && hasFallback;
- return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
-}
-
ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn)
{
String mimeType = mimeTypeIn;
@@ -1356,7 +982,7 @@ ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const S
if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
return WebCore::ObjectContentImage;
-#if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) // Mac has no PluginDatabase, nor does Chromium
+#if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
return WebCore::ObjectContentNetscapePlugin;
#endif
@@ -1367,50 +993,6 @@ ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const S
return WebCore::ObjectContentNone;
}
-static HTMLPlugInElement* toPlugInElement(Node* node)
-{
- if (!node)
- return 0;
-
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
- || node->hasTagName(videoTag) || node->hasTagName(audioTag)
- || node->hasTagName(appletTag));
-#else
- ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
- || node->hasTagName(appletTag));
-#endif
-
- return static_cast<HTMLPlugInElement*>(node);
-}
-
-bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
- const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
-{
- RefPtr<Widget> widget;
-
- if (renderer && !useFallback) {
- HTMLPlugInElement* element = toPlugInElement(renderer->node());
-
- if (!SecurityOrigin::canLoad(url, String(), frame()->document())) {
- FrameLoader::reportLocalLoadFailed(m_frame, url.string());
- return false;
- }
-
- checkIfRunInsecureContent(m_frame->document()->securityOrigin(), url);
-
- widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
- element, url, paramNames, paramValues, mimeType,
- m_frame->document()->isPluginDocument() && !m_containsPlugIns);
- if (widget) {
- renderer->setWidget(widget);
- m_containsPlugIns = true;
- }
- }
-
- return widget != 0;
-}
-
String FrameLoader::outgoingReferrer() const
{
return m_outgoingReferrer;
@@ -1426,7 +1008,7 @@ bool FrameLoader::isMixedContent(SecurityOrigin* context, const KURL& url)
if (context->protocol() != "https")
return false; // We only care about HTTPS security origins.
- if (!url.isValid() || url.protocolIs("https") || url.protocolIs("about") || url.protocolIs("data"))
+ if (!url.isValid() || SchemeRegistry::shouldTreatURLSchemeAsSecure(url.protocol()))
return false; // Loading these protocols is secure.
return true;
@@ -1489,7 +1071,8 @@ void FrameLoader::provisionalLoadStarted()
if (!m_frame->tree()->parent())
android::TimeCounter::reset();
#endif
- m_firstLayoutDone = false;
+ if (m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
m_frame->redirectScheduler()->cancel(true);
m_client->provisionalLoadStarted();
}
@@ -1497,9 +1080,9 @@ void FrameLoader::provisionalLoadStarted()
bool FrameLoader::isProcessingUserGesture()
{
Frame* frame = m_frame->tree()->top();
- if (!frame->script()->canExecuteScripts())
+ if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
- return frame->script()->processingUserGesture(mainThreadNormalWorld()); // FIXME: Use pageIsProcessingUserGesture.
+ return ScriptController::processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
}
void FrameLoader::resetMultipleFormSubmissionProtection()
@@ -1507,12 +1090,10 @@ void FrameLoader::resetMultipleFormSubmissionProtection()
m_submittedFormURL = KURL();
}
-void FrameLoader::setEncoding(const String& name, bool userChosen)
+void FrameLoader::willSetEncoding()
{
if (!m_workingURL.isEmpty())
receivedFirstData();
- m_encoding = name;
- m_encodingWasChosenByUser = userChosen;
}
void FrameLoader::addData(const char* bytes, int length)
@@ -1520,7 +1101,7 @@ void FrameLoader::addData(const char* bytes, int length)
ASSERT(m_workingURL.isEmpty());
ASSERT(m_frame->document());
ASSERT(m_frame->document()->parsing());
- write(bytes, length);
+ writer()->addData(bytes, length);
}
#if ENABLE(WML)
@@ -1534,208 +1115,6 @@ static inline bool frameContainsWMLContent(Frame* frame)
}
#endif
-bool FrameLoader::canCachePageContainingThisFrame()
-{
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
- if (!child->loader()->canCachePageContainingThisFrame())
- return false;
- }
-
- return m_documentLoader
- && m_documentLoader->mainDocumentError().isNull()
- // FIXME: If we ever change this so that frames with plug-ins will be cached,
- // we need to make sure that we don't cache frames that have outstanding NPObjects
- // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
- // they would need to be destroyed and then recreated, and there is no way that we can recreate
- // the right NPObjects. See <rdar://problem/5197041> for more information.
- && !m_containsPlugIns
- && !m_URL.protocolIs("https")
- && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
-#if ENABLE(DATABASE)
- && !m_frame->document()->hasOpenDatabases()
-#endif
-#if ENABLE(SHARED_WORKERS)
- && !SharedWorkerRepository::hasSharedWorkers(m_frame->document())
-#endif
- && !m_frame->document()->usingGeolocation()
- && history()->currentItem()
- && !m_quickRedirectComing
- && !m_documentLoader->isLoadingInAPISense()
- && !m_documentLoader->isStopping()
- && m_frame->document()->canSuspendActiveDOMObjects()
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- // FIXME: We should investigating caching frames that have an associated
- // application cache. <rdar://problem/5917899> tracks that work.
- && m_documentLoader->applicationCacheHost()->canCacheInPageCache()
-#endif
-#if ENABLE(WML)
- && !frameContainsWMLContent(m_frame)
-#endif
- && m_client->canCachePage()
- ;
-}
-
-bool FrameLoader::canCachePage()
-{
-#ifndef NDEBUG
- logCanCachePageDecision();
-#endif
-
- // Cache the page, if possible.
- // Don't write to the cache if in the middle of a redirect, since we will want to
- // store the final page we end up on.
- // No point writing to the cache on a reload or loadSame, since we will just write
- // over it again when we leave that page.
- // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
- // are the most interesting pages on the web, and often those that would benefit the most from caching!
- FrameLoadType loadType = this->loadType();
-
- return !m_frame->tree()->parent()
- && canCachePageContainingThisFrame()
- && m_frame->page()
- && m_frame->page()->backForwardList()->enabled()
- && m_frame->page()->backForwardList()->capacity() > 0
- && m_frame->page()->settings()->usesPageCache()
- && loadType != FrameLoadTypeReload
- && loadType != FrameLoadTypeReloadFromOrigin
- && loadType != FrameLoadTypeSame
- ;
-}
-
-#ifndef NDEBUG
-static String& pageCacheLogPrefix(int indentLevel)
-{
- static int previousIndent = -1;
- DEFINE_STATIC_LOCAL(String, prefix, ());
-
- if (indentLevel != previousIndent) {
- previousIndent = indentLevel;
- prefix.truncate(0);
- for (int i = 0; i < previousIndent; ++i)
- prefix += " ";
- }
-
- return prefix;
-}
-
-static void pageCacheLog(const String& prefix, const String& message)
-{
- LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
-}
-
-#define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
-
-void FrameLoader::logCanCachePageDecision()
-{
- // Only bother logging for main frames that have actually loaded and have content.
- if (m_creatingInitialEmptyDocument)
- return;
- KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
- if (currentURL.isEmpty())
- return;
-
- int indentLevel = 0;
- PCLOG("--------\n Determining if page can be cached:");
-
- bool cannotCache = !logCanCacheFrameDecision(1);
-
- FrameLoadType loadType = this->loadType();
- do {
- if (m_frame->tree()->parent())
- { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
- if (!m_frame->page()) {
- PCLOG(" -There is no Page object");
- cannotCache = true;
- break;
- }
- if (!m_frame->page()->backForwardList()->enabled())
- { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
- if (!(m_frame->page()->backForwardList()->capacity() > 0))
- { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
- if (!m_frame->page()->settings()->usesPageCache())
- { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
- if (loadType == FrameLoadTypeReload)
- { PCLOG(" -Load type is: Reload"); cannotCache = true; }
- if (loadType == FrameLoadTypeReloadFromOrigin)
- { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
- if (loadType == FrameLoadTypeSame)
- { PCLOG(" -Load type is: Same"); cannotCache = true; }
- } while (false);
-
- PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
-}
-
-bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
-{
- // Only bother logging for frames that have actually loaded and have content.
- if (m_creatingInitialEmptyDocument)
- return false;
- KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
- if (currentURL.isEmpty())
- return false;
-
- PCLOG("+---");
- KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
- if (!newURL.isEmpty())
- PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
- else
- PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
-
- bool cannotCache = false;
-
- do {
- if (!m_documentLoader) {
- PCLOG(" -There is no DocumentLoader object");
- cannotCache = true;
- break;
- }
- if (!m_documentLoader->mainDocumentError().isNull())
- { PCLOG(" -Main document has an error"); cannotCache = true; }
- if (m_containsPlugIns)
- { PCLOG(" -Frame contains plugins"); cannotCache = true; }
- if (m_URL.protocolIs("https"))
- { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
- if (m_frame->domWindow() && m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
- { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
-#if ENABLE(DATABASE)
- if (m_frame->document()->hasOpenDatabases())
- { PCLOG(" -Frame has open database handles"); cannotCache = true; }
-#endif
-#if ENABLE(SHARED_WORKERS)
- if (SharedWorkerRepository::hasSharedWorkers(m_frame->document()))
- { PCLOG(" -Frame has associated SharedWorkers"); cannotCache = true; }
-#endif
- if (m_frame->document()->usingGeolocation())
- { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
- if (!history()->currentItem())
- { PCLOG(" -No current history item"); cannotCache = true; }
- if (m_quickRedirectComing)
- { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
- if (m_documentLoader->isLoadingInAPISense())
- { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
- if (m_documentLoader->isStopping())
- { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
- if (!m_frame->document()->canSuspendActiveDOMObjects())
- { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (!m_documentLoader->applicationCacheHost()->canCacheInPageCache())
- { PCLOG(" -The DocumentLoader uses an application cache"); cannotCache = true; }
-#endif
- if (!m_client->canCachePage())
- { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
- } while (false);
-
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
- cannotCache = true;
-
- PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
- PCLOG("+---");
-
- return !cannotCache;
-}
-#endif
-
void FrameLoader::updateFirstPartyForCookies()
{
if (m_frame->tree()->parent())
@@ -1776,7 +1155,10 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
history()->updateBackForwardListForFragmentScroll();
}
+ String oldURL;
bool hashChange = equalIgnoringFragmentIdentifier(url, m_URL) && url.fragmentIdentifier() != m_URL.fragmentIdentifier();
+ oldURL = m_URL;
+
m_URL = url;
history()->updateForSameDocumentNavigation();
@@ -1787,11 +1169,11 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
// It's important to model this as a load that starts and immediately finishes.
// Otherwise, the parent frame may think we never finished loading.
started();
-
- if (hashChange) {
- if (FrameView* view = m_frame->view())
- view->scrollToFragment(m_URL);
- }
+
+ // We need to scroll to the fragment whether or not a hash change occurred, since
+ // the user might have scrolled since the previous navigation.
+ if (FrameView* view = m_frame->view())
+ view->scrollToFragment(m_URL);
m_isComplete = false;
checkCompleted();
@@ -1803,13 +1185,15 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
checkLoadComplete();
}
+ m_client->dispatchDidNavigateWithinPage();
+
if (stateObject) {
m_frame->document()->statePopped(stateObject);
m_client->dispatchDidPopStateWithinPage();
}
if (hashChange) {
- m_frame->document()->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
+ m_frame->document()->enqueueHashchangeEvent(oldURL, url);
m_client->dispatchDidChangeLocationWithinPage();
}
@@ -1842,11 +1226,6 @@ void FrameLoader::started()
frame->loader()->m_isComplete = false;
}
-bool FrameLoader::containsPlugins() const
-{
- return m_containsPlugIns;
-}
-
void FrameLoader::prepareForLoadStart()
{
if (Page* page = m_frame->page())
@@ -1895,7 +1274,7 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
referrer = m_outgoingReferrer;
ASSERT(frame()->document());
- if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
+ if (SchemeRegistry::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
if (!SecurityOrigin::canLoad(url, String(), frame()->document()) && !SecurityOrigin::canLoad(url, referrer, 0)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return;
@@ -1913,17 +1292,10 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
else
loadType = FrameLoadTypeStandard;
-#ifdef ANDROID_USER_GESTURE
- if (request.resourceRequest().httpMethod() == "POST")
- loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
- else
- loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
-#else
if (request.resourceRequest().httpMethod() == "POST")
loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
else
loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
-#endif
// FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
// load if frame names have changed.
@@ -1931,29 +1303,17 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
if (targetFrame && targetFrame != sourceFrame) {
if (Page* page = targetFrame->page())
-#ifdef ANDROID_USER_GESTURE
- page->chrome()->focus(request.resourceRequest().getUserGesture());
-#else
page->chrome()->focus();
-#endif
}
}
-#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
- PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
-#else
void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
-#endif
{
RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState;
ResourceRequest request(newURL);
-#ifdef ANDROID_USER_GESTURE
- request.setUserGesture(userGesture);
-#endif
if (!referrer.isEmpty()) {
request.setHTTPReferrer(referrer);
RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
@@ -1968,15 +1328,11 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
// The search for a target frame is done earlier in the case of form submission.
Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
if (targetFrame && targetFrame != m_frame) {
-#ifdef ANDROID_USER_GESTURE
- targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release(), userGesture);
-#else
targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release());
-#endif
return;
}
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
NavigationAction action(newURL, newLoadType, isFormSubmission, event);
@@ -2102,7 +1458,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ASSERT(m_frame->view());
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
policyChecker()->setLoadType(type);
@@ -2264,6 +1620,7 @@ static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame*
if (!targetFrame)
return false;
+ const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal();
for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
Document* ancestorDocument = ancestorFrame->document();
if (!ancestorDocument)
@@ -2272,6 +1629,10 @@ static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame*
const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
return true;
+
+ // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
+ if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
+ return true;
}
return false;
@@ -2295,16 +1656,16 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
if (m_frame == targetFrame)
return true;
- // A sandboxed frame can only navigate itself and its descendants.
- if (isDocumentSandboxed(SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
- return false;
-
// Let a frame navigate the top-level window that contains it. This is
// important to allow because it lets a site "frame-bust" (escape from a
// frame created by another web site).
- if (targetFrame == m_frame->tree()->top())
+ if (!isDocumentSandboxed(m_frame, SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
return true;
+ // A sandboxed frame can only navigate itself and its descendants.
+ if (isDocumentSandboxed(m_frame, SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
+ return false;
+
// Let a frame navigate its opener if the opener is a top-level window.
if (!targetFrame->tree()->parent() && m_frame->loader()->opener() == targetFrame)
return true;
@@ -2344,7 +1705,7 @@ void FrameLoader::stopLoadingSubframes()
void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy)
{
ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
// If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
@@ -2400,7 +1761,7 @@ bool FrameLoader::isLoading() const
bool FrameLoader::frameHasLoaded() const
{
- return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
+ return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
}
void FrameLoader::setDocumentLoader(DocumentLoader* loader)
@@ -2478,9 +1839,9 @@ void FrameLoader::markLoadComplete()
setState(FrameStateComplete);
}
-void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
+void FrameLoader::commitProvisionalLoad()
{
- RefPtr<CachedPage> cachedPage = prpCachedPage;
+ RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0;
RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data(),
@@ -2488,12 +1849,14 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
// Check to see if we need to cache the page we are navigating away from into the back/forward cache.
// We are doing this here because we know for sure that a new page is about to be loaded.
- cachePageForHistoryItem(history()->currentItem());
+ HistoryItem* item = history()->currentItem();
+ if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())
+ pageCache()->add(item, m_frame->page());
if (m_loadType != FrameLoadTypeReplace)
closeOldDataSources();
- if (!cachedPage && !m_creatingInitialEmptyDocument)
+ if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
m_client->makeRepresentation(pdl.get());
transitionToCommitted(cachedPage);
@@ -2505,9 +1868,11 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
if (m_sentRedirectNotification)
clientRedirectCancelledOrFinished(false);
- if (cachedPage && cachedPage->document())
- open(*cachedPage);
- else {
+ if (cachedPage && cachedPage->document()) {
+ prepareForCachedPageRestore();
+ cachedPage->restore(m_frame->page());
+ checkCompleted();
+ } else {
KURL url = pdl->substituteData().responseURL();
if (url.isEmpty())
url = pdl->url();
@@ -2595,18 +1960,24 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
case FrameLoadTypeIndexedBackForward:
if (Page* page = m_frame->page()) {
if (page->backForwardList()) {
+ // If the first load within a frame is a navigation within a back/forward list that was attached
+ // without any of the items being loaded then we need to update the history in a similar manner as
+ // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
+
history()->updateForBackForwardNavigation();
if (history()->currentItem())
m_pendingStateObject = history()->currentItem()->stateObject();
-
+
// Create a document view for this document, or used the cached view.
if (cachedPage) {
DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
ASSERT(cachedDocumentLoader);
cachedDocumentLoader->setFrame(m_frame);
m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
-
+
} else
m_client->transitionToCommittedForNewPage();
}
@@ -2643,15 +2014,16 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
ASSERT_NOT_REACHED();
}
- m_responseMIMEType = dl->responseMIMEType();
+ writer()->setMIMEType(dl->responseMIMEType());
// Tell the client we've committed this URL.
ASSERT(m_frame->view());
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
-
- m_committedFirstRealDocumentLoad = true;
+
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
if (!m_client->hasHTMLView())
receivedFirstData();
@@ -2690,7 +2062,7 @@ void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
// load as part of the original navigation. If we don't have a document loader, we have
// no "original" load on which to base a redirect, so we treat the redirect as a normal load.
// Loads triggered by JavaScript form submissions never count as quick redirects.
- m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction;
+ m_quickRedirectComing = (lockBackForwardList || history()->currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
}
bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
@@ -2723,7 +2095,7 @@ void FrameLoader::closeOldDataSources()
m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
}
-void FrameLoader::open(CachedPage& cachedPage)
+void FrameLoader::prepareForCachedPageRestore()
{
ASSERT(!m_frame->tree()->parent());
ASSERT(m_frame->page());
@@ -2735,14 +2107,12 @@ void FrameLoader::open(CachedPage& cachedPage)
closeURL();
// Delete old status bar messages (if it _was_ activated on last URL).
- if (m_frame->script()->canExecuteScripts()) {
- m_frame->setJSStatusBarText(String());
- m_frame->setJSDefaultStatusBarText(String());
+ if (m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) {
+ if (DOMWindow* window = m_frame->existingDOMWindow()) {
+ window->setStatus(String());
+ window->setDefaultStatus(String());
+ }
}
-
- cachedPage.restore(m_frame->page());
-
- checkCompleted();
}
void FrameLoader::open(CachedFrameBase& cachedFrame)
@@ -2788,7 +2158,7 @@ void FrameLoader::open(CachedFrameBase& cachedFrame)
m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
- m_decoder = document->decoder();
+ writer()->setDecoder(document->decoder());
updateFirstPartyForCookies();
@@ -2850,7 +2220,7 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
{
// FIXME: Platforms shouldn't differ here!
#if PLATFORM(WIN) || PLATFORM(CHROMIUM) || defined(ANDROID)
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
#endif
@@ -2881,14 +2251,14 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
ArchiveResource* mainResource = archive->mainResource();
loader->setParsedArchiveData(mainResource->data());
- m_responseMIMEType = mainResource->mimeType();
+ writer()->setMIMEType(mainResource->mimeType());
closeURL();
didOpenURL(mainResource->url());
String userChosenEncoding = documentLoader()->overrideEncoding();
bool encodingIsUserChosen = !userChosenEncoding.isNull();
- setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
+ writer()->setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
ASSERT(m_frame->document());
@@ -2924,6 +2294,9 @@ bool FrameLoader::subframeIsLoading() const
documentLoader = childLoader->provisionalDocumentLoader();
if (documentLoader && documentLoader->isLoadingInAPISense())
return true;
+ documentLoader = childLoader->policyDocumentLoader();
+ if (documentLoader)
+ return true;
}
return false;
}
@@ -3046,7 +2419,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
history()->restoreScrollPositionAndViewState();
- if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
+ if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
return;
const ResourceError& error = dl->mainDocumentError();
@@ -3103,6 +2476,9 @@ void FrameLoader::continueLoadAfterWillSubmitForm()
notifier()->assignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
}
+ ASSERT(!m_provisionalDocumentLoader->timing()->navigationStart);
+ m_provisionalDocumentLoader->timing()->navigationStart = currentTime();
+
if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
m_provisionalDocumentLoader->updateLoading();
}
@@ -3113,7 +2489,8 @@ void FrameLoader::didFirstLayout()
if (isBackForwardLoadType(m_loadType) && page->backForwardList())
history()->restoreScrollPositionAndViewState();
- m_firstLayoutDone = true;
+ if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
m_client->dispatchDidFirstLayout();
}
@@ -3132,13 +2509,8 @@ void FrameLoader::frameLoadCompleted()
// After a canceled provisional load, firstLayoutDone is false.
// Reset it to true if we're displaying a page.
- if (m_documentLoader)
- m_firstLayoutDone = true;
-}
-
-bool FrameLoader::firstLayoutDone() const
-{
- return m_firstLayoutDone;
+ if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
}
void FrameLoader::detachChildren()
@@ -3206,18 +2578,16 @@ String FrameLoader::userAgent(const KURL& url) const
return m_client->userAgent(url);
}
-void FrameLoader::tokenizerProcessedData()
-{
- checkCompleted();
-}
-
void FrameLoader::handledOnloadEvents()
{
m_client->dispatchDidHandleOnloadEvents();
+
+ if (documentLoader()) {
+ documentLoader()->handledOnloadEvents();
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (documentLoader())
documentLoader()->applicationCacheHost()->stopDeferringEvents();
#endif
+ }
}
void FrameLoader::frameDetached()
@@ -3286,14 +2656,30 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
applyUserAgent(request);
- if (loadType == FrameLoadTypeReload) {
+ // If we inherit cache policy from a main resource, we use the DocumentLoader's
+ // original request cache policy for two reasons:
+ // 1. For POST requests, we mutate the cache policy for the main resource,
+ // but we do not want this to apply to subresources
+ // 2. Delegates that modify the cache policy using willSendRequest: should
+ // not affect any other resources. Such changes need to be done
+ // per request.
+ if (!mainResource) {
+ if (request.isConditional())
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ else if (documentLoader()->isLoadingInAPISense())
+ request.setCachePolicy(documentLoader()->originalRequest().cachePolicy());
+ else
+ request.setCachePolicy(UseProtocolCachePolicy);
+ } else if (loadType == FrameLoadTypeReload) {
request.setCachePolicy(ReloadIgnoringCacheData);
request.setHTTPHeaderField("Cache-Control", "max-age=0");
} else if (loadType == FrameLoadTypeReloadFromOrigin) {
request.setCachePolicy(ReloadIgnoringCacheData);
request.setHTTPHeaderField("Cache-Control", "no-cache");
request.setHTTPHeaderField("Pragma", "no-cache");
- } else if (isBackForwardLoadType(loadType) && !request.url().protocolIs("https"))
+ } else if (request.isConditional())
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ else if (isBackForwardLoadType(loadType) && m_stateMachine.committedFirstRealDocumentLoad() && !request.url().protocolIs("https"))
request.setCachePolicy(ReturnCacheDataElseLoad);
if (mainResource)
@@ -3305,7 +2691,7 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
// Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
// For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
Settings* settings = m_frame->settings();
- request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
+ request.setResponseContentDispositionEncodingFallbackArray("UTF-8", writer()->deprecatedFrameEncoding(), settings ? settings->defaultTextEncodingName() : String());
}
void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
@@ -3343,11 +2729,7 @@ void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int le
m_client->committedLoad(loader, data, length);
}
-#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
-#else
void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
-#endif
{
RefPtr<FormState> formState = prpFormState;
@@ -3367,9 +2749,6 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
String origin = inRequest.httpOrigin();
ResourceRequest workingResourceRequest(url);
-#ifdef ANDROID_USER_GESTURE
- workingResourceRequest.setUserGesture(userGesture);
-#endif
if (!referrer.isEmpty())
workingResourceRequest.setHTTPReferrer(referrer);
@@ -3400,17 +2779,6 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
ResourceRequest initialRequest = request;
initialRequest.setTimeoutInterval(10);
- // Use the original request's cache policy for two reasons:
- // 1. For POST requests, we mutate the cache policy for the main resource,
- // but we do not want this to apply to subresources
- // 2. Delegates that modify the cache policy using willSendRequest: should
- // not affect any other resources. Such changes need to be done
- // per request.
- if (initialRequest.isConditional())
- initialRequest.setCachePolicy(ReloadIgnoringCacheData);
- else
- initialRequest.setCachePolicy(originalRequest().cachePolicy());
-
if (!referrer.isEmpty())
initialRequest.setHTTPReferrer(referrer);
addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
@@ -3418,6 +2786,8 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
if (Page* page = m_frame->page())
initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
+
+ addExtraFieldsToSubresourceRequest(initialRequest);
unsigned long identifier = 0;
ResourceRequest newRequest(initialRequest);
@@ -3526,6 +2896,36 @@ void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
}
+bool FrameLoader::shouldClose()
+{
+ Page* page = m_frame->page();
+ Chrome* chrome = page ? page->chrome() : 0;
+ if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
+ return true;
+
+ DOMWindow* domWindow = m_frame->existingDOMWindow();
+ if (!domWindow)
+ return true;
+
+ RefPtr<Document> document = m_frame->document();
+ HTMLElement* body = document->body();
+ if (!body)
+ return true;
+
+ RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+ m_pageDismissalEventBeingDispatched = true;
+ domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
+ m_pageDismissalEventBeingDispatched = false;
+
+ if (!beforeUnloadEvent->defaultPrevented())
+ document->defaultEventHandler(beforeUnloadEvent.get());
+ if (beforeUnloadEvent->result().isNull())
+ return true;
+
+ String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->result());
+ return chrome->runBeforeUnloadConfirmPanel(text, m_frame);
+}
+
void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
{
// If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
@@ -3540,7 +2940,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
// is the user responding Cancel to the form repost nag sheet.
// 2) User responded Cancel to an alert popped up by the before unload event handler.
// The "before unload" event handler runs only for the main frame.
- bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
+ bool canContinue = shouldContinue && (!isLoadingMainFrame() || shouldClose());
if (!canContinue) {
// If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
@@ -3576,7 +2976,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) && USE(JSC)
if (Page* page = m_frame->page()) {
if (page->mainFrame() == m_frame)
- page->inspectorController()->resumeDebugger();
+ page->inspectorController()->resume();
}
#endif
@@ -3586,8 +2986,10 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
setPolicyDocumentLoader(0);
- if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
+ if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {
+ loadProvisionalItemFromCachedPage();
return;
+ }
if (formState)
m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
@@ -3650,14 +3052,13 @@ void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
if (!page)
return;
-#if ENABLE(INSPECTOR)
- page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
-#endif
-
if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
return;
if (!page->areMemoryCacheClientCallsEnabled()) {
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
+#endif
m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
@@ -3665,6 +3066,9 @@ void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
ResourceRequest request(resource->url());
if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
+#endif
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
}
@@ -3700,48 +3104,22 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con
return false;
}
-bool FrameLoader::loadProvisionalItemFromCachedPage()
+void FrameLoader::loadProvisionalItemFromCachedPage()
{
- RefPtr<CachedPage> cachedPage = pageCache()->get(history()->provisionalItem());
- if (!cachedPage || !cachedPage->document())
- return false;
+ DocumentLoader* provisionalLoader = provisionalDocumentLoader();
+ LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().string().utf8().data());
- DocumentLoader *provisionalLoader = provisionalDocumentLoader();
- LOG(PageCache, "WebCorePageCache: FrameLoader %p loading provisional DocumentLoader %p with URL '%s' from CachedPage %p", this, provisionalLoader, provisionalLoader->url().string().utf8().data(), cachedPage.get());
-
provisionalLoader->prepareForLoadStart();
m_loadingFromCachedPage = true;
-
- provisionalLoader->setCommitted(true);
- commitProvisionalLoad(cachedPage);
-
- return true;
-}
-
-void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
-{
- if (!canCachePage() || item->isInPageCache())
- return;
-
- pageHidden();
- if (Page* page = m_frame->page()) {
- RefPtr<CachedPage> cachedPage = CachedPage::create(page);
- pageCache()->add(item, cachedPage.release());
- }
-}
-
-void FrameLoader::pageHidden()
-{
- m_unloadEventBeingDispatched = true;
- if (m_frame->domWindow())
- m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, true), m_frame->document());
- m_unloadEventBeingDispatched = false;
+ // Should have timing data from previous time(s) the page was shown.
+ ASSERT(provisionalLoader->timing()->navigationStart);
+ provisionalLoader->resetTiming();
+ provisionalLoader->timing()->navigationStart = currentTime();
- // Send pagehide event for subframes as well
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- child->loader()->pageHidden();
+ provisionalLoader->setCommitted(true);
+ commitProvisionalLoad();
}
bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
@@ -3767,7 +3145,7 @@ Frame* FrameLoader::findFrameForNavigation(const AtomicString& name)
{
Frame* frame = m_frame->tree()->find(name);
if (!shouldAllowNavigation(frame))
- return 0;
+ return 0;
return frame;
}
@@ -3797,21 +3175,10 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
{
// Remember this item so we can traverse any child items as child frames load
history()->setProvisionalItem(item);
-
- // Check if we'll be using the page cache. We only use the page cache
- // if one exists and it is less than _backForwardCacheExpirationInterval
- // seconds old. If the cache is expired it gets flushed here.
- if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
- // FIXME: 1800 should not be hardcoded, it should come from
- // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
- // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
- if (currentTime() - cachedPage->timeStamp() <= 1800) {
- loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
- return;
- }
-
- LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", history()->provisionalItem()->url().string().ascii().data());
- pageCache()->remove(item);
+
+ if (CachedPage* cachedPage = pageCache()->get(item)) {
+ loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
+ return;
}
KURL itemURL = item->url();
@@ -3830,7 +3197,7 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
// If this was a repost that failed the page cache, we might try to repost the form.
NavigationAction action;
if (formData) {
- formData->generateFiles(m_frame->page()->chrome()->client());
+ formData->generateFiles(m_frame->document());
request.setHTTPMethod("POST");
request.setHTTPBody(formData);
@@ -3867,7 +3234,9 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
case FrameLoadTypeBackWMLDeckNotAccessible:
case FrameLoadTypeForward:
case FrameLoadTypeIndexedBackForward:
- if (!itemURL.protocolIs("https"))
+ // If the first load within a frame is a navigation within a back/forward list that was attached
+ // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
+ if (m_stateMachine.committedFirstRealDocumentLoad() && !itemURL.protocolIs("https"))
request.setCachePolicy(ReturnCacheDataElseLoad);
break;
case FrameLoadTypeStandard:
@@ -3891,12 +3260,11 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
{
// We do same-document navigation in the following cases:
- // - The HistoryItem has a history state object
- // - Navigating to an anchor within the page, with no form data stored on the target item or the current history entry,
- // and the URLs in the frame tree match the history item for fragment scrolling.
+ // - The HistoryItem corresponds to the same document.
+ // - The HistoryItem is not the same as the current item.
HistoryItem* currentItem = history()->currentItem();
- bool sameDocumentNavigation = (!item->formData() && !(currentItem && currentItem->formData()) && history()->urlsMatchItem(item))
- || (currentItem && item->documentSequenceNumber() == currentItem->documentSequenceNumber());
+ bool sameDocumentNavigation = currentItem && item != currentItem
+ && item->documentSequenceNumber() == currentItem->documentSequenceNumber();
#if ENABLE(WML)
// All WML decks should go through the real load mechanism, not the scroll-to-anchor code
@@ -3961,11 +3329,23 @@ bool FrameLoader::shouldUseCredentialStorage(ResourceLoader* loader)
return m_client->shouldUseCredentialStorage(loader->documentLoader(), loader->identifier());
}
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+bool FrameLoader::canAuthenticateAgainstProtectionSpace(ResourceLoader* loader, const ProtectionSpace& protectionSpace)
+{
+ return m_client->canAuthenticateAgainstProtectionSpace(loader->documentLoader(), loader->identifier(), protectionSpace);
+}
+#endif
+
void FrameLoader::setTitle(const String& title)
{
documentLoader()->setTitle(title);
}
+void FrameLoader::setIconURL(const String& iconURL)
+{
+ documentLoader()->setIconURL(iconURL);
+}
+
KURL FrameLoader::originalRequestURL() const
{
return activeDocumentLoader()->originalRequest().url();
@@ -3973,7 +3353,7 @@ KURL FrameLoader::originalRequestURL() const
String FrameLoader::referrer() const
{
- return documentLoader()->request().httpReferrer();
+ return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
}
void FrameLoader::dispatchDocumentElementAvailable()
@@ -3984,7 +3364,7 @@ void FrameLoader::dispatchDocumentElementAvailable()
void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
{
- if (!m_frame->script()->canExecuteScripts())
+ if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return;
Vector<DOMWrapperWorld*> worlds;
@@ -3995,7 +3375,7 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
{
- if (!m_frame->script()->canExecuteScripts() || !m_frame->script()->existingWindowShell(world))
+ if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript) || !m_frame->script()->existingWindowShell(world))
return;
m_client->dispatchDidClearWindowObjectInWorld(world);
@@ -4007,15 +3387,13 @@ void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
if (Page* page = m_frame->page()) {
if (InspectorController* inspector = page->inspectorController())
inspector->inspectedWindowScriptObjectCleared(m_frame);
- if (InspectorController* inspector = page->parentInspectorController())
- inspector->windowScriptObjectAvailable();
}
#endif
}
void FrameLoader::updateSandboxFlags()
{
- SandboxFlags flags = SandboxNone;
+ SandboxFlags flags = m_forcedSandboxFlags;
if (Frame* parentFrame = m_frame->tree()->parent())
flags |= parentFrame->loader()->sandboxFlags();
if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
@@ -4030,47 +3408,6 @@ void FrameLoader::updateSandboxFlags()
child->loader()->updateSandboxFlags();
}
-bool FrameLoader::isDocumentSandboxed(SandboxFlags mask) const
-{
- return m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(mask);
-}
-
-PassRefPtr<Widget> FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
-{
- String baseURLString;
- String codeBaseURLString;
- Vector<String> paramNames;
- Vector<String> paramValues;
- HashMap<String, String>::const_iterator end = args.end();
- for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
- if (equalIgnoringCase(it->first, "baseurl"))
- baseURLString = it->second;
- else if (equalIgnoringCase(it->first, "codebase"))
- codeBaseURLString = it->second;
- paramNames.append(it->first);
- paramValues.append(it->second);
- }
-
- if (!codeBaseURLString.isEmpty()) {
- KURL codeBaseURL = completeURL(codeBaseURLString);
- if (!SecurityOrigin::canLoad(codeBaseURL, String(), element->document())) {
- FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
- return 0;
- }
- }
-
- if (baseURLString.isEmpty())
- baseURLString = m_frame->document()->baseURL().string();
- KURL baseURL = completeURL(baseURLString);
-
- RefPtr<Widget> widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
- if (!widget)
- return 0;
-
- m_containsPlugIns = true;
- return widget;
-}
-
void FrameLoader::didChangeTitle(DocumentLoader* loader)
{
m_client->didChangeTitle(loader);
@@ -4085,9 +3422,15 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader)
}
}
+void FrameLoader::didChangeIcons(DocumentLoader* loader)
+{
+ if (loader == m_documentLoader)
+ m_client->dispatchDidChangeIcons();
+}
+
void FrameLoader::dispatchDidCommitLoad()
{
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
#ifndef NDEBUG
@@ -4134,4 +3477,69 @@ bool FrameLoaderClient::hasHTMLView() const
return true;
}
+Frame* createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
+{
+ ASSERT(!features.dialog || request.frameName().isEmpty());
+
+ if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
+ Frame* frame = lookupFrame->tree()->find(request.frameName());
+ if (frame && openerFrame->loader()->shouldAllowNavigation(frame)) {
+ if (!request.resourceRequest().url().isEmpty())
+ frame->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
+ if (Page* page = frame->page())
+ page->chrome()->focus();
+ created = false;
+ return frame;
+ }
+ }
+
+ // Sandboxed frames cannot open new auxiliary browsing contexts.
+ if (isDocumentSandboxed(openerFrame, SandboxNavigation))
+ return 0;
+
+ // FIXME: Setting the referrer should be the caller's responsibility.
+ FrameLoadRequest requestWithReferrer = request;
+ requestWithReferrer.resourceRequest().setHTTPReferrer(openerFrame->loader()->outgoingReferrer());
+ FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin());
+
+ Page* oldPage = openerFrame->page();
+ if (!oldPage)
+ return 0;
+
+ Page* page = oldPage->chrome()->createWindow(openerFrame, requestWithReferrer, features);
+ if (!page)
+ return 0;
+
+ Frame* frame = page->mainFrame();
+ if (request.frameName() != "_blank")
+ frame->tree()->setName(request.frameName());
+
+ page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
+ page->chrome()->setStatusbarVisible(features.statusBarVisible);
+ page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
+ page->chrome()->setMenubarVisible(features.menuBarVisible);
+ page->chrome()->setResizable(features.resizable);
+
+ // 'x' and 'y' specify the location of the window, while 'width' and 'height'
+ // specify the size of the page. We can only resize the window, so
+ // adjust for the difference between the window size and the page size.
+
+ FloatRect windowRect = page->chrome()->windowRect();
+ FloatSize pageSize = page->chrome()->pageRect().size();
+ if (features.xSet)
+ windowRect.setX(features.x);
+ if (features.ySet)
+ windowRect.setY(features.y);
+ if (features.widthSet)
+ windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
+ if (features.heightSet)
+ windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
+ page->chrome()->setWindowRect(windowRect);
+
+ page->chrome()->show();
+
+ created = true;
+ return frame;
+}
+
} // namespace WebCore