/* * 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. */ #include "sky/engine/core/dom/DocumentLifecycle.h" #include "sky/engine/wtf/Assertions.h" namespace blink { static DocumentLifecycle::DeprecatedTransition* s_deprecatedTransitionStack = 0; DocumentLifecycle::Scope::Scope(DocumentLifecycle& lifecycle, State finalState) : m_lifecycle(lifecycle) , m_finalState(finalState) { } DocumentLifecycle::Scope::~Scope() { m_lifecycle.advanceTo(m_finalState); } DocumentLifecycle::DeprecatedTransition::DeprecatedTransition(State from, State to) : m_previous(s_deprecatedTransitionStack) , m_from(from) , m_to(to) { s_deprecatedTransitionStack = this; } DocumentLifecycle::DeprecatedTransition::~DeprecatedTransition() { s_deprecatedTransitionStack = m_previous; } DocumentLifecycle::DocumentLifecycle() : m_state(Uninitialized) , m_detachCount(0) { } DocumentLifecycle::~DocumentLifecycle() { } #if ENABLE(ASSERT) bool DocumentLifecycle::canAdvanceTo(State state) const { if (state > m_state) return true; if (m_state == Disposed) { // FIXME: We can dispose a document multiple times. This seems wrong. // See https://code.google.com/p/chromium/issues/detail?id=301668. return state == Disposed; } if (m_state == StyleClean) { // We can synchronously recalc style. if (state == InStyleRecalc) return true; // We can synchronously perform layout. if (state == InPreLayout) return true; if (state == InPerformLayout) return true; // We can redundant arrive in the style clean state. if (state == StyleClean) return true; return false; } if (m_state == InPreLayout) { if (state == InStyleRecalc) return true; if (state == StyleClean) return true; if (state == InPreLayout) return true; return false; } if (m_state == AfterPerformLayout) { // We can synchronously recompute layout in AfterPerformLayout. // FIXME: Ideally, we would unnest this recursion into a loop. return state == InPreLayout; } if (m_state == LayoutClean) { // We can synchronously recalc style. if (state == InStyleRecalc) return true; // We can synchronously perform layout. if (state == InPreLayout) return true; if (state == InPerformLayout) return true; // We can redundant arrive in the layout clean state. This situation // can happen when we call layout recursively and we unwind the stack. if (state == LayoutClean) return true; if (state == StyleClean) return true; return false; } if (m_state == StyleAndLayoutClean) { if (state == InStyleRecalc) return true; if (state == InPreLayout) return true; if (state == LayoutClean) return true; // We can pump frames without style or layout needing updating. if (state == StyleAndLayoutClean) return true; return false; } return false; } bool DocumentLifecycle::canRewindTo(State state) const { // This transition is bogus, but we've whitelisted it anyway. if (s_deprecatedTransitionStack && m_state == s_deprecatedTransitionStack->from() && state == s_deprecatedTransitionStack->to()) return true; return m_state == StyleClean || m_state == AfterPerformLayout || m_state == LayoutClean || m_state == StyleAndLayoutClean; } #endif void DocumentLifecycle::advanceTo(State state) { ASSERT(canAdvanceTo(state)); m_state = state; } void DocumentLifecycle::ensureStateAtMost(State state) { ASSERT(state == VisualUpdatePending || state == StyleClean || state == LayoutClean); if (m_state <= state) return; ASSERT(canRewindTo(state)); m_state = state; } }