1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 tvcm.require('tvcm.utils');
9 tvcm.exportTo('tvcm', function() {
10 // Setting this to true will cause stack traces to get dumped into the
11 // tasks. When an exception happens the original stack will be printed.
13 // NOTE: This should never be set committed as true.
14 var recordRAFStacks = false;
16 var pendingPreAFs = [];
18 var pendingIdleCallbacks = [];
19 var currentRAFDispatchList = undefined;
21 var rafScheduled = false;
23 function scheduleRAF() {
27 if (window.requestAnimationFrame) {
28 window.requestAnimationFrame(processRequests);
30 var delta = Date.now() - window.performance.now();
31 window.webkitRequestAnimationFrame(function(domTimeStamp) {
32 processRequests(domTimeStamp - delta);
37 function onAnimationFrameError(e, opt_stack) {
39 console.log(opt_stack);
42 console.error(e.message, e.stack);
47 function runTask(task, frameBeginTime) {
49 task.callback.call(task.context, frameBeginTime);
51 tvcm.onAnimationFrameError(e, task.stack);
55 function processRequests(frameBeginTime) {
56 // We assume that we want to do a maximum of 10ms optional work per frame.
57 // Hopefully rAF will eventually pass this in for us.
58 var rafCompletionDeadline = frameBeginTime + 10;
62 var currentPreAFs = pendingPreAFs;
63 currentRAFDispatchList = pendingRAFs;
66 var hasRAFTasks = currentPreAFs.length || currentRAFDispatchList.length;
68 for (var i = 0; i < currentPreAFs.length; i++)
69 runTask(currentPreAFs[i], frameBeginTime);
71 while (currentRAFDispatchList.length > 0)
72 runTask(currentRAFDispatchList.shift(), frameBeginTime);
73 currentRAFDispatchList = undefined;
76 while (pendingIdleCallbacks.length > 0) {
77 runTask(pendingIdleCallbacks.shift());
78 // Check timer after running at least one idle task to avoid buggy
79 // window.performance.now() on some platforms from blocking the idle
81 if (window.performance.now() >= rafCompletionDeadline)
86 if (pendingIdleCallbacks.length > 0)
90 function getStack_() {
94 var stackLines = tvcm.stackTrace();
95 // Strip off getStack_.
97 return stackLines.join('\n');
100 function requestPreAnimationFrame(callback, opt_this) {
103 context: opt_this || window,
104 stack: getStack_()});
108 function requestAnimationFrameInThisFrameIfPossible(callback, opt_this) {
109 if (!currentRAFDispatchList) {
110 requestAnimationFrame(callback, opt_this);
113 currentRAFDispatchList.push({
115 context: opt_this || window,
116 stack: getStack_()});
120 function requestAnimationFrame(callback, opt_this) {
123 context: opt_this || window,
124 stack: getStack_()});
128 function requestIdleCallback(callback, opt_this) {
129 pendingIdleCallbacks.push({
131 context: opt_this || window,
132 stack: getStack_()});
136 function forcePendingRAFTasksToRun(frameBeginTime) {
139 processRequests(frameBeginTime);
143 onAnimationFrameError: onAnimationFrameError,
144 requestPreAnimationFrame: requestPreAnimationFrame,
145 requestAnimationFrame: requestAnimationFrame,
146 requestAnimationFrameInThisFrameIfPossible:
147 requestAnimationFrameInThisFrameIfPossible,
148 requestIdleCallback: requestIdleCallback,
149 forcePendingRAFTasksToRun: forcePendingRAFTasksToRun