OLD | NEW |
| (Empty) |
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 ScriptPromiseResolver_h | |
6 #define ScriptPromiseResolver_h | |
7 | |
8 #include "bindings/v8/ScopedPersistent.h" | |
9 #include "bindings/v8/ScriptPromise.h" | |
10 #include "bindings/v8/ScriptState.h" | |
11 #include "bindings/v8/V8Binding.h" | |
12 #include "core/dom/ActiveDOMObject.h" | |
13 #include "core/dom/ExecutionContext.h" | |
14 #include "platform/Timer.h" | |
15 #include "wtf/RefCounted.h" | |
16 #include "wtf/Vector.h" | |
17 #include <v8.h> | |
18 | |
19 namespace WebCore { | |
20 | |
21 // This class wraps v8::Promise::Resolver and provides the following | |
22 // functionalities. | |
23 // - A ScriptPromiseResolver retains a ScriptState. A caller | |
24 // can call resolve or reject from outside of a V8 context. | |
25 // - This class is an ActiveDOMObject and keeps track of the associated | |
26 // ExecutionContext state. When the ExecutionContext is suspended, | |
27 // resolve or reject will be delayed. When it is stopped, resolve or reject | |
28 // will be ignored. | |
29 class ScriptPromiseResolver : public ActiveDOMObject, public RefCounted<ScriptPr
omiseResolver> { | |
30 WTF_MAKE_NONCOPYABLE(ScriptPromiseResolver); | |
31 | |
32 public: | |
33 static PassRefPtr<ScriptPromiseResolver> create(ScriptState* scriptState) | |
34 { | |
35 RefPtr<ScriptPromiseResolver> resolver = adoptRef(new ScriptPromiseResol
ver(scriptState)); | |
36 resolver->suspendIfNeeded(); | |
37 return resolver.release(); | |
38 } | |
39 | |
40 virtual ~ScriptPromiseResolver() | |
41 { | |
42 // This assertion fails if: | |
43 // - promise() is called at least once and | |
44 // - this resolver is destructed before it is resolved, rejected or | |
45 // the associated ExecutionContext is stopped. | |
46 ASSERT(m_state == ResolvedOrRejected || !m_isPromiseCalled); | |
47 } | |
48 | |
49 // Anything that can be passed to toV8Value can be passed to this function. | |
50 template <typename T> | |
51 void resolve(T value) | |
52 { | |
53 resolveOrReject(value, Resolving); | |
54 } | |
55 | |
56 // Anything that can be passed to toV8Value can be passed to this function. | |
57 template <typename T> | |
58 void reject(T value) | |
59 { | |
60 resolveOrReject(value, Rejecting); | |
61 } | |
62 | |
63 ScriptState* scriptState() { return m_scriptState.get(); } | |
64 | |
65 // Note that an empty ScriptPromise will be returned after resolve or | |
66 // reject is called. | |
67 ScriptPromise promise() | |
68 { | |
69 #if ASSERT_ENABLED | |
70 m_isPromiseCalled = true; | |
71 #endif | |
72 return m_resolver.promise(); | |
73 } | |
74 | |
75 ScriptState* scriptState() const { return m_scriptState.get(); } | |
76 | |
77 // ActiveDOMObject implementation. | |
78 virtual void suspend() OVERRIDE; | |
79 virtual void resume() OVERRIDE; | |
80 virtual void stop() OVERRIDE; | |
81 | |
82 // Once this function is called this resolver stays alive while the | |
83 // promise is pending and the associated ExecutionContext isn't stopped. | |
84 void keepAliveWhilePending(); | |
85 | |
86 protected: | |
87 // You need to call suspendIfNeeded after the construction because | |
88 // this is an ActiveDOMObject. | |
89 explicit ScriptPromiseResolver(ScriptState*); | |
90 | |
91 private: | |
92 typedef ScriptPromise::InternalResolver Resolver; | |
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 V8ValueTraits<T>::toV8Value(value, m_scriptState->context()->Glob
al(), m_scriptState->isolate()); | |
108 } | |
109 | |
110 template <typename T> | |
111 void resolveOrReject(T value, ResolutionState newState) | |
112 { | |
113 if (m_state != Pending || !executionContext() || executionContext()->act
iveDOMObjectsAreStopped()) | |
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<ScriptPromiseResolver>*); | |
129 void clear(); | |
130 | |
131 ResolutionState m_state; | |
132 const RefPtr<ScriptState> m_scriptState; | |
133 LifetimeMode m_mode; | |
134 Timer<ScriptPromiseResolver> m_timer; | |
135 Resolver 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 ScriptPromiseResolver_h | |
OLD | NEW |