| <!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'; |
| |
| tv.exportTo('tv.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) { |
| tv.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 = tv.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> |