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
parent 2e1dd3f8
2012-10-08 Kiran Muppala <cmuppala@apple.com>
Throttle DOM timers on hidden pages.
https://bugs.webkit.org/show_bug.cgi?id=98474
Reviewed by Maciej Stachowiak.
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.
2012-10-08 Yoshifumi Inoue <yosin@chromium.org>
HTMLSelectElement::typeAheadFind depends on implementation dependent behavior
......
Bug 98474: Throttle DOM timers on hidden pages.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS timerIntervalWhilePageVisible is within 20 of 100
PASS firstTimerIntervalWhilePageHidden is >= 80
PASS firstTimerIntervalWhilePageHidden <= 1120 is true
PASS timerIntervalWhilePageHidden is within 20 of 1000
PASS timerIntervalWhilePageVisible is within 20 of 100
PASS successfullyParsed is true
TEST COMPLETE
This test measures the time taken to fire a 100ms DOM Timer when the page visibility is set to "visible", "hidden" and then back to "visible". Due to hidden page timer throttling, the timer should fire close to 1s when page is hidden. And it should fire close to 100ms, when the page is visible.
<html>
<head>
<script src="../js/resources/js-test-pre.js"></script>
<script>
description('<a href="https://bugs.webkit.org/show_bug.cgi?id=98474">Bug 98474</a>: Throttle DOM timers on hidden pages.');
var jsTestIsAsync = true;
var previousT = new Date().getTime();
var timerCount = 0;
var firstTimerWhileHidden = true;
var isPageVisible = true;
var timeoutInterval = 100;
var tolerance = 20;
var timerAlignmentInterval = 1000;
function testTimer() {
var d = new Date();
var t = d.getTime();
if (!isPageVisible) {
if (firstTimerWhileHidden) {
firstTimerIntervalWhilePageHidden = t - previousT;
var minValue = timeoutInterval - tolerance;
shouldBeGreaterThanOrEqual("firstTimerIntervalWhilePageHidden", minValue.toString());
var maxValue = timeoutInterval + timerAlignmentInterval + tolerance;
shouldBeTrue("firstTimerIntervalWhilePageHidden <= " + maxValue);
firstTimerWhileHidden = false;
} else {
timerIntervalWhilePageHidden = t - previousT;
shouldBeCloseTo("timerIntervalWhilePageHidden", timerAlignmentInterval, tolerance);
}
}
else {
timerIntervalWhilePageVisible = t - previousT;
shouldBeCloseTo("timerIntervalWhilePageVisible", timeoutInterval, tolerance);
}
timerCount++;
previousT = t;
if (timerCount == 1) {
testRunner.setPageVisibility("hidden");
isPageVisible = false;
} else if (timerCount == 3) {
testRunner.resetPageVisibility();
isPageVisible = true;
} else if (timerCount >= 4){
finishJSTest();
return;
}
setTimeout(testTimer, timeoutInterval);
}
function runTest() {
if (!window.testRunner) {
debug('This test requires testRunner');
return;
}
var timeoutIntervalSpans = document.getElementsByClassName('timeoutInterval');
for (var i = 0; i < timeoutIntervalSpans.length; i++) {
timeoutIntervalSpans[i].innerText = timeoutInterval;
}
document.getElementById('alignmentInterval').innerText = timerAlignmentInterval / 1000;
testRunner.dumpAsText();
setTimeout(testTimer, timeoutInterval);
}
</script>
</head>
<body onload="runTest()">
<p>
This test measures the time taken to fire a <span class="timeoutInterval"></span>ms DOM Timer when the page visibility is set to "visible", "hidden" and then back to "visible". Due to hidden page timer throttling, the timer should fire close to <span id="alignmentInterval"></span>s when page is hidden. And it should fire close to <span class="timeoutInterval"></span>ms, when the page is visible.
</p>
<script src="../js/resources/js-test-post.js"></script>
</body>
</html>
......@@ -910,6 +910,9 @@ platform/gtk/plugins/invalidate-rect-with-null-npp-argument.html [ WontFix ]
webkit.org/b/96109 [ Linux ] editing/pasteboard/paste-global-selection.html [ Skip ]
# Chromium does not enable HIDDEN_PAGE_DOM_TIMER_THROTTLING
fast/dom/timer-throttling-hidden-page.html [ WontFix ]
# Skipping rules for ANDROID are in platform/chromium-android/TestExpectations.
# -----------------------------------------------------------------
......
......@@ -661,6 +661,9 @@ webkit.org/b/82340 fast/regions/style-scoped-in-flow-override-region-styling-mul
webkit.org/b/82340 fast/regions/style-scoped-in-flow-override-region-styling.html [ ImageOnlyFailure ]
webkit.org/b/82340 fast/regions/style-scoped-in-flow.html [ ImageOnlyFailure ]
# This port does not enable HIDDEN_PAGE_DOM_TIMER_THROTTLING
fast/dom/timer-throttling-hidden-page.html [ WontFix ]
#////////////////////////////////////////////////////////////////////////////////////////
# CRASHES
#////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -435,6 +435,9 @@ webkit.org/b/92942 fast/events/constructors/device-proximity-event-constructor.h
# CSS compositing is not yet enabled.
Bug(GTK) css3/compositing [ Skip ]
# HIDDEN_PAGE_DOM_TIMER_THROTTLING is not enabled
fast/dom/timer-throttling-hidden-page.html [ WontFix ]
#////////////////////////////////////////////////////////////////////////////////////////
# End of Expected failures
#////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -439,6 +439,9 @@ fast/js/names.html
touchadjustment/touch-links-longpress.html
touchadjustment/touch-links-active.html
# ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) is disabled
fast/dom/timer-throttling-hidden-page.html
# =========================================================================== #
# Feature not yet supported. #
# =========================================================================== #
......
......@@ -2332,3 +2332,6 @@ http/tests/inspector/csp-inline-warning-contains-stacktrace.html
# https://bugs.webkit.org/show_bug.cgi?id=98209
fast/text/international/float-as-only-child-of-isolate-crash.html
# HIDDEN_PAGE_DOM_TIMER_THROTTLING is disabled
fast/dom/timer-throttling-hidden-page.html
2012-10-08 Kiran Muppala <cmuppala@apple.com>
Throttle DOM timers on hidden pages.
https://bugs.webkit.org/show_bug.cgi?id=98474
Reviewed by Maciej Stachowiak.
Add HIDDEN_PAGE_DOM_TIMER_THROTTLING feature define.
* Configurations/FeatureDefines.xcconfig:
2012-10-08 Michael Saboff <msaboff@apple.com>
After r130344, OpaqueJSString() creates an empty string which should be a null string
......
......@@ -63,6 +63,8 @@ ENABLE_FILTERS_macosx = ENABLE_FILTERS;
ENABLE_FULLSCREEN_API = ENABLE_FULLSCREEN_API;
ENABLE_GAMEPAD = ;
ENABLE_GEOLOCATION = ENABLE_GEOLOCATION;
ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING = $(HIDDEN_PAGE_DOM_TIMER_THROTTLING_$(REAL_PLATFORM_NAME));
ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING_macosx = HIDDEN_PAGE_DOM_TIMER_THROTTLING;
ENABLE_HIGH_DPI_CANVAS = ENABLE_HIGH_DPI_CANVAS;
ENABLE_ICONDATABASE = $(ENABLE_ICONDATABASE_$(REAL_PLATFORM_NAME));
ENABLE_ICONDATABASE_macosx = ENABLE_ICONDATABASE;
......@@ -141,4 +143,4 @@ ENABLE_WIDGET_REGION_macosx = ENABLE_WIDGET_REGION;
ENABLE_WORKERS = ENABLE_WORKERS;
ENABLE_XSLT = ENABLE_XSLT;
FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT);
FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT);
2012-10-08 Kiran Muppala <cmuppala@apple.com>
Throttle DOM timers on hidden pages.
https://bugs.webkit.org/show_bug.cgi?id=98474
Reviewed by Maciej Stachowiak.
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):
2012-10-08 Andreas Kling <kling@webkit.org>
1.18MB below RenderTableSection::setCachedCollapsedBorderValue() on Membuster3.
......
......@@ -64,6 +64,8 @@ ENABLE_FILTERS_macosx = ENABLE_FILTERS;
ENABLE_FULLSCREEN_API = ENABLE_FULLSCREEN_API;
ENABLE_GAMEPAD = ;
ENABLE_GEOLOCATION = ENABLE_GEOLOCATION;
ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING = $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING_$(REAL_PLATFORM_NAME));
ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING_macosx = ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING;
ENABLE_HIGH_DPI_CANVAS = ENABLE_HIGH_DPI_CANVAS;
ENABLE_ICONDATABASE = $(ENABLE_ICONDATABASE_$(REAL_PLATFORM_NAME));
ENABLE_ICONDATABASE_macosx = ENABLE_ICONDATABASE;
......@@ -142,4 +144,4 @@ ENABLE_WIDGET_REGION_macosx = ENABLE_WIDGET_REGION;
ENABLE_WORKERS = ENABLE_WORKERS;
ENABLE_XSLT = ENABLE_XSLT;
FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT);
FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT);
......@@ -677,6 +677,7 @@ __ZN7WebCore4Page16setDefersLoadingEb
__ZN7WebCore4Page17willMoveOffscreenEv
__ZN7WebCore4Page18removeSchedulePairEN3WTF10PassRefPtrINS_12SchedulePairEEE
__ZN7WebCore4Page18setPageScaleFactorEfRKNS_8IntPointE
__ZN7WebCore4Page18setVisibilityStateENS_19PageVisibilityStateEb
__ZN7WebCore4Page19addLayoutMilestonesEj
__ZN7WebCore4Page19visitedStateChangedEPNS_9PageGroupEy
__ZN7WebCore4Page20setDeviceScaleFactorEf
......@@ -907,6 +908,7 @@ __ZN7WebCore8Settings27setJavaEnabledForLocalFilesEb
__ZN7WebCore8Settings27setLoadsImagesAutomaticallyEb
__ZN7WebCore8Settings27setLocalStorageDatabasePathERKN3WTF6StringE
__ZN7WebCore8Settings27setSpatialNavigationEnabledEb
__ZN7WebCore8Settings28setDOMTimerAlignmentIntervalEd
__ZN7WebCore8Settings28setForceFTPDirectoryListingsEb
__ZN7WebCore8Settings29setAccelerated2dCanvasEnabledEb
__ZN7WebCore8Settings29setAuthorAndUserStylesEnabledEb
......@@ -917,6 +919,7 @@ __ZN7WebCore8Settings31setCanvasUsesAcceleratedDrawingEb
__ZN7WebCore8Settings31setJavaScriptCanAccessClipboardEb
__ZN7WebCore8Settings31setJavaScriptExperimentsEnabledEb
__ZN7WebCore8Settings31setShrinksStandaloneImagesToFitEb
__ZN7WebCore8Settings32defaultDOMTimerAlignmentIntervalEv
__ZN7WebCore8Settings32setAcceleratedCompositingEnabledEb
__ZN7WebCore8Settings32setNeedsAdobeFrameReloadingQuirkEb
__ZN7WebCore8Settings32setScreenFontSubstitutionEnabledEb
......
......@@ -2665,6 +2665,14 @@ double Document::minimumTimerInterval() const
return p->settings()->minDOMTimerInterval();
}
double Document::timerAlignmentInterval() const
{
Page* p = page();
if (!p)
return ScriptExecutionContext::timerAlignmentInterval();
return p->settings()->domTimerAlignmentInterval();
}
EventTarget* Document::errorEventTarget()
{
return domWindow();
......
......@@ -1197,6 +1197,8 @@ private:
virtual double minimumTimerInterval() const;
virtual double timerAlignmentInterval() const;
void updateTitle(const StringWithDirection&);
void updateFocusAppearanceTimerFired(Timer<Document>*);
void updateBaseURL();
......
......@@ -396,6 +396,19 @@ double ScriptExecutionContext::minimumTimerInterval() const
return Settings::defaultMinDOMTimerInterval();
}
void ScriptExecutionContext::didChangeTimerAlignmentInterval()
{
for (TimeoutMap::iterator iter = m_timeouts.begin(); iter != m_timeouts.end(); ++iter) {
DOMTimer* timer = iter->value;
timer->didChangeAlignmentInterval();
}
}
double ScriptExecutionContext::timerAlignmentInterval() const
{
return Settings::defaultDOMTimerAlignmentInterval();
}
ScriptExecutionContext::Task::~Task()
{
}
......
......@@ -156,6 +156,9 @@ public:
void adjustMinimumTimerInterval(double oldMinimumTimerInterval);
virtual double minimumTimerInterval() const;
void didChangeTimerAlignmentInterval();
virtual double timerAlignmentInterval() const;
virtual EventQueue* eventQueue() const = 0;
protected:
......
......@@ -30,6 +30,7 @@
#include "InspectorInstrumentation.h"
#include "ScheduledAction.h"
#include "ScriptExecutionContext.h"
#include <wtf/CurrentTime.h>
#include <wtf/HashSet.h>
#include <wtf/StdLibExtras.h>
......@@ -41,6 +42,7 @@ static const int maxIntervalForUserGestureForwarding = 1000; // One second match
static const int maxTimerNestingLevel = 5;
static const double oneMillisecond = 0.001;
double DOMTimer::s_minDefaultTimerInterval = 0.010; // 10 milliseconds
double DOMTimer::s_defaultTimerAlignmentInterval = 0;
static int timerNestingLevel = 0;
......@@ -192,4 +194,19 @@ double DOMTimer::intervalClampedToMinimum(int timeout, double minimumTimerInterv
return intervalMilliseconds;
}
double DOMTimer::alignedFireTime(double fireTime) const
{
double alignmentInterval = scriptExecutionContext()->timerAlignmentInterval();
if (alignmentInterval) {
double currentTime = monotonicallyIncreasingTime();
if (fireTime <= currentTime)
return fireTime;
double alignedTime = ceil(fireTime / alignmentInterval) * alignmentInterval;
return alignedTime;
}
return fireTime;
}
} // namespace WebCore
......@@ -66,12 +66,22 @@ namespace WebCore {
static double defaultMinTimerInterval() { return s_minDefaultTimerInterval; }
static void setDefaultMinTimerInterval(double value) { s_minDefaultTimerInterval = value; }
// Retuns timer fire time rounded to the next multiple of timer alignment interval.
virtual double alignedFireTime(double) const;
// The default timer alignment interval (in seconds). If non zero, timer fire times
// will be rounded to a multiple of the alignment interval.
// These are only modified via static methods in Settings.
static double defaultTimerAlignmentInterval() { return s_defaultTimerAlignmentInterval; }
static void setDefaultTimerAlignmentInterval(double value) { s_defaultTimerAlignmentInterval = value; }
int m_timeoutId;
int m_nestingLevel;
OwnPtr<ScheduledAction> m_action;
int m_originalInterval;
RefPtr<UserGestureIndicator::Token> m_userGestureToken;
static double s_minDefaultTimerInterval;
static double s_defaultTimerAlignmentInterval;
};
} // namespace WebCore
......
......@@ -82,6 +82,7 @@
namespace WebCore {
static HashSet<Page*>* allPages;
static const double hiddenPageTimerAlignmentInterval = 1.0; // once a second
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
......@@ -156,6 +157,7 @@ Page::Page(PageClients& pageClients)
, m_canStartMedia(true)
, m_viewMode(ViewModeWindowed)
, m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
, m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval())
, m_isEditable(false)
, m_isOnscreen(true)
#if ENABLE(PAGE_VISIBILITY_API)
......@@ -1025,6 +1027,23 @@ double Page::minimumTimerInterval() const
return m_minimumTimerInterval;
}
void Page::setTimerAlignmentInterval(double interval)
{
if (interval == m_timerAlignmentInterval)
return;
m_timerAlignmentInterval = interval;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
if (frame->document())
frame->document()->didChangeTimerAlignmentInterval();
}
}
double Page::timerAlignmentInterval() const
{
return m_timerAlignmentInterval;
}
void Page::dnsPrefetchingStateChanged()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
......@@ -1093,9 +1112,10 @@ void Page::checkSubframeCountConsistency() const
}
#endif
#if ENABLE(PAGE_VISIBILITY_API)
#if ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
{
#if ENABLE(PAGE_VISIBILITY_API)
if (m_visibilityState == visibilityState)
return;
m_visibilityState = visibilityState;
......@@ -1108,8 +1128,21 @@ void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitia
}
m_mainFrame->dispatchVisibilityStateChangeEvent();
}
#endif
#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
if (visibilityState == WebCore::PageVisibilityStateHidden)
setTimerAlignmentInterval(hiddenPageTimerAlignmentInterval);
else
setTimerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval());
#if !ENABLE(PAGE_VISIBILITY_API)
UNUSED_PARAM(isInitialState);
#endif
#endif
}
#endif // ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
#if ENABLE(PAGE_VISIBILITY_API)
PageVisibilityState Page::visibilityState() const
{
return m_visibilityState;
......
......@@ -322,6 +322,8 @@ namespace WebCore {
#if ENABLE(PAGE_VISIBILITY_API)
PageVisibilityState visibilityState() const;
#endif
#if ENABLE(PAGE_VISIBILITY_API) || ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
void setVisibilityState(PageVisibilityState, bool);
#endif
......@@ -364,6 +366,9 @@ namespace WebCore {
void setMinimumTimerInterval(double);
double minimumTimerInterval() const;
void setTimerAlignmentInterval(double);
double timerAlignmentInterval() const;
void collectPluginViews(Vector<RefPtr<PluginViewBase>, 32>& pluginViewBases);
OwnPtr<Chrome> m_chrome;
......@@ -442,6 +447,8 @@ namespace WebCore {
double m_minimumTimerInterval;
double m_timerAlignmentInterval;
bool m_isEditable;
bool m_isOnscreen;
......
......@@ -683,6 +683,26 @@ double Settings::minDOMTimerInterval()
return m_page->minimumTimerInterval();
}
void Settings::setDefaultDOMTimerAlignmentInterval(double interval)
{
DOMTimer::setDefaultTimerAlignmentInterval(interval);
}
double Settings::defaultDOMTimerAlignmentInterval()
{
return DOMTimer::defaultTimerAlignmentInterval();
}
void Settings::setDOMTimerAlignmentInterval(double interval)
{
m_page->setTimerAlignmentInterval(interval);
}
double Settings::domTimerAlignmentInterval() const
{
return m_page->timerAlignmentInterval();
}
void Settings::setUsesPageCache(bool usesPageCache)
{
if (m_usesPageCache == usesPageCache)
......
......@@ -254,6 +254,12 @@ namespace WebCore {
void setMinDOMTimerInterval(double); // Per-page; initialized to default value.
double minDOMTimerInterval();
static void setDefaultDOMTimerAlignmentInterval(double);
static double defaultDOMTimerAlignmentInterval();
void setDOMTimerAlignmentInterval(double);
double domTimerAlignmentInterval() const;
void setUsesPageCache(bool);
bool usesPageCache() const { return m_usesPageCache; }
......
......@@ -64,7 +64,7 @@ void SuspendableTimer::suspend(ReasonForSuspension)
#endif
m_active = isActive();
if (m_active) {
m_nextFireInterval = nextFireInterval();
m_nextFireInterval = nextUnalignedFireInterval();
m_repeatInterval = repeatInterval();
TimerBase::stop();
}
......
......@@ -106,6 +106,7 @@ void ThreadTimers::sharedTimerFiredInternal()
while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) {
TimerBase* timer = m_timerHeap.first();
timer->m_nextFireTime = 0;
timer->m_unalignedNextFireTime = 0;
timer->heapDeleteMin();
double interval = timer->repeatInterval();
......
......@@ -192,6 +192,7 @@ inline bool TimerHeapLessThanFunction::operator()(TimerBase* a, TimerBase* b) co
TimerBase::TimerBase()
: m_nextFireTime(0)
, m_unalignedNextFireTime(0)
, m_repeatInterval(0)
, m_heapIndex(-1)
#ifndef NDEBUG
......@@ -312,12 +313,16 @@ void TimerBase::heapPopMin()
ASSERT(this == timerHeap().last());
}
void TimerBase::setNextFireTime(double newTime)
void TimerBase::setNextFireTime(double newUnalignedTime)
{
ASSERT(m_thread == currentThread());
if (m_unalignedNextFireTime != newUnalignedTime)
m_unalignedNextFireTime = newUnalignedTime;
// Keep heap valid while changing the next-fire time.
double oldTime = m_nextFireTime;
double newTime