diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/loader/FrameLoader.cpp | 193 |
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 |