Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / v8 / ScriptPromiseResolverWithContext.h
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef ScriptPromiseResolverWithContext_h
6 #define ScriptPromiseResolverWithContext_h
7
8 #include "bindings/v8/ScopedPersistent.h"
9 #include "bindings/v8/ScriptPromise.h"
10 #include "bindings/v8/ScriptPromiseResolver.h"
11 #include "bindings/v8/ScriptState.h"
12 #include "bindings/v8/V8Binding.h"
13 #include "core/dom/ActiveDOMObject.h"
14 #include "core/dom/ExecutionContext.h"
15 #include "platform/Timer.h"
16 #include "wtf/RefCounted.h"
17 #include "wtf/Vector.h"
18 #include <v8.h>
19
20 namespace WebCore {
21
22 // This class wraps ScriptPromiseResolver and provides the following
23 // functionalities in addition to ScriptPromiseResolver's.
24 //  - A ScriptPromiseResolverWithContext retains a ScriptState. A caller
25 //    can call resolve or reject from outside of a V8 context.
26 //  - This class is an ActiveDOMObject and keeps track of the associated
27 //    ExecutionContext state. When the ExecutionContext is suspended,
28 //    resolve or reject will be delayed. When it is stopped, resolve or reject
29 //    will be ignored.
30 class ScriptPromiseResolverWithContext : public ActiveDOMObject, public RefCounted<ScriptPromiseResolverWithContext> {
31     WTF_MAKE_NONCOPYABLE(ScriptPromiseResolverWithContext);
32
33 public:
34     static PassRefPtr<ScriptPromiseResolverWithContext> create(ScriptState* scriptState)
35     {
36         RefPtr<ScriptPromiseResolverWithContext> resolver = adoptRef(new ScriptPromiseResolverWithContext(scriptState));
37         resolver->suspendIfNeeded();
38         return resolver.release();
39     }
40
41     virtual ~ScriptPromiseResolverWithContext()
42     {
43         // This assertion fails if:
44         //  - promise() is called at least once and
45         //  - this resolver is destructed before it is resolved, rejected or
46         //    the associated ExecutionContext is stopped.
47         ASSERT(m_state == ResolvedOrRejected || !m_isPromiseCalled);
48     }
49
50     // Anything that can be passed to toV8Value can be passed to this function.
51     template <typename T>
52     void resolve(T value)
53     {
54         resolveOrReject(value, Resolving);
55     }
56
57     // Anything that can be passed to toV8Value can be passed to this function.
58     template <typename T>
59     void reject(T value)
60     {
61         resolveOrReject(value, Rejecting);
62     }
63
64     ScriptState* scriptState() { return m_scriptState.get(); }
65
66     // Note that an empty ScriptPromise will be returned after resolve or
67     // reject is called.
68     ScriptPromise promise()
69     {
70 #if ASSERT_ENABLED
71         m_isPromiseCalled = true;
72 #endif
73         return m_resolver ? m_resolver->promise() : ScriptPromise();
74     }
75
76     ScriptState* scriptState() const { return m_scriptState.get(); }
77
78     // ActiveDOMObject implementation.
79     virtual void suspend() OVERRIDE;
80     virtual void resume() OVERRIDE;
81     virtual void stop() OVERRIDE;
82
83     // Once this function is called this resolver stays alive while the
84     // promise is pending and the associated ExecutionContext isn't stopped.
85     void keepAliveWhilePending();
86
87 protected:
88     // You need to call suspendIfNeeded after the construction because
89     // this is an ActiveDOMObject.
90     explicit ScriptPromiseResolverWithContext(ScriptState*);
91
92 private:
93     enum ResolutionState {
94         Pending,
95         Resolving,
96         Rejecting,
97         ResolvedOrRejected,
98     };
99     enum LifetimeMode {
100         Default,
101         KeepAliveWhilePending,
102     };
103
104     template<typename T>
105     v8::Handle<v8::Value> toV8Value(const T& value)
106     {
107         return ToV8Value<ScriptPromiseResolverWithContext, v8::Handle<v8::Object> >::toV8Value(value, m_scriptState->context()->Global(), m_scriptState->isolate());
108     }
109
110     template <typename T>
111     void resolveOrReject(T value, ResolutionState newState)
112     {
113         if (m_state != Pending || !executionContext() || executionContext()->activeDOMObjectsAreStopped())
114             return;
115         ASSERT(newState == Resolving || newState == Rejecting);
116         m_state = newState;
117         // Retain this object until it is actually resolved or rejected.
118         // |deref| will be called in |clear|.
119         ref();
120
121         ScriptState::Scope scope(m_scriptState.get());
122         m_value.set(m_scriptState->isolate(), toV8Value(value));
123         if (!executionContext()->activeDOMObjectsAreSuspended())
124             resolveOrRejectImmediately();
125     }
126
127     void resolveOrRejectImmediately();
128     void onTimerFired(Timer<ScriptPromiseResolverWithContext>*);
129     void clear();
130
131     ResolutionState m_state;
132     const RefPtr<ScriptState> m_scriptState;
133     LifetimeMode m_mode;
134     Timer<ScriptPromiseResolverWithContext> m_timer;
135     RefPtr<ScriptPromiseResolver> m_resolver;
136     ScopedPersistent<v8::Value> m_value;
137 #if ASSERT_ENABLED
138     // True if promise() is called.
139     bool m_isPromiseCalled;
140 #endif
141 };
142
143 } // namespace WebCore
144
145 #endif // #ifndef ScriptPromiseResolverWithContext_h