| 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 |