Throttle DOM timers on hidden pages.
https://bugs.webkit.org/show_bug.cgi?id=98474

Patch by Kiran Muppala <cmuppala@apple.com> on 2012-10-08
Reviewed by Maciej Stachowiak.

Source/JavaScriptCore:

Add HIDDEN_PAGE_DOM_TIMER_THROTTLING feature define.

* Configurations/FeatureDefines.xcconfig:

Source/WebCore:

When the visibility of a page changes to "hidden", all it's DOM timers are
updated to align their fire times on one second intervals.  This limits the
number of CPU wakes due to a hidden pages to one per second.

Test: fast/dom/timer-throttling-hidden-page.html

* Configurations/FeatureDefines.xcconfig:
* WebCore.exp.in:
* dom/Document.cpp:
(WebCore):
(WebCore::Document::timerAlignmentInterval):
Read Page::timerAlignmentInterval and pass it along to DOMTimer.

* dom/Document.h:
(Document):
* dom/ScriptExecutionContext.cpp:
(WebCore):
(WebCore::ScriptExecutionContext::didChangeTimerAlignmentInterval):
Scan through self DOM Timers and tell them to recompute their fire
time based on the updated alignment interval.
(WebCore::ScriptExecutionContext::timerAlignmentInterval):

* dom/ScriptExecutionContext.h:
(ScriptExecutionContext):
* page/DOMTimer.cpp:
(WebCore):
(WebCore::DOMTimer::alignedFireTime):
If the document's alignment interval is non zero, round up the fire
time to the next multiple of alignment interval.

* page/DOMTimer.h:
(DOMTimer):
(WebCore::DOMTimer::defaultTimerAlignmentInterval):
(WebCore::DOMTimer::setDefaultTimerAlignmentInterval):
* page/Page.cpp:
(WebCore::Page::Page):
(WebCore):
(WebCore::Page::setTimerAlignmentInterval):
(WebCore::Page::timerAlignmentInterval):
(WebCore::Page::setVisibilityState):
Getter and Setter for alignment interval.  Expose setVisibilityState
if either PAGE_VISIBILITY_API is enabled or if HIDDEN_PAGE_DOM_TIMER_REDUCTION
is enabled.

* page/Page.h:
(Page):
* page/Settings.cpp:
(WebCore):
(WebCore::Settings::setDefaultDOMTimerAlignmentInterval):
(WebCore::Settings::defaultDOMTimerAlignmentInterval):
(WebCore::Settings::setDOMTimerAlignmentInterval):
(WebCore::Settings::domTimerAlignmentInterval):
* page/Settings.h:
(Settings):
* page/SuspendableTimer.cpp:
(WebCore::SuspendableTimer::suspend):
Save the time remaining to the original unaligned fire time, so that
on resuming, the fire time will be correctly aligned using the latest
alignment interval.

* platform/ThreadTimers.cpp:
(WebCore::ThreadTimers::sharedTimerFiredInternal):
Clear m_unalignedNextFireTime along with m_nextFireTime to keep
them always in sync.

* platform/Timer.cpp:
(WebCore::TimerBase::TimerBase):
(WebCore::TimerBase::setNextFireTime):
Save the requested fire time in m_unalignedNextFireTime and
set m_nextFireTime to the aligned value.  The unalinged value
is used to recompute fire time if alignment interval changes.
(WebCore):
(WebCore::TimerBase::didChangeAlignmentInterval):
Recompute next fire time from m_unalignedNextFireTime.
(WebCore::TimerBase::nextUnalignedFireInterval):
Interval from current time to the original unaligned fire time.

* platform/Timer.h:
(TimerBase):
(WebCore::TimerBase::alignedFireTime):

Source/WebKit/mac:

Add HIDDEN_PAGE_DOM_TIMER_THROTTLING feature define and provide a SPI for
DumpRenderTree to modify the visibility state of a page.  The latter
is needed to test throttling of timers on hidden pages through DumpRenderTree.

* Configurations/FeatureDefines.xcconfig:
* WebView/WebView.mm:
(-[WebView _setVisibilityState:isInitialState:]):
* WebView/WebViewPrivate.h:

Source/WebKit2:

Add HIDDEN_PAGE_DOM_TIMER_THROTTLING feature define.  Use existing code of
PAGE_VISIBILITY_API to detect changes to page visibility state.

* Configurations/FeatureDefines.xcconfig:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
Check visibility state on construction.
(WebKit::WebPageProxy::initializeWebPage):
Send initial visibility state message if HIDDEN_PAGE_DOM_TIMER_THROTTLING
is enabled or if PAGE_VISIBILITY_API is enabled.
(WebKit::WebPageProxy::viewStateDidChange):
When PAGE_VISIBILITY_API is not enabled, compare new visibility against
WebPageProxy::m_isVisible, to minimize number of messages sent.
Remove unnecessary second call to PageClient::isViewVisible for updating
visibility state.

* WebProcess/InjectedBundle/InjectedBundle.cpp:
(WebKit::InjectedBundle::setPageVisibilityState):
WebKitTestRunner uses this method to implement testRunner.setPageVisibility(),
hence enable it for testing hidden page timer throttling as well.

* WebProcess/WebPage/WebPage.cpp:
(WebKit):
(WebKit::WebPage::setVisibilityState):
Ensure Page::setVisibilityState is called either if PAGE_VISIBILITY_API is
enabled or if HIDDEN_PAGE_DOM_TIMER_THROTTLING is enabled.

* WebProcess/WebPage/WebPage.h:
(WebPage):
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Implement testRunner.setPageVisibility on mac for testing throttling
of timers on hidden pages using DumpRenderTree.

* DumpRenderTree/mac/Configurations/Base.xcconfig:
Fix build error on mac-ews bot.  Add JSC copy of ICU headers to search path.

* DumpRenderTree/mac/TestRunnerMac.mm:
(TestRunner::resetPageVisibility):
(TestRunner::setPageVisibility):

WebKitLibraries:

Add HIDDEN_PAGE_DOM_TIMER_THROTTLING feature define.

* win/tools/vsprops/FeatureDefines.vsprops:
* win/tools/vsprops/FeatureDefinesCairo.vsprops:

LayoutTests:

Add a test for DOM timer throttling on hidden pages.

* fast/dom/timer-throttling-hidden-page-expected.txt: Added.
* fast/dom/timer-throttling-hidden-page.html: Added.
* platform/chromium/TestExpectations:
* platform/efl/TestExpectations:
* platform/gtk/TestExpectations:
* platform/qt/TestExpectations:
* platform/win/TestExpectations:
Skip the test since HIDDEN_PAGE_DOM_TIMER_THROTTLING is not enabled by default.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@130720 268f45cc-cd09-0410-ab3c-d52691b4dbfc