// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef ScriptPromiseProperty_h #define ScriptPromiseProperty_h #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromisePropertyBase.h" #include "bindings/core/v8/V8Binding.h" #include "wtf/Noncopyable.h" #include "wtf/PassRefPtr.h" namespace blink { class ExecutionContext; // ScriptPromiseProperty is a helper for implementing a DOM method or // attribute whose value is a Promise, and the same Promise must be // returned each time. // // ScriptPromiseProperty does not keep Promises or worlds alive to // deliver Promise resolution/rejection to them; the Promise // resolution/rejections are delivered if the holder's wrapper is // alive. This is achieved by keeping a weak reference from // ScriptPromiseProperty to the holder's wrapper, and references in // hidden values from the wrapper to the promise and resolver // (coincidentally the Resolver and Promise may be the same object, // but that is an implementation detail of v8.) // // ----> Resolver // / // ScriptPromiseProperty - - -> Holder Wrapper ----> Promise // // To avoid exposing the action of the garbage collector to script, // you should keep the wrapper alive as long as a promise may be // settled. // // To avoid clobbering hidden values, a holder should only have one // ScriptPromiseProperty object for a given name at a time. See reset. template class ScriptPromiseProperty : public ScriptPromisePropertyBase { WTF_MAKE_NONCOPYABLE(ScriptPromiseProperty); public: // Creates a ScriptPromiseProperty that will create Promises in // the specified ExecutionContext for a property of 'holder' // (typically ScriptPromiseProperty should be a member of the // property holder). // // When implementing a ScriptPromiseProperty add the property name // to ScriptPromiseProperties.h and pass // ScriptPromiseProperty::Foo to create. The name must be unique // per kind of holder. template ScriptPromiseProperty(ExecutionContext*, PassHolderType, Name); virtual ~ScriptPromiseProperty() { } template void resolve(PassResolvedType); template void reject(PassRejectedType); // Resets this property by unregistering the Promise property from the // holder wrapper. Resets the internal state to Pending and clears the // resolved and the rejected values. // This method keeps the holder object and the property name. void reset(); virtual void trace(Visitor*) OVERRIDE; private: virtual v8::Handle holder(v8::Handle creationContext, v8::Isolate*) OVERRIDE; virtual v8::Handle resolvedValue(v8::Handle creationContext, v8::Isolate*) OVERRIDE; virtual v8::Handle rejectedValue(v8::Handle creationContext, v8::Isolate*) OVERRIDE; HolderType m_holder; ResolvedType m_resolved; RejectedType m_rejected; }; template template ScriptPromiseProperty::ScriptPromiseProperty(ExecutionContext* executionContext, PassHolderType holder, Name name) : ScriptPromisePropertyBase(executionContext, name) , m_holder(holder) { } template template void ScriptPromiseProperty::resolve(PassResolvedType value) { if (state() != Pending) { ASSERT_NOT_REACHED(); return; } if (!executionContext() || executionContext()->activeDOMObjectsAreStopped()) return; m_resolved = value; resolveOrReject(Resolved); } template template void ScriptPromiseProperty::reject(PassRejectedType value) { if (state() != Pending) { ASSERT_NOT_REACHED(); return; } if (!executionContext() || executionContext()->activeDOMObjectsAreStopped()) return; m_rejected = value; resolveOrReject(Rejected); } template v8::Handle ScriptPromiseProperty::holder(v8::Handle creationContext, v8::Isolate* isolate) { v8::Handle value = V8ValueTraits::toV8Value(m_holder, creationContext, isolate); return value.As(); } template v8::Handle ScriptPromiseProperty::resolvedValue(v8::Handle creationContext, v8::Isolate* isolate) { ASSERT(state() == Resolved); return V8ValueTraits::toV8Value(m_resolved, creationContext, isolate); } template v8::Handle ScriptPromiseProperty::rejectedValue(v8::Handle creationContext, v8::Isolate* isolate) { ASSERT(state() == Rejected); return V8ValueTraits::toV8Value(m_rejected, creationContext, isolate); } template void ScriptPromiseProperty::reset() { resetBase(); m_resolved = ResolvedType(); m_rejected = RejectedType(); } template void ScriptPromiseProperty::trace(Visitor* visitor) { TraceIfNeeded::trace(visitor, &m_holder); TraceIfNeeded::trace(visitor, &m_resolved); TraceIfNeeded::trace(visitor, &m_rejected); ScriptPromisePropertyBase::trace(visitor); } } // namespace blink #endif // ScriptPromiseProperty_h