summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp193
1 files changed, 114 insertions, 79 deletions
diff --git a/src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp b/src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp
index 4321be0..807edef 100644
--- a/src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp
+++ b/src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp
@@ -71,6 +71,7 @@
#include "Page.h"
#include "PageCache.h"
#include "PageGroup.h"
+#include "PageTransitionEvent.h"
#include "PlaceholderDocument.h"
#include "PluginData.h"
#include "PluginDocument.h"
@@ -138,6 +139,7 @@ struct ScheduledRedirection {
const bool wasUserGesture;
const bool wasRefresh;
const bool wasDuringLoad;
+ bool toldClient;
ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
: type(redirection)
@@ -149,6 +151,7 @@ struct ScheduledRedirection {
, wasUserGesture(wasUserGesture)
, wasRefresh(refresh)
, wasDuringLoad(false)
+ , toldClient(false)
{
ASSERT(!url.isEmpty());
}
@@ -164,6 +167,7 @@ struct ScheduledRedirection {
, wasUserGesture(wasUserGesture)
, wasRefresh(refresh)
, wasDuringLoad(duringLoad)
+ , toldClient(false)
{
ASSERT(!url.isEmpty());
}
@@ -177,6 +181,7 @@ struct ScheduledRedirection {
, wasUserGesture(false)
, wasRefresh(false)
, wasDuringLoad(false)
+ , toldClient(false)
{
}
@@ -194,6 +199,7 @@ struct ScheduledRedirection {
, wasUserGesture(false)
, wasRefresh(false)
, wasDuringLoad(duringLoad)
+ , toldClient(false)
{
ASSERT(!frameRequest.isEmpty());
ASSERT(this->formState);
@@ -267,8 +273,9 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
, m_encodingWasChosenByUser(false)
, m_containsPlugIns(false)
, m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
- , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
- , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
+ , m_checkTimer(this, &FrameLoader::checkTimerFired)
+ , m_shouldCallCheckCompleted(false)
+ , m_shouldCallCheckLoadComplete(false)
, m_opener(0)
, m_openedByDOM(false)
, m_creatingInitialEmptyDocument(false)
@@ -318,6 +325,11 @@ void FrameLoader::setDefersLoading(bool defers)
m_provisionalDocumentLoader->setDefersLoading(defers);
if (m_policyDocumentLoader)
m_policyDocumentLoader->setDefersLoading(defers);
+
+ if (!defers) {
+ startRedirectionTimer();
+ startCheckCompleteTimer();
+ }
}
Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
@@ -581,9 +593,9 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
m_unloadEventBeingDispatched = true;
if (m_frame->domWindow()) {
if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide)
- m_frame->domWindow()->dispatchPageTransitionEvent(EventNames().pagehideEvent, m_frame->document()->inPageCache());
+ m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document());
if (!m_frame->document()->inPageCache())
- m_frame->domWindow()->dispatchUnloadEvent();
+ m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
}
m_unloadEventBeingDispatched = false;
if (m_frame->document())
@@ -597,7 +609,7 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
m_frame->document()->removeAllEventListeners();
}
- m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
+ m_isComplete = true; // to avoid calling completed() in finishedParsing()
m_isLoadingMainResource = false;
m_didCallImplicitClose = true; // don't want that one either
@@ -656,8 +668,6 @@ void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
stopRedirectionTimer();
-
- m_scheduledRedirection.clear();
}
KURL FrameLoader::iconURL()
@@ -743,8 +753,10 @@ bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool
const int javascriptSchemeLength = sizeof("javascript:") - 1;
- String script = decodeURLEscapeSequences(url.string().substring(javascriptSchemeLength));
- ScriptValue result = executeScript(script, userGesture);
+ String script = url.string().substring(javascriptSchemeLength);
+ ScriptValue result;
+ if (m_frame->script()->xssAuditor()->canEvaluateJavaScriptURL(script))
+ result = executeScript(decodeURLEscapeSequences(script), userGesture);
String scriptResult;
if (!result.getString(scriptResult))
@@ -844,8 +856,9 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
m_redirectionTimer.stop();
m_scheduledRedirection.clear();
- m_checkCompletedTimer.stop();
- m_checkLoadCompleteTimer.stop();
+ m_checkTimer.stop();
+ m_shouldCallCheckCompleted = false;
+ m_shouldCallCheckLoadComplete = false;
m_receivedData = false;
m_isDisplayingInitialEmptyDocument = false;
@@ -1238,15 +1251,34 @@ void FrameLoader::loadDone()
checkCompleted();
}
+bool FrameLoader::allChildrenAreComplete() const
+{
+ for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
+ if (!child->loader()->m_isComplete)
+ return false;
+ }
+ return true;
+}
+
+bool FrameLoader::allAncestorsAreComplete() const
+{
+ for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) {
+ if (!ancestor->loader()->m_isComplete)
+ return false;
+ }
+ return true;
+}
+
void FrameLoader::checkCompleted()
{
+ m_shouldCallCheckCompleted = false;
+
if (m_frame->view())
m_frame->view()->checkStopDelayingDeferredRepaints();
// Any frame that hasn't completed yet?
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- if (!child->loader()->m_isComplete)
- return;
+ if (!allChildrenAreComplete())
+ return;
// Have we completed before?
if (m_isComplete)
@@ -1266,38 +1298,44 @@ void FrameLoader::checkCompleted()
RefPtr<Frame> protect(m_frame);
checkCallImplicitClose(); // if we didn't do it before
- // Do not start a redirection timer for subframes here.
- // That is deferred until the parent is completed.
- if (m_scheduledRedirection && !m_frame->tree()->parent())
- startRedirectionTimer();
+ startRedirectionTimer();
completed();
if (m_frame->page())
checkLoadComplete();
}
-void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
+void FrameLoader::checkTimerFired(Timer<FrameLoader>*)
{
- checkCompleted();
+ if (Page* page = m_frame->page()) {
+ if (page->defersLoading())
+ return;
+ }
+ if (m_shouldCallCheckCompleted)
+ checkCompleted();
+ if (m_shouldCallCheckLoadComplete)
+ checkLoadComplete();
}
-void FrameLoader::scheduleCheckCompleted()
+void FrameLoader::startCheckCompleteTimer()
{
- if (!m_checkCompletedTimer.isActive())
- m_checkCompletedTimer.startOneShot(0);
+ if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete))
+ return;
+ if (m_checkTimer.isActive())
+ return;
+ m_checkTimer.startOneShot(0);
}
-void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
+void FrameLoader::scheduleCheckCompleted()
{
- if (!m_frame->page())
- return;
- checkLoadComplete();
+ m_shouldCallCheckCompleted = true;
+ startCheckCompleteTimer();
}
void FrameLoader::scheduleCheckLoadComplete()
{
- if (!m_checkLoadCompleteTimer.isActive())
- m_checkLoadCompleteTimer.startOneShot(0);
+ m_shouldCallCheckLoadComplete = true;
+ startCheckCompleteTimer();
}
void FrameLoader::checkCallImplicitClose()
@@ -1305,9 +1343,8 @@ void FrameLoader::checkCallImplicitClose()
if (m_didCallImplicitClose || m_frame->document()->parsing())
return;
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- if (!child->loader()->m_isComplete) // still got a frame running -> too early
- return;
+ if (!allChildrenAreComplete())
+ return; // still got a frame running -> too early
m_didCallImplicitClose = true;
m_wasUnloadEventEmitted = false;
@@ -1427,12 +1464,6 @@ void FrameLoader::scheduleHistoryNavigation(int steps)
if (!m_frame->page())
return;
- // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload.
- if (!canGoBackOrForward(steps)) {
- cancelRedirection();
- return;
- }
-
scheduleRedirection(new ScheduledRedirection(steps));
}
@@ -1470,6 +1501,9 @@ void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
{
ASSERT(m_frame->page());
+ if (m_frame->page()->defersLoading())
+ return;
+
OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
switch (redirection->type) {
@@ -1486,7 +1520,8 @@ void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
}
// go(i!=0) from a frame navigates into the history of the frame only,
// in both IE and NS (but not in Mozilla). We can't easily do that.
- goBackOrForward(redirection->historySteps);
+ if (canGoBackOrForward(redirection->historySteps))
+ goBackOrForward(redirection->historySteps);
return;
case ScheduledRedirection::formSubmission:
// The submitForm function will find a target frame before using the redirection timer.
@@ -1710,12 +1745,6 @@ bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String
return widget != 0;
}
-void FrameLoader::parentCompleted()
-{
- if (m_scheduledRedirection && !m_redirectionTimer.isActive())
- startRedirectionTimer();
-}
-
String FrameLoader::outgoingReferrer() const
{
return m_outgoingReferrer;
@@ -1854,7 +1883,7 @@ bool FrameLoader::canCachePageContainingThisFrame()
&& !m_containsPlugIns
&& !m_URL.protocolIs("https")
#ifndef PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS
- && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListener(eventNames().unloadEvent))
+ && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
#endif
#if ENABLE(DATABASE)
&& !m_frame->document()->hasOpenDatabases()
@@ -2001,7 +2030,7 @@ bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
if (m_URL.protocolIs("https"))
{ PCLOG(" -Frame is HTTPS"); cannotCache = true; }
#ifndef PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS
- if (m_frame->domWindow() && m_frame->domWindow()->hasEventListener(eventNames().unloadEvent))
+ if (m_frame->domWindow() && m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
{ PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
#endif
#if ENABLE(DATABASE)
@@ -2068,7 +2097,7 @@ public:
virtual void performTask(ScriptExecutionContext* context)
{
ASSERT_UNUSED(context, context->isDocument());
- m_document->dispatchWindowEvent(eventNames().hashchangeEvent, false, false);
+ m_document->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
}
private:
@@ -2110,7 +2139,7 @@ bool FrameLoader::isComplete() const
return m_isComplete;
}
-void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
+void FrameLoader::scheduleRedirection(PassOwnPtr<ScheduledRedirection> redirection)
{
ASSERT(m_frame->page());
@@ -2124,24 +2153,33 @@ void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
}
stopRedirectionTimer();
- m_scheduledRedirection.set(redirection);
- if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
+ m_scheduledRedirection = redirection;
+ if (!m_isComplete && m_scheduledRedirection->type != ScheduledRedirection::redirection)
completed();
- if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
- startRedirectionTimer();
+ startRedirectionTimer();
}
void FrameLoader::startRedirectionTimer()
{
+ if (!m_scheduledRedirection)
+ return;
+
ASSERT(m_frame->page());
- ASSERT(m_scheduledRedirection);
- m_redirectionTimer.stop();
+ if (m_redirectionTimer.isActive())
+ return;
+
+ if (m_scheduledRedirection->type == ScheduledRedirection::redirection && !allAncestorsAreComplete())
+ return;
+
m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
switch (m_scheduledRedirection->type) {
case ScheduledRedirection::locationChange:
case ScheduledRedirection::redirection:
+ if (m_scheduledRedirection->toldClient)
+ return;
+ m_scheduledRedirection->toldClient = true;
clientRedirected(KURL(ParsedURLString, m_scheduledRedirection->url),
m_scheduledRedirection->delay,
currentTime() + m_redirectionTimer.nextFireInterval(),
@@ -2161,35 +2199,18 @@ void FrameLoader::startRedirectionTimer()
void FrameLoader::stopRedirectionTimer()
{
- if (!m_redirectionTimer.isActive())
- return;
-
m_redirectionTimer.stop();
- if (m_scheduledRedirection) {
- switch (m_scheduledRedirection->type) {
- case ScheduledRedirection::locationChange:
- case ScheduledRedirection::redirection:
- clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
- return;
- case ScheduledRedirection::formSubmission:
- // FIXME: It would make sense to report form submissions as client redirects too.
- // But we didn't do that in the past when form submission used a separate delay
- // mechanism, so doing it will be a behavior change.
- return;
- case ScheduledRedirection::historyNavigation:
- // Don't report history navigations.
- return;
- }
- ASSERT_NOT_REACHED();
- }
+ OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
+ if (redirection && redirection->toldClient)
+ clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
}
void FrameLoader::completed()
{
RefPtr<Frame> protect(m_frame);
for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- child->loader()->parentCompleted();
+ child->loader()->startRedirectionTimer();
if (Frame* parent = m_frame->tree()->parent())
parent->loader()->checkCompleted();
if (m_frame->view())
@@ -2291,6 +2312,9 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
{
+ if (m_unloadEventBeingDispatched)
+ return;
+
RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState;
@@ -2330,6 +2354,7 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) {
oldDocumentLoader->setTriggeringAction(action);
stopPolicyCheck();
+ m_policyLoadType = newLoadType;
checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(),
callContinueFragmentScrollAfterNavigationPolicy, this);
} else {
@@ -2434,6 +2459,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ASSERT(m_frame->view());
+ if (m_unloadEventBeingDispatched)
+ return;
+
m_policyLoadType = type;
RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState;
@@ -2670,7 +2698,8 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
//
// Or the target frame is:
// - a top-level frame in the frame hierarchy and the active frame can
- // navigate the target frame's opener per above.
+ // navigate the target frame's opener per above or it is the opener of
+ // the target frame.
if (!targetFrame)
return true;
@@ -2685,6 +2714,10 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
if (targetFrame == m_frame->tree()->top())
return true;
+ // 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;
+
Document* activeDocument = m_frame->document();
ASSERT(activeDocument);
const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin();
@@ -2900,7 +2933,7 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
m_frame->document()->documentDidBecomeActive();
// Force a layout to update view size and thereby update scrollbars.
- m_client->forceLayout();
+ m_frame->view()->forceLayout();
const ResponseVector& responses = m_documentLoader->responses();
size_t count = responses.size();
@@ -3554,6 +3587,8 @@ void FrameLoader::checkLoadComplete()
{
ASSERT(m_client->hasWebView());
+ m_shouldCallCheckLoadComplete = false;
+
// FIXME: Always traversing the entire frame tree is a bit inefficient, but
// is currently needed in order to null out the previous history item for all frames.
if (Page* page = m_frame->page())
@@ -4288,7 +4323,7 @@ void FrameLoader::pageHidden()
{
m_unloadEventBeingDispatched = true;
if (m_frame->domWindow())
- m_frame->domWindow()->dispatchPageTransitionEvent(EventNames().pagehideEvent, true);
+ m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, true), m_frame->document());
m_unloadEventBeingDispatched = false;
// Send pagehide event for subframes as well