text: /*
   * 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 "wtf/Assertions.h"
  #include "wtf/Noncopyable.h"
  
  namespace WebCore {
  
  class DocumentLifecycle {
      WTF_MAKE_NONCOPYABLE(DocumentLifecycle);
  public:
      enum State {
          Uninitialized,
          Inactive,
  
          // When the document is active, it traverses these states.
  
          VisualUpdatePending,
  
          InStyleRecalc,
          StyleClean,
  
          InPreLayout,
          InPerformLayout,
          AfterPerformLayout,
          LayoutClean,
  
          InCompositingUpdate,
          CompositingClean,
  
          // Once the document starts shuting down, we cannot return
          // to the style/layout/rendering states.
          Stopping,
          Stopped,
          Disposed,
      };
  
      class Scope {
          WTF_MAKE_NONCOPYABLE(Scope);
      public:
          Scope(DocumentLifecycle&, State finalState);
          ~Scope();
  
          void setFinalState(State finalState) { m_finalState = finalState; }
  
      private:
          DocumentLifecycle& m_lifecycle;
          State m_finalState;
      };
  
      class DeprecatedTransition {
          WTF_MAKE_NONCOPYABLE(DeprecatedTransition);
      public:
          DeprecatedTransition(State from, State to);
          ~DeprecatedTransition();
  
          State from() const { return m_from; }
          State to() const { return m_to; }
  
      private:
          DeprecatedTransition* m_previous;
          State m_from;
          State m_to;
      };
  
      class DetachScope {
          WTF_MAKE_NONCOPYABLE(DetachScope);
      public:
          explicit DetachScope(DocumentLifecycle& documentLifecycle)
              : m_documentLifecycle(documentLifecycle)
          {
              m_documentLifecycle.incrementDetachCount();
          }
  
          ~DetachScope()
          {
              m_documentLifecycle.decrementDetachCount();
          }
  
      private:
          DocumentLifecycle& m_documentLifecycle;
      };
  
      DocumentLifecycle();
      ~DocumentLifecycle();
  
      bool isActive() const { return m_state > Inactive && m_state < Stopping; }
      State state() const { return m_state; }
  
      bool stateAllowsTreeMutations() const;
      bool stateAllowsRenderTreeMutations() const;
      bool stateAllowsDetach() const;
  
      void advanceTo(State);
      void ensureStateAtMost(State);
  
      void incrementDetachCount() { m_detachCount++; }
      void decrementDetachCount()
      {
          ASSERT(m_detachCount > 0);
          m_detachCount--;
      }
  
  private:
  #if ASSERT_ENABLED
      bool canAdvanceTo(State) const;
      bool canRewindTo(State) const;
  #endif
  
      State m_state;
      int m_detachCount;
  };
  
  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;
  }
  
  inline bool DocumentLifecycle::stateAllowsRenderTreeMutations() const
  {
      return m_detachCount || m_state == InStyleRecalc;
  }
  
  inline bool DocumentLifecycle::stateAllowsDetach() const
  {
      return m_state == VisualUpdatePending
          || m_state == InStyleRecalc
          || m_state == StyleClean
          || m_state == InPreLayout
          || m_state == LayoutClean
          || m_state == CompositingClean
          || m_state == Stopping;
  }
  
  }
  
  #endif
  