blob: c224743c7d06f0c55269b9183011f05e5167ea2a [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/base/utils.html">
<script>
'use strict';
tr.exportTo('tr.b', function() {
// Setting this to true will cause stack traces to get dumped into the
// tasks. When an exception happens the original stack will be printed.
//
// NOTE: This should never be set committed as true.
var recordRAFStacks = false;
var pendingPreAFs = [];
var pendingRAFs = [];
var pendingIdleCallbacks = [];
var currentRAFDispatchList = undefined;
var rafScheduled = false;
function scheduleRAF() {
if (rafScheduled)
return;
rafScheduled = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(processRequests);
} else {
var delta = Date.now() - window.performance.now();
window.webkitRequestAnimationFrame(function(domTimeStamp) {
processRequests(domTimeStamp - delta);
});
}
}
function onAnimationFrameError(e, opt_stack) {
if (opt_stack)
console.log(opt_stack);
if (e.message)
console.error(e.message, e.stack);
else
console.error(e);
}
function runTask(task, frameBeginTime) {
try {
task.callback.call(task.context, frameBeginTime);
} catch (e) {
tr.b.onAnimationFrameError(e, task.stack);
}
}
function processRequests(frameBeginTime) {
// We assume that we want to do a maximum of 10ms optional work per frame.
// Hopefully rAF will eventually pass this in for us.
var rafCompletionDeadline = frameBeginTime + 10;
rafScheduled = false;
var currentPreAFs = pendingPreAFs;
currentRAFDispatchList = pendingRAFs;
pendingPreAFs = [];
pendingRAFs = [];
var hasRAFTasks = currentPreAFs.length || currentRAFDispatchList.length;
for (var i = 0; i < currentPreAFs.length; i++)
runTask(currentPreAFs[i], frameBeginTime);
while (currentRAFDispatchList.length > 0)
runTask(currentRAFDispatchList.shift(), frameBeginTime);
currentRAFDispatchList = undefined;
if (!hasRAFTasks) {
while (pendingIdleCallbacks.length > 0) {
runTask(pendingIdleCallbacks.shift());
// Check timer after running at least one idle task to avoid buggy
// window.performance.now() on some platforms from blocking the idle
// task queue.
if (window.performance.now() >= rafCompletionDeadline)
break;
}
}
if (pendingIdleCallbacks.length > 0)
scheduleRAF();
}
function getStack_() {
if (!recordRAFStacks)
return '';
var stackLines = tr.b.stackTrace();
// Strip off getStack_.
stackLines.shift();
return stackLines.join('\n');
}
function requestPreAnimationFrame(callback, opt_this) {
pendingPreAFs.push({
callback: callback,
context: opt_this || window,
stack: getStack_()});
scheduleRAF();
}
function requestAnimationFrameInThisFrameIfPossible(callback, opt_this) {
if (!currentRAFDispatchList) {
requestAnimationFrame(callback, opt_this);
return;
}
currentRAFDispatchList.push({
callback: callback,
context: opt_this || window,
stack: getStack_()});
return;
}
function requestAnimationFrame(callback, opt_this) {
pendingRAFs.push({
callback: callback,
context: opt_this || window,
stack: getStack_()});
scheduleRAF();
}
function requestIdleCallback(callback, opt_this) {
pendingIdleCallbacks.push({
callback: callback,
context: opt_this || window,
stack: getStack_()});
scheduleRAF();
}
function forcePendingRAFTasksToRun(frameBeginTime) {
if (!rafScheduled)
return;
processRequests(frameBeginTime);
}
return {
onAnimationFrameError: onAnimationFrameError,
requestPreAnimationFrame: requestPreAnimationFrame,
requestAnimationFrame: requestAnimationFrame,
requestAnimationFrameInThisFrameIfPossible:
requestAnimationFrameInThisFrameIfPossible,
requestIdleCallback: requestIdleCallback,
forcePendingRAFTasksToRun: forcePendingRAFTasksToRun
};
});
</script>