Diff
Modified: trunk/Source/WebCore/ChangeLog (185406 => 185407)
--- trunk/Source/WebCore/ChangeLog 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/ChangeLog 2015-06-10 08:10:44 UTC (rev 185407)
@@ -1,3 +1,42 @@
+2015-06-10 Youenn Fablet <[email protected]>
+
+ Refactor AudioContext implementation to enable automatic binding generation of promise-based methods
+ https://bugs.webkit.org/show_bug.cgi?id=145223
+
+ Reviewed by Darin Adler.
+
+ Introducing DOMPromise as a typed wrapper above DeferredWrapper.
+ This DOMPromise allows constraining Promise resolution/rejection to a single resolution type and rejection type.
+ This might be useful for typed callback usage of promise based APIs, like getUserMedia() or ReadableStreamReader.read().
+
+ Applying DOMPromise to AudioContext close, suspend and resume.
+ Changed binding code to represent what could be automatically generated by binding generator.
+ Fixing unneeded copies of std::function callbacks.
+
+ Disabling DOMPromise copy constructors to lower chances that resolution/rejection is done twice on the same object.
+
+ Covered by existing tests.
+
+ * Modules/webaudio/AudioContext.cpp:
+ (WebCore::AudioContext::addReaction):
+ (WebCore::AudioContext::setState):
+ (WebCore::AudioContext::suspend):
+ (WebCore::AudioContext::resume):
+ (WebCore::AudioContext::close):
+ * Modules/webaudio/AudioContext.h:
+ * bindings/js/JSAudioContextCustom.cpp:
+ (WebCore::JSAudioContext::suspend):
+ (WebCore::JSAudioContext::resume):
+ (WebCore::JSAudioContext::close):
+ * bindings/js/JSDOMPromise.cpp:
+ (WebCore::DeferredWrapper::callFunction):
+ * bindings/js/JSDOMPromise.h:
+ (WebCore::DeferredWrapper::resolve):
+ (WebCore::DeferredWrapper::reject):
+ (WebCore::DOMPromise::DOMPromise):
+ (WebCore::DOMPromise::resolve):
+ (WebCore::DOMPromise::reject):
+
2015-06-10 Xabier Rodriguez Calvar <[email protected]> and Youenn Fablet <[email protected]>
[Streams API] Implement pulling of a source by a ReadableStream
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (185406 => 185407)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp 2015-06-10 08:10:44 UTC (rev 185407)
@@ -51,6 +51,7 @@
#include "GenericEventQueue.h"
#include "HRTFDatabaseLoader.h"
#include "HRTFPanner.h"
+#include "JSDOMPromise.h"
#include "OfflineAudioCompletionEvent.h"
#include "OfflineAudioDestinationNode.h"
#include "OscillatorNode.h"
@@ -277,13 +278,13 @@
return m_isInitialized;
}
-void AudioContext::addReaction(State state, std::function<void()> reaction)
+void AudioContext::addReaction(State state, Promise&& promise)
{
size_t stateIndex = static_cast<size_t>(state);
if (stateIndex >= m_stateReactions.size())
m_stateReactions.resize(stateIndex + 1);
- m_stateReactions[stateIndex].append(reaction);
+ m_stateReactions[stateIndex].append(WTF::move(promise));
}
void AudioContext::setState(State state)
@@ -298,11 +299,11 @@
if (stateIndex >= m_stateReactions.size())
return;
- Vector<std::function<void()>> reactions;
+ Vector<Promise> reactions;
m_stateReactions[stateIndex].swap(reactions);
- for (auto& reaction : reactions)
- reaction();
+ for (auto& promise : reactions)
+ promise.resolve(nullptr);
}
const AtomicString& AudioContext::state() const
@@ -1096,27 +1097,24 @@
--m_activeSourceCount;
}
-void AudioContext::suspendContext(std::function<void()> successCallback, FailureCallback failureCallback)
+void AudioContext::suspend(Promise&& promise)
{
- ASSERT(successCallback);
- ASSERT(failureCallback);
-
if (isOfflineContext()) {
- failureCallback(INVALID_STATE_ERR);
+ promise.reject(INVALID_STATE_ERR);
return;
}
if (m_state == State::Suspended) {
- successCallback();
+ promise.resolve(nullptr);
return;
}
if (m_state == State::Closed || m_state == State::Interrupted || !m_destinationNode) {
- failureCallback(0);
+ promise.reject(0);
return;
}
- addReaction(State::Suspended, successCallback);
+ addReaction(State::Suspended, WTF::move(promise));
if (!willPausePlayback())
return;
@@ -1129,27 +1127,24 @@
});
}
-void AudioContext::resumeContext(std::function<void()> successCallback, FailureCallback failureCallback)
+void AudioContext::resume(Promise&& promise)
{
- ASSERT(successCallback);
- ASSERT(failureCallback);
-
if (isOfflineContext()) {
- failureCallback(INVALID_STATE_ERR);
+ promise.reject(INVALID_STATE_ERR);
return;
}
if (m_state == State::Running) {
- successCallback();
+ promise.resolve(nullptr);
return;
}
if (m_state == State::Closed || !m_destinationNode) {
- failureCallback(0);
+ promise.reject(0);
return;
}
- addReaction(State::Running, successCallback);
+ addReaction(State::Running, WTF::move(promise));
if (!willBeginPlayback())
return;
@@ -1162,27 +1157,24 @@
});
}
-void AudioContext::closeContext(std::function<void()> successCallback, FailureCallback failureCallback)
+void AudioContext::close(Promise&& promise)
{
- ASSERT(successCallback);
- ASSERT(failureCallback);
-
if (isOfflineContext()) {
- failureCallback(INVALID_STATE_ERR);
+ promise.reject(INVALID_STATE_ERR);
return;
}
if (m_state == State::Closed || !m_destinationNode) {
- successCallback();
+ promise.resolve(nullptr);
return;
}
- addReaction(State::Closed, successCallback);
+ addReaction(State::Closed, WTF::move(promise));
lazyInitialize();
RefPtr<AudioContext> strongThis(this);
- m_destinationNode->close([strongThis, successCallback] {
+ m_destinationNode->close([strongThis] {
strongThis->setState(State::Closed);
strongThis->uninitialize();
});
Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (185406 => 185407)
--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h 2015-06-10 08:10:44 UTC (rev 185407)
@@ -31,6 +31,7 @@
#include "AudioDestinationNode.h"
#include "EventListener.h"
#include "EventTarget.h"
+#include "JSDOMPromise.h"
#include "MediaCanStartListener.h"
#include "MediaProducer.h"
#include "PlatformMediaSession.h"
@@ -106,11 +107,15 @@
AudioListener* listener() { return m_listener.get(); }
- typedef std::function<void(ExceptionCode)> FailureCallback;
+ using ActiveDOMObject::suspend;
+ using ActiveDOMObject::resume;
- void suspendContext(std::function<void()>, FailureCallback);
- void resumeContext(std::function<void()>, FailureCallback);
- void closeContext(std::function<void()>, FailureCallback);
+ typedef DOMPromise<std::nullptr_t, ExceptionCode> Promise;
+
+ void suspend(Promise&&);
+ void resume(Promise&&);
+ void close(Promise&&);
+
const AtomicString& state() const;
// The AudioNode create methods are called on the main thread (from _javascript_).
@@ -324,7 +329,7 @@
void handleDirtyAudioSummingJunctions();
void handleDirtyAudioNodeOutputs();
- void addReaction(State, std::function<void()>);
+ void addReaction(State, Promise&&);
void updateAutomaticPullNodes();
// Only accessed in the audio thread.
@@ -361,7 +366,7 @@
Vector<AudioNode*> m_renderingAutomaticPullNodes;
// Only accessed in the audio thread.
Vector<AudioNode*> m_deferredFinishDerefList;
- Vector<Vector<std::function<void()>>> m_stateReactions;
+ Vector<Vector<Promise>> m_stateReactions;
std::unique_ptr<PlatformMediaSession> m_mediaSession;
std::unique_ptr<GenericEventQueue> m_eventQueue;
Modified: trunk/Source/WebCore/bindings/js/JSAudioContextCustom.cpp (185406 => 185407)
--- trunk/Source/WebCore/bindings/js/JSAudioContextCustom.cpp 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/bindings/js/JSAudioContextCustom.cpp 2015-06-10 08:10:44 UTC (rev 185407)
@@ -111,50 +111,29 @@
return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), AudioContext, audioContext.get()));
}
-JSValue JSAudioContext::suspend(ExecState* exec)
+JSValue JSAudioContext::suspend(ExecState* state)
{
- JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
- DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
- auto successCallback = [wrapper]() mutable {
- wrapper.resolve(nullptr);
- };
- auto failureCallback = [wrapper](ExceptionCode value) mutable {
- wrapper.reject(value);
- };
+ JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(state, globalObject());
- impl().suspendContext(WTF::move(successCallback), WTF::move(failureCallback));
+ impl().suspend(DeferredWrapper(state, globalObject(), promiseDeferred));
return promiseDeferred->promise();
}
-JSValue JSAudioContext::resume(ExecState* exec)
+JSValue JSAudioContext::resume(ExecState* state)
{
- JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
- DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
- auto successCallback = [wrapper]() mutable {
- wrapper.resolve(nullptr);
- };
- auto failureCallback = [wrapper](ExceptionCode value) mutable {
- wrapper.reject(value);
- };
+ JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(state, globalObject());
- impl().resumeContext(WTF::move(successCallback), WTF::move(failureCallback));
+ impl().resume(DeferredWrapper(state, globalObject(), promiseDeferred));
return promiseDeferred->promise();
}
-JSValue JSAudioContext::close(ExecState* exec)
+JSValue JSAudioContext::close(ExecState* state)
{
- JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
- DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
- auto successCallback = [wrapper]() mutable {
- wrapper.resolve(nullptr);
- };
- auto failureCallback = [wrapper](ExceptionCode value) mutable {
- wrapper.reject(value);
- };
+ JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(state, globalObject());
- impl().closeContext(WTF::move(successCallback), WTF::move(failureCallback));
+ impl().close(DeferredWrapper(state, globalObject(), promiseDeferred));
return promiseDeferred->promise();
}
Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.cpp (185406 => 185407)
--- trunk/Source/WebCore/bindings/js/JSDOMPromise.cpp 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.cpp 2015-06-10 08:10:44 UTC (rev 185407)
@@ -28,6 +28,8 @@
#if ENABLE(PROMISES)
+#include "ExceptionCode.h"
+
using namespace JSC;
namespace WebCore {
@@ -45,40 +47,21 @@
return m_deferred->promise();
}
-void DeferredWrapper::resolve(ExecState* exec, JSValue resolution)
+void DeferredWrapper::callFunction(ExecState& exec, JSValue function, JSValue resolution)
{
- JSValue deferredResolve = m_deferred->resolve();
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
- CallData resolveCallData;
- CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
- ASSERT(resolveCallType != CallTypeNone);
-
MarkedArgumentBuffer arguments;
arguments.append(resolution);
- call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
+ call(&exec, function, callType, callData, jsUndefined(), arguments);
m_globalObject.clear();
m_deferred.clear();
}
-void DeferredWrapper::reject(ExecState* exec, JSValue reason)
-{
- JSValue deferredReject = m_deferred->reject();
-
- CallData rejectCallData;
- CallType rejectCallType = getCallData(deferredReject, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(reason);
-
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
-
- m_globalObject.clear();
- m_deferred.clear();
}
-}
-
#endif // ENABLE(PROMISES)
Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.h (185406 => 185407)
--- trunk/Source/WebCore/bindings/js/JSDOMPromise.h 2015-06-10 08:09:02 UTC (rev 185406)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.h 2015-06-10 08:10:44 UTC (rev 185407)
@@ -49,13 +49,30 @@
JSC::JSObject* promise() const;
private:
- void resolve(JSC::ExecState*, JSC::JSValue);
- void reject(JSC::ExecState*, JSC::JSValue);
+ void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution);
+ void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->resolve(), resolution); }
+ void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->reject(), resolution); }
JSC::Strong<JSDOMGlobalObject> m_globalObject;
JSC::Strong<JSC::JSPromiseDeferred> m_deferred;
};
+template <typename Value, typename Error>
+class DOMPromise {
+public:
+ DOMPromise(DeferredWrapper&& wrapper) : m_wrapper(WTF::move(wrapper)) { }
+ DOMPromise(DOMPromise&& promise) : m_wrapper(WTF::move(promise.m_wrapper)) { }
+
+ DOMPromise(const DOMPromise&)= delete;
+ DOMPromise& operator=(DOMPromise const&) = delete;
+
+ void resolve(const Value& value) { m_wrapper.resolve<Value>(value); }
+ void reject(const Error& error) { m_wrapper.reject<Error>(error); }
+
+private:
+ DeferredWrapper m_wrapper;
+};
+
template<class ResolveResultType>
inline void DeferredWrapper::resolve(const ResolveResultType& result)
{
@@ -63,7 +80,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- resolve(exec, toJS(exec, m_globalObject.get(), result));
+ resolve(*exec, toJS(exec, m_globalObject.get(), result));
}
template<class RejectResultType>
@@ -73,7 +90,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- reject(exec, toJS(exec, m_globalObject.get(), result));
+ reject(*exec, toJS(exec, m_globalObject.get(), result));
}
template<>
@@ -83,7 +100,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- reject(exec, JSC::jsNull());
+ reject(*exec, JSC::jsNull());
}
template<>
@@ -93,7 +110,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- reject(exec, value);
+ reject(*exec, value);
}
template<>
@@ -103,7 +120,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- reject(exec, createDOMException(exec, ec));
+ reject(*exec, createDOMException(exec, ec));
}
template<>
@@ -113,7 +130,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- resolve(exec, jsString(exec, result));
+ resolve(*exec, jsString(exec, result));
}
template<>
@@ -123,7 +140,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- resolve(exec, JSC::jsBoolean(result));
+ resolve(*exec, JSC::jsBoolean(result));
}
template<>
@@ -133,7 +150,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- resolve(exec, value);
+ resolve(*exec, value);
}
template<>
inline void DeferredWrapper::resolve<Vector<unsigned char>>(const Vector<unsigned char>& result)
@@ -143,7 +160,7 @@
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(result.data(), result.size());
- resolve(exec, toJS(exec, m_globalObject.get(), buffer.get()));
+ resolve(*exec, toJS(exec, m_globalObject.get(), buffer.get()));
}
template<>
@@ -153,7 +170,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- resolve(exec, JSC::jsUndefined());
+ resolve(*exec, JSC::jsUndefined());
}
template<>
@@ -163,7 +180,7 @@
ASSERT(m_globalObject);
JSC::ExecState* exec = m_globalObject->globalExec();
JSC::JSLockHolder locker(exec);
- reject(exec, jsString(exec, result));
+ reject(*exec, jsString(exec, result));
}
}