/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DocumentLifecycle_h
#define DocumentLifecycle_h

#include "core/CoreExport.h"
#include "wtf/Allocator.h"
#include "wtf/Assertions.h"
#include "wtf/Noncopyable.h"

#if DCHECK_IS_ON()
#include "wtf/Forward.h"
#endif

namespace blink {

class CORE_EXPORT DocumentLifecycle {
  DISALLOW_NEW();
  WTF_MAKE_NONCOPYABLE(DocumentLifecycle);

 public:
  enum LifecycleState {
    Uninitialized,
    Inactive,

    // When the document is active, it traverses these states.

    VisualUpdatePending,

    InStyleRecalc,
    StyleClean,

    InLayoutSubtreeChange,
    LayoutSubtreeChangeClean,

    InPreLayout,
    InPerformLayout,
    AfterPerformLayout,
    LayoutClean,

    InCompositingUpdate,
    CompositingClean,

    InPaintInvalidation,
    PaintInvalidationClean,

    // In InPrePaint step, any data needed by painting are prepared.
    // When RuntimeEnabledFeatures::slimmingPaintV2Enabled, paint property trees
    // are built.
    // Otherwise these steps are not applicable.
    InPrePaint,
    PrePaintClean,

    InPaint,
    PaintClean,

    // Once the document starts shutting down, we cannot return
    // to the style/layout/compositing states.
    Stopping,
    Stopped,
  };

  class Scope {
    STACK_ALLOCATED();
    WTF_MAKE_NONCOPYABLE(Scope);

   public:
    Scope(DocumentLifecycle&, LifecycleState finalState);
    ~Scope();

   private:
    DocumentLifecycle& m_lifecycle;
    LifecycleState m_finalState;
  };

  class DeprecatedTransition {
    DISALLOW_NEW();
    WTF_MAKE_NONCOPYABLE(DeprecatedTransition);

   public:
    DeprecatedTransition(LifecycleState from, LifecycleState to);
    ~DeprecatedTransition();

    LifecycleState from() const { return m_from; }
    LifecycleState to() const { return m_to; }

   private:
    DeprecatedTransition* m_previous;
    LifecycleState m_from;
    LifecycleState m_to;
  };

  // Within this scope, state transitions are not allowed.
  // Any attempts to advance or rewind will result in a DCHECK.
  class DisallowTransitionScope {
    STACK_ALLOCATED();
    WTF_MAKE_NONCOPYABLE(DisallowTransitionScope);

   public:
    explicit DisallowTransitionScope(DocumentLifecycle& documentLifecycle)
        : m_documentLifecycle(documentLifecycle) {
      m_documentLifecycle.incrementNoTransitionCount();
    }

    ~DisallowTransitionScope() {
      m_documentLifecycle.decrementNoTransitionCount();
    }

   private:
    DocumentLifecycle& m_documentLifecycle;
  };

  class DetachScope {
    STACK_ALLOCATED();
    WTF_MAKE_NONCOPYABLE(DetachScope);

   public:
    explicit DetachScope(DocumentLifecycle& documentLifecycle)
        : m_documentLifecycle(documentLifecycle) {
      m_documentLifecycle.incrementDetachCount();
    }

    ~DetachScope() { m_documentLifecycle.decrementDetachCount(); }

   private:
    DocumentLifecycle& m_documentLifecycle;
  };

  // Throttling is disabled by default. Instantiating this class allows
  // throttling (e.g., during BeginMainFrame). If a script needs to run inside
  // this scope, DisallowThrottlingScope should be used to let the script
  // perform a synchronous layout if necessary.
  class CORE_EXPORT AllowThrottlingScope {
    STACK_ALLOCATED();
    WTF_MAKE_NONCOPYABLE(AllowThrottlingScope);

   public:
    AllowThrottlingScope(DocumentLifecycle&);
    ~AllowThrottlingScope();
  };

  class CORE_EXPORT DisallowThrottlingScope {
    STACK_ALLOCATED();
    WTF_MAKE_NONCOPYABLE(DisallowThrottlingScope);

   public:
    DisallowThrottlingScope(DocumentLifecycle&);
    ~DisallowThrottlingScope();

   private:
    int m_savedCount;
  };

  DocumentLifecycle();
  ~DocumentLifecycle();

  bool isActive() const { return m_state > Inactive && m_state < Stopping; }
  LifecycleState state() const { return m_state; }

  bool stateAllowsTreeMutations() const;
  bool stateAllowsLayoutTreeMutations() const;
  bool stateAllowsDetach() const;
  bool stateAllowsLayoutInvalidation() const;
  bool stateAllowsLayoutTreeNotifications() const;

  void advanceTo(LifecycleState);
  void ensureStateAtMost(LifecycleState);

  bool stateTransitionDisallowed() const { return m_disallowTransitionCount; }
  void incrementNoTransitionCount() { m_disallowTransitionCount++; }
  void decrementNoTransitionCount() {
    DCHECK_GT(m_disallowTransitionCount, 0);
    m_disallowTransitionCount--;
  }

  bool inDetach() const { return m_detachCount; }
  void incrementDetachCount() { m_detachCount++; }
  void decrementDetachCount() {
    DCHECK_GT(m_detachCount, 0);
    m_detachCount--;
  }

  bool throttlingAllowed() const;

#if DCHECK_IS_ON()
  WTF::String toString() const;
#endif
 private:
#if DCHECK_IS_ON()
  bool canAdvanceTo(LifecycleState) const;
  bool canRewindTo(LifecycleState) const;
#endif

  LifecycleState m_state;
  int m_detachCount;
  int m_disallowTransitionCount;
};

inline bool DocumentLifecycle::stateAllowsTreeMutations() const {
  // FIXME: We should not allow mutations in InPreLayout or AfterPerformLayout
  // either, but we need to fix MediaList listeners and plugins first.
  return m_state != InStyleRecalc && m_state != InPerformLayout &&
         m_state != InCompositingUpdate && m_state != InPrePaint &&
         m_state != InPaint;
}

inline bool DocumentLifecycle::stateAllowsLayoutTreeMutations() const {
  return m_detachCount || m_state == InStyleRecalc ||
         m_state == InLayoutSubtreeChange;
}

inline bool DocumentLifecycle::stateAllowsLayoutTreeNotifications() const {
  return m_state == InLayoutSubtreeChange;
}

inline bool DocumentLifecycle::stateAllowsDetach() const {
  return m_state == VisualUpdatePending || m_state == InStyleRecalc ||
         m_state == StyleClean || m_state == LayoutSubtreeChangeClean ||
         m_state == InPreLayout || m_state == LayoutClean ||
         m_state == CompositingClean || m_state == PaintInvalidationClean ||
         m_state == PrePaintClean || m_state == PaintClean ||
         m_state == Stopping;
}

inline bool DocumentLifecycle::stateAllowsLayoutInvalidation() const {
  return m_state != InPerformLayout && m_state != InCompositingUpdate &&
         m_state != InPaintInvalidation && m_state != InPrePaint &&
         m_state != InPaint;
}

}  // namespace blink

#endif
