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