Home | History | Annotate | Download | only in base
      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.
      4 
      5 'use strict';
      6 
      7 base.require('base.utils');
      8 
      9 base.exportTo('base', 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.
     12   //
     13   // NOTE: This should never be set committed as true.
     14   var recordRAFStacks = false;
     15 
     16   var pendingPreAFs = [];
     17   var pendingRAFs = [];
     18   var currentRAFDispatchList = undefined;
     19 
     20   var rafScheduled = false;
     21 
     22   function scheduleRAF() {
     23     if (rafScheduled)
     24       return;
     25     rafScheduled = true;
     26     window.webkitRequestAnimationFrame(processRequests);
     27   }
     28 
     29   function onAnimationFrameError(e, opt_stack) {
     30     if (opt_stack)
     31       console.log(opt_stack);
     32 
     33     if (e.message)
     34       console.error(e.message, e.stack);
     35     else
     36       console.error(e);
     37   }
     38 
     39   function runTask(task) {
     40     try {
     41       task.callback.call(task.context);
     42     } catch (e) {
     43       base.onAnimationFrameError(e, task.stack);
     44     }
     45   }
     46 
     47   function processRequests() {
     48     rafScheduled = false;
     49 
     50     var currentPreAFs = pendingPreAFs;
     51     currentRAFDispatchList = pendingRAFs;
     52     pendingPreAFs = [];
     53     pendingRAFs = [];
     54 
     55     for (var i = 0; i < currentPreAFs.length; i++)
     56       runTask(currentPreAFs[i]);
     57 
     58     while (currentRAFDispatchList.length > 0)
     59       runTask(currentRAFDispatchList.shift());
     60     currentRAFDispatchList = undefined;
     61   }
     62 
     63   function getStack_() {
     64     if (!recordRAFStacks)
     65       return '';
     66 
     67     var stackLines = base.stackTrace();
     68     // Strip off getStack_.
     69     stackLines.shift();
     70     return stackLines.join('\n');
     71   }
     72 
     73   function requestPreAnimationFrame(callback, opt_this) {
     74     pendingPreAFs.push({
     75       callback: callback,
     76       context: opt_this || window,
     77       stack: getStack_()});
     78     scheduleRAF();
     79   }
     80 
     81   function requestAnimationFrameInThisFrameIfPossible(callback, opt_this) {
     82     if (!currentRAFDispatchList) {
     83       requestAnimationFrame(callback, opt_this);
     84       return;
     85     }
     86     currentRAFDispatchList.push({
     87       callback: callback,
     88       context: opt_this || window,
     89       stack: getStack_()});
     90     return;
     91   }
     92 
     93   function requestAnimationFrame(callback, opt_this) {
     94     pendingRAFs.push({
     95       callback: callback,
     96       context: opt_this || window,
     97       stack: getStack_()});
     98     scheduleRAF();
     99   }
    100   return {
    101     onAnimationFrameError: onAnimationFrameError,
    102     requestPreAnimationFrame: requestPreAnimationFrame,
    103     requestAnimationFrame: requestAnimationFrame,
    104     requestAnimationFrameInThisFrameIfPossible:
    105         requestAnimationFrameInThisFrameIfPossible
    106   };
    107 });
    108