| /* |
| * 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 THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOCUMENT_LIFECYCLE_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOCUMENT_LIFECYCLE_H_ |
| |
| #include "base/auto_reset.h" |
| #include "base/macros.h" |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator.h" |
| #include "third_party/blink/renderer/platform/wtf/assertions.h" |
| |
| #if DCHECK_IS_ON() |
| #include "third_party/blink/renderer/platform/wtf/forward.h" |
| #endif |
| |
| namespace blink { |
| |
| class CORE_EXPORT DocumentLifecycle { |
| DISALLOW_NEW(); |
| |
| public: |
| enum LifecycleState { |
| kUninitialized, |
| kInactive, |
| |
| // When the document is active, it traverses these states. |
| |
| kVisualUpdatePending, |
| |
| kInStyleRecalc, |
| kStyleClean, |
| |
| kInLayoutSubtreeChange, |
| kLayoutSubtreeChangeClean, |
| |
| kInPreLayout, |
| kInPerformLayout, |
| kAfterPerformLayout, |
| kLayoutClean, |
| |
| kInCompositingUpdate, |
| kCompositingInputsClean, |
| kCompositingClean, |
| |
| // In InPrePaint step, any data needed by painting are prepared. |
| // Paint property trees are built and paint invalidations are issued. |
| kInPrePaint, |
| kPrePaintClean, |
| |
| // In InPaint step, paint artifacts are generated and raster invalidations |
| // are issued. |
| // In CAP, composited layers are generated/updated. |
| kInPaint, |
| kPaintClean, |
| |
| // Once the document starts shutting down, we cannot return |
| // to the style/layout/compositing states. |
| kStopping, |
| kStopped, |
| }; |
| |
| // This must be kept coordinated with WebWidget::LifecycleUpdateReason |
| enum LifecycleUpdateReason { kBeginMainFrame, kTest, kOther }; |
| |
| class Scope { |
| STACK_ALLOCATED(); |
| |
| public: |
| Scope(DocumentLifecycle&, LifecycleState final_state); |
| ~Scope(); |
| |
| private: |
| DocumentLifecycle& lifecycle_; |
| LifecycleState final_state_; |
| DISALLOW_COPY_AND_ASSIGN(Scope); |
| }; |
| |
| class DeprecatedTransition { |
| DISALLOW_NEW(); |
| |
| public: |
| DeprecatedTransition(LifecycleState from, LifecycleState to); |
| ~DeprecatedTransition(); |
| |
| LifecycleState From() const { return from_; } |
| LifecycleState To() const { return to_; } |
| |
| private: |
| DeprecatedTransition* previous_; |
| LifecycleState from_; |
| LifecycleState to_; |
| DISALLOW_COPY_AND_ASSIGN(DeprecatedTransition); |
| }; |
| |
| // Within this scope, state transitions are not allowed. |
| // Any attempts to advance or rewind will result in a DCHECK. |
| class DisallowTransitionScope { |
| STACK_ALLOCATED(); |
| |
| public: |
| explicit DisallowTransitionScope(DocumentLifecycle& document_lifecycle) |
| : document_lifecycle_(document_lifecycle) { |
| document_lifecycle_.IncrementNoTransitionCount(); |
| } |
| |
| ~DisallowTransitionScope() { |
| document_lifecycle_.DecrementNoTransitionCount(); |
| } |
| |
| private: |
| DocumentLifecycle& document_lifecycle_; |
| DISALLOW_COPY_AND_ASSIGN(DisallowTransitionScope); |
| }; |
| |
| class DetachScope { |
| STACK_ALLOCATED(); |
| |
| public: |
| explicit DetachScope(DocumentLifecycle& document_lifecycle) |
| : document_lifecycle_(document_lifecycle) { |
| document_lifecycle_.IncrementDetachCount(); |
| } |
| |
| ~DetachScope() { document_lifecycle_.DecrementDetachCount(); } |
| |
| private: |
| DocumentLifecycle& document_lifecycle_; |
| DISALLOW_COPY_AND_ASSIGN(DetachScope); |
| }; |
| |
| // 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(); |
| |
| public: |
| AllowThrottlingScope(DocumentLifecycle&); |
| ~AllowThrottlingScope(); |
| DISALLOW_COPY_AND_ASSIGN(AllowThrottlingScope); |
| }; |
| |
| class CORE_EXPORT DisallowThrottlingScope { |
| STACK_ALLOCATED(); |
| |
| public: |
| DisallowThrottlingScope(DocumentLifecycle&); |
| ~DisallowThrottlingScope(); |
| |
| private: |
| int saved_count_; |
| DISALLOW_COPY_AND_ASSIGN(DisallowThrottlingScope); |
| }; |
| |
| // If we hit a devtool break point in the middle of document lifecycle, for |
| // example, https://crbug.com/788219, this scope is triggered and no more |
| // layout or style computation is allowed. |
| // This class should never be used outside of debugging. |
| class PostponeTransitionScope { |
| public: |
| explicit PostponeTransitionScope(DocumentLifecycle& document_lifecycle) |
| : document_lifecycle_(document_lifecycle) { |
| document_lifecycle_.SetLifecyclePostponed(); |
| } |
| ~PostponeTransitionScope() { |
| document_lifecycle_.ResetLifecyclePostponed(); |
| } |
| |
| private: |
| DocumentLifecycle& document_lifecycle_; |
| }; |
| |
| class CheckNoTransitionScope { |
| STACK_ALLOCATED(); |
| |
| public: |
| explicit CheckNoTransitionScope(DocumentLifecycle& document_lifecycle) |
| : auto_reset_(&document_lifecycle.check_no_transition_, true) {} |
| |
| private: |
| base::AutoReset<bool> auto_reset_; |
| }; |
| |
| DocumentLifecycle(); |
| ~DocumentLifecycle(); |
| |
| bool IsActive() const { return state_ > kInactive && state_ < kStopping; } |
| LifecycleState GetState() const { return 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 disallow_transition_count_; } |
| void IncrementNoTransitionCount() { disallow_transition_count_++; } |
| void DecrementNoTransitionCount() { |
| DCHECK_GT(disallow_transition_count_, 0); |
| disallow_transition_count_--; |
| } |
| |
| bool InDetach() const { return detach_count_; } |
| void IncrementDetachCount() { detach_count_++; } |
| void DecrementDetachCount() { |
| DCHECK_GT(detach_count_, 0); |
| detach_count_--; |
| } |
| |
| bool ThrottlingAllowed() const; |
| bool LifecyclePostponed() const { return life_cycle_postponed_; } |
| |
| #if DCHECK_IS_ON() |
| WTF::String ToString() const; |
| #endif |
| private: |
| friend class PostponeTransitionScope; |
| friend class CheckNoTransitionScope; |
| #if DCHECK_IS_ON() |
| bool CanAdvanceTo(LifecycleState) const; |
| bool CanRewindTo(LifecycleState) const; |
| #endif |
| |
| void SetLifecyclePostponed() { life_cycle_postponed_ = true; } |
| void ResetLifecyclePostponed() { life_cycle_postponed_ = false; } |
| |
| LifecycleState state_; |
| int detach_count_; |
| int disallow_transition_count_; |
| bool life_cycle_postponed_; |
| bool check_no_transition_; |
| DISALLOW_COPY_AND_ASSIGN(DocumentLifecycle); |
| }; |
| |
| 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 state_ != kInStyleRecalc && state_ != kInPerformLayout && |
| state_ != kInCompositingUpdate && state_ != kInPrePaint && |
| state_ != kInPaint; |
| } |
| |
| inline bool DocumentLifecycle::StateAllowsLayoutTreeMutations() const { |
| return detach_count_ || state_ == kInStyleRecalc || |
| state_ == kInLayoutSubtreeChange; |
| } |
| |
| inline bool DocumentLifecycle::StateAllowsLayoutTreeNotifications() const { |
| return state_ == kInLayoutSubtreeChange; |
| } |
| |
| inline bool DocumentLifecycle::StateAllowsDetach() const { |
| return state_ == kVisualUpdatePending || state_ == kInStyleRecalc || |
| state_ == kStyleClean || state_ == kLayoutSubtreeChangeClean || |
| state_ == kInPreLayout || state_ == kLayoutClean || |
| state_ == kCompositingInputsClean || state_ == kCompositingClean || |
| state_ == kPrePaintClean || state_ == kPaintClean || |
| state_ == kStopping; |
| } |
| |
| inline bool DocumentLifecycle::StateAllowsLayoutInvalidation() const { |
| return state_ != kInPerformLayout && state_ != kInCompositingUpdate && |
| state_ != kInPrePaint && state_ != kInPaint; |
| } |
| |
| } // namespace blink |
| |
| #endif |