1/*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2013 Google Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#include "config.h"
29#include "core/dom/ContextLifecycleNotifier.h"
30
31#include "core/dom/ExecutionContext.h"
32#include "wtf/TemporaryChange.h"
33
34namespace blink {
35
36ContextLifecycleNotifier::ContextLifecycleNotifier(ExecutionContext* context)
37    : LifecycleNotifier<ExecutionContext>(context)
38{
39}
40
41ContextLifecycleNotifier::~ContextLifecycleNotifier()
42{
43}
44
45void ContextLifecycleNotifier::addObserver(ContextLifecycleNotifier::Observer* observer)
46{
47    LifecycleNotifier<ExecutionContext>::addObserver(observer);
48
49    RELEASE_ASSERT(m_iterating != IteratingOverContextObservers);
50    if (observer->observerType() == Observer::ActiveDOMObjectType) {
51        RELEASE_ASSERT(m_iterating != IteratingOverActiveDOMObjects);
52        m_activeDOMObjects.add(static_cast<ActiveDOMObject*>(observer));
53    }
54}
55
56void ContextLifecycleNotifier::removeObserver(ContextLifecycleNotifier::Observer* observer)
57{
58    LifecycleNotifier<ExecutionContext>::removeObserver(observer);
59
60    RELEASE_ASSERT(m_iterating != IteratingOverContextObservers);
61    if (observer->observerType() == Observer::ActiveDOMObjectType) {
62        m_activeDOMObjects.remove(static_cast<ActiveDOMObject*>(observer));
63    }
64}
65
66void ContextLifecycleNotifier::notifyResumingActiveDOMObjects()
67{
68    TemporaryChange<IterationType> scope(this->m_iterating, IteratingOverActiveDOMObjects);
69    Vector<ActiveDOMObject*> snapshotOfActiveDOMObjects;
70    copyToVector(m_activeDOMObjects, snapshotOfActiveDOMObjects);
71    for (Vector<ActiveDOMObject*>::iterator iter = snapshotOfActiveDOMObjects.begin(); iter != snapshotOfActiveDOMObjects.end(); iter++) {
72        // FIXME: Oilpan: At the moment, it's possible that the ActiveDOMObject is destructed
73        // during the iteration. Once we move ActiveDOMObject to the heap and
74        // make m_activeDOMObjects a HeapHashSet<WeakMember<ActiveDOMObject>>,
75        // it's no longer possible that ActiveDOMObject is destructed during the iteration,
76        // so we can remove the hack (i.e., we can just iterate m_activeDOMObjects without
77        // taking a snapshot). For more details, see https://codereview.chromium.org/247253002/.
78        if (m_activeDOMObjects.contains(*iter)) {
79            ASSERT((*iter)->executionContext() == context());
80            ASSERT((*iter)->suspendIfNeededCalled());
81            (*iter)->resume();
82        }
83    }
84}
85
86void ContextLifecycleNotifier::notifySuspendingActiveDOMObjects()
87{
88    TemporaryChange<IterationType> scope(this->m_iterating, IteratingOverActiveDOMObjects);
89    Vector<ActiveDOMObject*> snapshotOfActiveDOMObjects;
90    copyToVector(m_activeDOMObjects, snapshotOfActiveDOMObjects);
91    for (Vector<ActiveDOMObject*>::iterator iter = snapshotOfActiveDOMObjects.begin(); iter != snapshotOfActiveDOMObjects.end(); iter++) {
92        // It's possible that the ActiveDOMObject is already destructed.
93        // See a FIXME above.
94        if (m_activeDOMObjects.contains(*iter)) {
95            ASSERT((*iter)->executionContext() == context());
96            ASSERT((*iter)->suspendIfNeededCalled());
97            (*iter)->suspend();
98        }
99    }
100}
101
102void ContextLifecycleNotifier::notifyStoppingActiveDOMObjects()
103{
104    TemporaryChange<IterationType> scope(this->m_iterating, IteratingOverActiveDOMObjects);
105    Vector<ActiveDOMObject*> snapshotOfActiveDOMObjects;
106    copyToVector(m_activeDOMObjects, snapshotOfActiveDOMObjects);
107    for (Vector<ActiveDOMObject*>::iterator iter = snapshotOfActiveDOMObjects.begin(); iter != snapshotOfActiveDOMObjects.end(); iter++) {
108        // It's possible that the ActiveDOMObject is already destructed.
109        // See a FIXME above.
110        if (m_activeDOMObjects.contains(*iter)) {
111            ASSERT((*iter)->executionContext() == context());
112            ASSERT((*iter)->suspendIfNeededCalled());
113            (*iter)->stop();
114        }
115    }
116}
117
118bool ContextLifecycleNotifier::hasPendingActivity() const
119{
120    for (ActiveDOMObjectSet::const_iterator iter = m_activeDOMObjects.begin(); iter != m_activeDOMObjects.end(); ++iter) {
121        if ((*iter)->hasPendingActivity())
122            return true;
123    }
124    return false;
125}
126
127} // namespace blink
128