#include "config.h"
#include "PageThrottler.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "Frame.h"
#include "Page.h"
#include "PageActivityAssertionToken.h"
namespace WebCore {
static const double kThrottleHysteresisSeconds = 2.0;
PageThrottler::PageThrottler(Page* page)
: m_page(page)
, m_activeThrottleBlockers(0)
, m_throttleState(PageNotThrottledState)
, m_throttleHysteresisTimer(this, &PageThrottler::throttleHysteresisTimerFired)
{
if (ChromeClient* chromeClient = m_page->chrome().client())
chromeClient->incrementActivePageCount();
}
PageThrottler::~PageThrottler()
{
for (HashSet<PageActivityAssertionToken*>::iterator i = m_activityTokens.begin(); i != m_activityTokens.end(); ++i)
(*i)->invalidate();
if (m_throttleState != PageThrottledState && m_page) {
if (ChromeClient* chromeClient = m_page->chrome().client())
chromeClient->decrementActivePageCount();
}
}
void PageThrottler::clearPage()
{
setThrottled(false);
m_page = 0;
}
void PageThrottler::throttlePage()
{
m_throttleState = PageThrottledState;
if (!m_page)
return;
if (ChromeClient* chromeClient = m_page->chrome().client())
chromeClient->decrementActivePageCount();
for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->document())
frame->document()->scriptedAnimationControllerSetThrottled(true);
}
m_page->throttleTimers();
}
void PageThrottler::unthrottlePage()
{
PageThrottleState oldState = m_throttleState;
m_throttleState = PageNotThrottledState;
if (!m_page || oldState == PageNotThrottledState)
return;
if (oldState == PageThrottledState) {
if (ChromeClient* chromeClient = m_page->chrome().client())
chromeClient->incrementActivePageCount();
}
for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->document())
frame->document()->scriptedAnimationControllerSetThrottled(false);
}
m_page->unthrottleTimers();
}
void PageThrottler::setThrottled(bool isThrottled)
{
if (isThrottled) {
m_throttleState = PageWaitingToThrottleState;
startThrottleHysteresisTimer();
} else {
unthrottlePage();
stopThrottleHysteresisTimer();
}
}
void PageThrottler::preventThrottling()
{
if (m_activeThrottleBlockers++)
return;
if (m_throttleState == PageNotThrottledState)
return;
if (m_throttleState == PageThrottledState)
unthrottlePage();
m_throttleState = PageWaitingToThrottleState;
stopThrottleHysteresisTimer();
}
void PageThrottler::allowThrottling()
{
ASSERT(m_activeThrottleBlockers > 0);
m_activeThrottleBlockers--;
if (m_activeThrottleBlockers)
return;
if (m_throttleState == PageNotThrottledState)
return;
ASSERT(m_throttleState == PageWaitingToThrottleState);
startThrottleHysteresisTimer();
}
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_activeThrottleBlockers)
m_throttleHysteresisTimer.startOneShot(kThrottleHysteresisSeconds);
}
void PageThrottler::throttleHysteresisTimerFired(Timer<PageThrottler>*)
{
ASSERT(!m_activeThrottleBlockers);
throttlePage();
}
void PageThrottler::addActivityToken(PageActivityAssertionToken* token)
{
if (!token || m_activityTokens.contains(token))
return;
m_activityTokens.add(token);
preventThrottling();
}
void PageThrottler::removeActivityToken(PageActivityAssertionToken* token)
{
if (!token || !m_activityTokens.contains(token))
return;
m_activityTokens.remove(token);
allowThrottling();
}
}