text: /**
   * Copyright 2013-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   * @providesModule ReactDOMFrameScheduling
   * @flow
   */
  
  'use strict';
  
  // This is a built-in polyfill for requestIdleCallback. It works by scheduling
  // a requestAnimationFrame, storing the time for the start of the frame, then
  // scheduling a postMessage which gets scheduled after paint. Within the
  // postMessage handler do as much work as possible until time + frame rate.
  // By separating the idle call into a separate event tick we ensure that
  // layout, paint and other browser work is counted against the available time.
  // The frame rate is dynamically adjusted.
  
  import type { Deadline } from 'ReactFiberReconciler';
  
  var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
  
  var warning;
  
  // TODO: There's no way to cancel, because Fiber doesn't atm.
  
  let rIC: (callback: (deadline: Deadline) => void) => number;
  
  if (!ExecutionEnvironment.canUseDOM) {
    rIC = function (frameCallback: (deadline: Deadline) => void): number {
      setTimeout(() => {
        frameCallback({
          timeRemaining() {
            return Infinity;
          }
        });
      });
      return 0;
    };
  } else if (typeof requestIdleCallback !== 'function') {
    // Polyfill requestIdleCallback.
  
    var scheduledRAFCallback = null;
    var scheduledRICCallback = null;
  
    var isIdleScheduled = false;
    var isAnimationFrameScheduled = false;
  
    var frameDeadline = 0;
    // We start out assuming that we run at 30fps but then the heuristic tracking
    // will adjust this value to a faster fps if we get more frequent animation
    // frames.
    var previousFrameTime = 33;
    var activeFrameTime = 33;
  
    var frameDeadlineObject = {
      timeRemaining: typeof performance === 'object' && typeof performance.now === 'function' ? function () {
        // We assume that if we have a performance timer that the rAF callback
        // gets a performance timer value. Not sure if this is always true.
        return frameDeadline - performance.now();
      } : function () {
        // As a fallback we use Date.now.
        return frameDeadline - Date.now();
      }
    };
  
    // We use the postMessage trick to defer idle work until after the repaint.
    var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2);
    var idleTick = function (event) {
      if (event.source !== window || event.data !== messageKey) {
        return;
      }
      isIdleScheduled = false;
      var callback = scheduledRICCallback;
      scheduledRICCallback = null;
      if (callback !== null) {
        callback(frameDeadlineObject);
      }
    };
    // Assumes that we have addEventListener in this environment. Might need
    // something better for old IE.
    window.addEventListener('message', idleTick, false);
  
    var animationTick = function (rafTime) {
      isAnimationFrameScheduled = false;
      var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
      if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) {
        if (nextFrameTime < 8) {
          // Defensive coding. We don't support higher frame rates than 120hz.
          // If we get lower than that, it is probably a bug.
          nextFrameTime = 8;
        }
        // If one frame goes long, then the next one can be short to catch up.
        // If two frames are short in a row, then that's an indication that we
        // actually have a higher frame rate than what we're currently optimizing.
        // We adjust our heuristic dynamically accordingly. For example, if we're
        // running on 120hz display or 90hz VR display.
        // Take the max of the two in case one of them was an anomaly due to
        // missed frame deadlines.
        activeFrameTime = nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime;
      } else {
        previousFrameTime = nextFrameTime;
      }
      frameDeadline = rafTime + activeFrameTime;
      if (!isIdleScheduled) {
        isIdleScheduled = true;
        window.postMessage(messageKey, '*');
      }
      var callback = scheduledRAFCallback;
      scheduledRAFCallback = null;
      if (callback !== null) {
        callback(rafTime);
      }
    };
  
    rIC = function (callback: (deadline: Deadline) => void): number {
      // This assumes that we only schedule one callback at a time because that's
      // how Fiber uses it.
      scheduledRICCallback = callback;
      if (!isAnimationFrameScheduled) {
        // If rAF didn't already schedule one, we need to schedule a frame.
        // TODO: If this rAF doesn't materialize because the browser throttles, we
        // might want to still have setTimeout trigger rIC as a backup to ensure
        // that we keep performing work.
        isAnimationFrameScheduled = true;
        requestAnimationFrame(animationTick);
      }
      return 0;
    };
  } else {
    rIC = requestIdleCallback;
  }
  
  exports.rIC = rIC;