summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/PageThrottler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/PageThrottler.cpp')
-rw-r--r--Source/WebCore/page/PageThrottler.cpp145
1 files changed, 128 insertions, 17 deletions
diff --git a/Source/WebCore/page/PageThrottler.cpp b/Source/WebCore/page/PageThrottler.cpp
index 824cfd129..28c63f1e1 100644
--- a/Source/WebCore/page/PageThrottler.cpp
+++ b/Source/WebCore/page/PageThrottler.cpp
@@ -26,42 +26,153 @@
#include "config.h"
#include "PageThrottler.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "MainFrame.h"
#include "Page.h"
+#include "PageActivityAssertionToken.h"
+#include <wtf/StdLibExtras.h>
namespace WebCore {
+static const double kThrottleHysteresisSeconds = 2.0;
+
PageThrottler::PageThrottler(Page& page)
: m_page(page)
- , m_userInputHysteresis([this](HysteresisState state) { setActivityFlag(PageActivityState::UserInputActivity, state == HysteresisState::Started); })
- , m_audiblePluginHysteresis([this](HysteresisState state) { setActivityFlag(PageActivityState::AudiblePlugin, state == HysteresisState::Started); })
- , m_mediaActivityCounter([this](bool value) { setActivityFlag(PageActivityState::MediaActivity, value); })
- , m_pageLoadActivityCounter([this](bool value) { setActivityFlag(PageActivityState::PageLoadActivity, value); })
+ , m_throttleState(PageNotThrottledState)
+ , m_throttleHysteresisTimer(this, &PageThrottler::throttleHysteresisTimerFired)
+ , m_visuallyNonIdle("Page is not visually idle.")
+{
+ m_page.chrome().client().incrementActivePageCount();
+}
+
+PageThrottler::~PageThrottler()
{
+ setIsVisuallyIdle(false);
+
+ for (auto it = m_activityTokens.begin(), end = m_activityTokens.end(); it != end; ++it)
+ (*it)->invalidate();
+
+ if (m_throttleState != PageThrottledState)
+ m_page.chrome().client().decrementActivePageCount();
}
-PageActivityAssertionToken PageThrottler::mediaActivityToken()
+std::unique_ptr<PageActivityAssertionToken> PageThrottler::createActivityToken()
{
- return m_mediaActivityCounter.token<PageActivityAssertionTokenType>();
+ return std::make_unique<PageActivityAssertionToken>(*this);
}
-PageActivityAssertionToken PageThrottler::pageLoadActivityToken()
+void PageThrottler::throttlePage()
{
- return m_pageLoadActivityCounter.token<PageActivityAssertionTokenType>();
+ m_throttleState = PageThrottledState;
+
+ m_page.chrome().client().decrementActivePageCount();
+
+ for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ if (frame->document())
+ frame->document()->scriptedAnimationControllerSetThrottled(true);
+ }
+
+ m_page.throttleTimers();
}
-void PageThrottler::setActivityFlag(PageActivityState::Flags flag, bool value)
+void PageThrottler::unthrottlePage()
{
- PageActivityState::Flags activityState = m_activityState;
- if (value)
- activityState |= flag;
- else
- activityState &= ~flag;
+ PageThrottleState oldState = m_throttleState;
+ m_throttleState = PageNotThrottledState;
+
+ if (oldState == PageNotThrottledState)
+ return;
+
+ if (oldState == PageThrottledState)
+ m_page.chrome().client().incrementActivePageCount();
+
+ for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ if (frame->document())
+ frame->document()->scriptedAnimationControllerSetThrottled(false);
+ }
+
+ m_page.unthrottleTimers();
+}
+
+void PageThrottler::setIsVisuallyIdle(bool isVisuallyIdle)
+{
+ if (isVisuallyIdle) {
+ m_throttleState = PageWaitingToThrottleState;
+ startThrottleHysteresisTimer();
+ if (m_visuallyNonIdle.isActive())
+ m_visuallyNonIdle.endActivity();
+ } else {
+ unthrottlePage();
+ stopThrottleHysteresisTimer();
+ if (!m_visuallyNonIdle.isActive())
+ m_visuallyNonIdle.beginActivity();
+ }
+}
+
+void PageThrottler::stopThrottleHysteresisTimer()
+{
+ m_throttleHysteresisTimer.stop();
+}
+
+void PageThrottler::reportInterestingEvent()
+{
+ if (m_throttleState == PageNotThrottledState)
+ return;
+ if (m_throttleState == PageThrottledState)
+ unthrottlePage();
+ m_throttleState = PageWaitingToThrottleState;
+ startThrottleHysteresisTimer();
+}
+
+void PageThrottler::startThrottleHysteresisTimer()
+{
+ if (m_throttleHysteresisTimer.isActive())
+ m_throttleHysteresisTimer.stop();
+ if (!m_activityTokens.size())
+ m_throttleHysteresisTimer.startOneShot(kThrottleHysteresisSeconds);
+}
+
+void PageThrottler::throttleHysteresisTimerFired(Timer<PageThrottler>&)
+{
+ ASSERT(!m_activityTokens.size());
+ throttlePage();
+}
+
+void PageThrottler::addActivityToken(PageActivityAssertionToken& token)
+{
+ ASSERT(!m_activityTokens.contains(&token));
+
+ m_activityTokens.add(&token);
+
+ // If we've already got events that block throttling we can return early
+ if (m_activityTokens.size() > 1)
+ return;
+
+ if (m_throttleState == PageNotThrottledState)
+ return;
+
+ if (m_throttleState == PageThrottledState)
+ unthrottlePage();
+
+ m_throttleState = PageWaitingToThrottleState;
+ stopThrottleHysteresisTimer();
+}
+
+void PageThrottler::removeActivityToken(PageActivityAssertionToken& token)
+{
+ ASSERT(m_activityTokens.contains(&token));
+
+ m_activityTokens.remove(&token);
+
+ if (m_activityTokens.size())
+ return;
- if (m_activityState == activityState)
+ if (m_throttleState == PageNotThrottledState)
return;
- m_activityState = activityState;
- m_page.setPageActivityState(m_activityState);
+ ASSERT(m_throttleState == PageWaitingToThrottleState);
+ startThrottleHysteresisTimer();
}
}