author Simon Whitehead <>
Sat, 13 May 2017 15:12:15 -0500
changeset 358329 633151f5d481d49bd39900d43e6a75d77459a7bb
parent 356188 b55f4a13a1aa40ded16f61702509bc52dc877a8f
child 359290 7af3265734b85beff6c6b443bae8966b9a7a5ad0
permissions -rw-r--r--
servo: Merge #16829 - Disallow negative duration for animation and transition (from hiikezoe:disallow-negative-duration); r=emilio <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15343 <!-- Either: --> - [X] There are tests for these changes written by @simon-whitehead . Thank you! <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: Source-Revision: 4613c0382ab76263fb8202ccf52f4c0520e44809

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at */

#ifndef mozilla_dom_TimeoutManager_h__
#define mozilla_dom_TimeoutManager_h__

#include "mozilla/dom/Timeout.h"

class nsIEventTarget;
class nsITimeoutHandler;
class nsGlobalWindow;

namespace mozilla {
namespace dom {

class OrderedTimeoutIterator;

// This class manages the timeouts in a Window's setTimeout/setInterval pool.
class TimeoutManager final
  explicit TimeoutManager(nsGlobalWindow& aWindow);
  TimeoutManager(const TimeoutManager& rhs) = delete;
  void operator=(const TimeoutManager& rhs) = delete;

  bool IsRunningTimeout() const { return mTimeoutFiringDepth > 0; }

  static uint32_t GetNestingLevel() { return sNestingLevel; }
  static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }

  bool HasTimeouts() const
    return !mNormalTimeouts.IsEmpty() ||

  nsresult SetTimeout(nsITimeoutHandler* aHandler,
                      int32_t interval, bool aIsInterval,
                      mozilla::dom::Timeout::Reason aReason,
                      int32_t* aReturn);
  void ClearTimeout(int32_t aTimerId,
                    mozilla::dom::Timeout::Reason aReason);

  // The timeout implementation functions.
  void RunTimeout(mozilla::dom::Timeout* aTimeout);
  // Return true if |aTimeout| needs to be reinserted into the timeout list.
  bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout, const TimeStamp& now,
                         bool aRunningPendingTimeouts);

  void ClearAllTimeouts();
  uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);

  // Apply back pressure to the window if the TabGroup ThrottledEventQueue
  // exists and has too many runnables waiting to run.  For example, increase
  // the minimum timer delay, etc.
  void MaybeApplyBackPressure();

  // Check the current ThrottledEventQueue depth and update the back pressure
  // state.  If the queue has drained back pressure may be canceled.
  void CancelOrUpdateBackPressure(nsGlobalWindow* aWindow);

  // When timers are being throttled and we reduce the thottle delay we must
  // reschedule.  The amount of the old throttle delay must be provided in
  // order to bound how many timers must be examined.
  nsresult ResetTimersForThrottleReduction();

  int32_t DOMMinTimeoutValue(bool aIsTracking) const;

  // aTimeout is the timeout that we're about to start running.  This function
  // returns the current timeout.
  mozilla::dom::Timeout* BeginRunningTimeout(mozilla::dom::Timeout* aTimeout);
  // aTimeout is the last running timeout.
  void EndRunningTimeout(mozilla::dom::Timeout* aTimeout);

  void UnmarkGrayTimers();

  // These four methods are intended to be called from the corresponding methods
  // on nsGlobalWindow.
  void Suspend();
  void Resume();
  void Freeze();
  void Thaw();

  // Initialize TimeoutManager before the first time it is accessed.
  static void Initialize();

  // Exposed only for testing
  bool IsTimeoutTracking(uint32_t aTimeoutId);

  // The document finished loading
  void OnDocumentLoaded();
  void StartThrottlingTrackingTimeouts();

  // Run some code for each Timeout in our list.  Note that this function
  // doesn't guarantee that Timeouts are iterated in any particular order.
  template <class Callable>
  void ForEachUnorderedTimeout(Callable c)

  // Run some code for each Timeout in our list, but let the callback cancel the
  // iteration by returning true.  Note that this function doesn't guarantee
  // that Timeouts are iterated in any particular order.
  template <class Callable>
  void ForEachUnorderedTimeoutAbortable(Callable c)
    if (!mNormalTimeouts.ForEachAbortable(c)) {

  void BeginSyncOperation();
  void EndSyncOperation();
  nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS);
  void MaybeStartThrottleTrackingTimout();

  bool IsBackground() const;
  struct Timeouts {
      : mTimeoutInsertionPoint(nullptr)

    // Insert aTimeout into the list, before all timeouts that would
    // fire after it, but no earlier than mTimeoutInsertionPoint, if any.
    enum class SortBy
    void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
    nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
                                             const TimeoutManager& aTimeoutManager,
                                             SortBy aSortBy,
                                             nsIEventTarget* aQueue);

    const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
    Timeout* GetFirst() { return mTimeoutList.getFirst(); }
    const Timeout* GetLast() const { return mTimeoutList.getLast(); }
    Timeout* GetLast() { return mTimeoutList.getLast(); }
    bool IsEmpty() const { return mTimeoutList.isEmpty(); }
    void InsertFront(Timeout* aTimeout) { mTimeoutList.insertFront(aTimeout); }
    void Clear() { mTimeoutList.clear(); }

    void SetInsertionPoint(Timeout* aTimeout)
      mTimeoutInsertionPoint = aTimeout;
    Timeout* InsertionPoint()
      return mTimeoutInsertionPoint;

    template <class Callable>
    void ForEach(Callable c)
      for (Timeout* timeout = GetFirst();
           timeout = timeout->getNext()) {

    // Returns true when a callback aborts iteration.
    template <class Callable>
    bool ForEachAbortable(Callable c)
      for (Timeout* timeout = GetFirst();
           timeout = timeout->getNext()) {
        if (c(timeout)) {
          return true;
      return false;

    friend class OrderedTimeoutIterator;

    typedef mozilla::LinkedList<mozilla::dom::Timeout> TimeoutList;

    // mTimeoutList is generally sorted by mWhen, unless mTimeoutInsertionPoint is
    // non-null.  In that case, the dummy timeout pointed to by
    // mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
    // that come after it.
    TimeoutList               mTimeoutList;
    // If mTimeoutInsertionPoint is non-null, insertions should happen after it.
    // This is a dummy timeout at the moment; if that ever changes, the logic in
    // ResetTimersForThrottleReduction needs to change.
    mozilla::dom::Timeout*    mTimeoutInsertionPoint;

  friend class OrderedTimeoutIterator;

  // Each nsGlobalWindow object has a TimeoutManager member.  This reference
  // points to that holder object.
  nsGlobalWindow&             mWindow;
  // The list of timeouts coming from non-tracking scripts.
  Timeouts                    mNormalTimeouts;
  // The list of timeouts coming from scripts on the tracking protection list.
  Timeouts                    mTrackingTimeouts;
  uint32_t                    mTimeoutIdCounter;
  uint32_t                    mTimeoutFiringDepth;
  mozilla::dom::Timeout*      mRunningTimeout;

   // The current idle request callback timeout handle
  uint32_t                    mIdleCallbackTimeoutCounter;

  int32_t                     mBackPressureDelayMS;

  nsCOMPtr<nsITimer>          mThrottleTrackingTimeoutsTimer;
  bool                        mThrottleTrackingTimeouts;

  static uint32_t             sNestingLevel;