Index: Source/core/dom/Future.cpp |
diff --git a/Source/core/dom/Future.cpp b/Source/core/dom/Future.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..109e84ed48b7cfccea95ea8d0e42beee58d6f442 |
--- /dev/null |
+++ b/Source/core/dom/Future.cpp |
@@ -0,0 +1,300 @@ |
+/* |
+ * Copyright (C) 2013 Google Inc. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+#include "config.h" |
+ |
+#include "core/dom/Future.h" |
+ |
+#include "bindings/v8/V8Utilities.h" |
+#include "core/dom/AnyCallback.h" |
+#include "core/platform/Logging.h" |
+ |
+namespace WebCore { |
+ |
+namespace { |
+ |
+class ProcessAcceptCallbacksTask : public ScriptExecutionContext::Task { |
+public: |
+ static PassOwnPtr<ProcessAcceptCallbacksTask> create(PassRefPtr<Future> future, const ScriptValue& value) |
+ { |
+ return adoptPtr(new ProcessAcceptCallbacksTask(future, value)); |
+ } |
+ |
+ virtual void performTask(ScriptExecutionContext*) OVERRIDE |
+ { |
+ LOG(Network, "ProcessAcceptCallbacksTask::performTask %d", m_future.get()->refCount()); |
+ m_future->processAcceptCallbacks(m_value); |
+ } |
+ |
+private: |
+ ProcessAcceptCallbacksTask(PassRefPtr<Future> future, const ScriptValue& value) |
+ : m_future(future) |
+ , m_value(value) |
+ { |
+ } |
+ |
+ RefPtr<Future> m_future; |
+ ScriptValue m_value; |
+}; |
+ |
+class ProcessRejectCallbacksTask : public ScriptExecutionContext::Task { |
+public: |
+ static PassOwnPtr<ProcessRejectCallbacksTask> create(PassRefPtr<Future> future, const ScriptValue& value) |
+ { |
+ return adoptPtr(new ProcessRejectCallbacksTask(future, value)); |
+ } |
+ |
+ virtual void performTask(ScriptExecutionContext*) OVERRIDE |
+ { |
+ LOG(Network, "ProcessRejectCallbacksTask::performTask %d", m_future.get()->refCount()); |
+ |
+ m_future->processRejectCallbacks(m_value); |
+ } |
+ |
+private: |
+ ProcessRejectCallbacksTask(PassRefPtr<Future> future, const ScriptValue& value) |
+ : m_future(future) |
+ , m_value(value) |
+ { |
+ } |
+ |
+ RefPtr<Future> m_future; |
+ ScriptValue m_value; |
+}; |
+ |
+} // namespace |
+ |
+PassRefPtr<Future> Future::create() |
+{ |
+ LOG(Network, "Future::create start"); |
+ |
+ ScriptExecutionContext* context = getScriptExecutionContext(); |
+ |
+ RefPtr<Future> future = adoptRef(new Future(context)); |
+ |
+ RefPtr<FutureResolver> resolver = FutureResolver::create(future); |
+ future->setResolver(resolver); |
+ |
+ return future; |
+} |
+ |
+PassRefPtr<Future> Future::createAndRunInit(PassRefPtr<FutureInit> init) |
+{ |
+ RefPtr<Future> future = Future::create(); |
+ |
+ LOG(Network, "Future::create call init start %d", future->refCount()); |
+ |
+ RefPtr<FutureResolver> resolver = future->getResolver(); |
+ |
+ ScriptExecutionContext* context = getScriptExecutionContext(); |
+ |
+ // Pass future as this as specified in the spec. |
+ ScriptValue result = init->call(resolver, future, context); |
+ if (!result.hasNoValue()) |
+ resolver->rejectInternal(result, false); |
+ |
+ LOG(Network, "Future::create call init done"); |
+ |
+ return future; |
+} |
+ |
+Future::Future(ScriptExecutionContext* context) |
+ : ActiveDOMObject(context) |
+ , m_state(Pending) |
+{ |
+ LOG(Network, "Future::Future start %d", refCount()); |
+ |
+ suspendIfNeeded(); |
+} |
+ |
+Future::~Future() |
+{ |
+ LOG(Network, "Future dtor"); |
+} |
+ |
+PassRefPtr<Future> Future::accept(const ScriptValue& value) |
+{ |
+ RefPtr<Future> future = Future::create(); |
+ future->getResolver()->accept(value); |
+ |
+ LOG(Network, "Future::accept end %d", future->refCount()); |
+ |
+ return future; |
+} |
+ |
+PassRefPtr<Future> Future::resolve(const ScriptValue& value) |
+{ |
+ return 0; |
+} |
+ |
+PassRefPtr<Future> Future::reject(const ScriptValue& value) |
+{ |
+ RefPtr<Future> future = Future::create(); |
+ future->getResolver()->reject(value); |
+ |
+ return future; |
+} |
+ |
+PassRefPtr<Future> Future::anyof(Vector<ScriptValue>& values) |
+{ |
+ return 0; |
+} |
+ |
+PassRefPtr<Future> Future::every(Vector<ScriptValue>& values) |
+{ |
+ return 0; |
+} |
+ |
+PassRefPtr<Future> Future::some(Vector<ScriptValue>& values) |
+{ |
+ return 0; |
+} |
+ |
+void Future::FutureCallback::invoke(const ScriptValue& value) |
+{ |
+ LOG(Network, "invoke %d", m_algorithm); |
+ |
+ bool exceptionThrown = false; |
+ switch (m_algorithm) { |
+ case NoAlgorithm: |
+ m_callback->call(value, 0, &exceptionThrown); |
+ break; |
+ case WrapperAlgorithm: |
+ ASSERT(m_callback); |
+ { |
+ ScriptValue result = m_callback->call(value, m_resolver->getFuture(), &exceptionThrown); |
+ if (exceptionThrown) |
+ m_resolver->rejectInternal(result, true); |
+ // FIXME |
+ // else |
+ // m_resolver->resolveInternal(result, true); |
+ else |
+ m_resolver->acceptInternal(result, true); |
+ } |
+ break; |
+ case AcceptAlgorithm: |
+ m_resolver->acceptInternal(value, true); |
+ break; |
+ case ResolveAlgorithm: |
+ // FIXME |
+ // m_resolver->resolveInternal(value, true); |
+ break; |
+ case RejectAlgorithm: |
+ m_resolver->rejectInternal(value, true); |
+ break; |
+ } |
+} |
+ |
+void Future::appendCallbacks(PassRefPtr<FutureCallback> acceptCallback, PassRefPtr<FutureCallback> rejectCallback) |
+{ |
+ m_acceptCallbacks.append(acceptCallback); |
+ |
+ m_rejectCallbacks.append(rejectCallback); |
+ |
+ if (m_state == Accepted) |
+ queueProcessAcceptCallbacksTask(m_result); |
+ |
+ if (m_state == Rejected) |
+ queueProcessRejectCallbacksTask(m_result); |
+} |
+ |
+PassRefPtr<Future> Future::then(PassRefPtr<AnyCallback> acceptCallback, PassRefPtr<AnyCallback> rejectCallback) |
+{ |
+ RefPtr<Future> newFuture = Future::create(); |
+ |
+ RefPtr<FutureResolver> newResolver = newFuture->getResolver(); |
+ |
+ FutureCallback::Algorithm algorithmForAccept = FutureCallback::AcceptAlgorithm; |
+ if (acceptCallback) |
+ algorithmForAccept = FutureCallback::WrapperAlgorithm; |
+ RefPtr<FutureCallback> acceptFutureCallback = FutureCallback::create(algorithmForAccept, newResolver, acceptCallback); |
+ |
+ FutureCallback::Algorithm algorithmForReject = FutureCallback::RejectAlgorithm; |
+ if (rejectCallback) |
+ algorithmForReject = FutureCallback::WrapperAlgorithm; |
+ RefPtr<FutureCallback> rejectFutureCallback = FutureCallback::create(algorithmForReject, newResolver, rejectCallback); |
+ |
+ appendCallbacks(acceptFutureCallback, rejectFutureCallback); |
+ |
+ return newFuture; |
+} |
+ |
+void Future::then(PassRefPtr<Future> future) |
+{ |
+ ScriptExecutionContext* context = getScriptExecutionContext(); |
+ |
+ RefPtr<FutureResolver> resolver = future->getResolver(); |
+ |
+ FutureCallback::Algorithm algorithmForAccept = FutureCallback::AcceptAlgorithm; |
+ RefPtr<FutureCallback> acceptFutureCallback = FutureCallback::create(algorithmForAccept, resolver, 0); |
+ |
+ FutureCallback::Algorithm algorithmForReject = FutureCallback::RejectAlgorithm; |
+ RefPtr<FutureCallback> rejectFutureCallback = FutureCallback::create(algorithmForReject, resolver, 0); |
+ |
+ appendCallbacks(acceptFutureCallback, rejectFutureCallback); |
+} |
+ |
+void Future::done(PassRefPtr<AnyCallback> acceptCallback, PassRefPtr<AnyCallback> rejectCallback) |
+{ |
+ RefPtr<FutureCallback> acceptFutureCallback = FutureCallback::create(FutureCallback::NoAlgorithm, 0, acceptCallback); |
+ RefPtr<FutureCallback> rejectFutureCallback = FutureCallback::create(FutureCallback::NoAlgorithm, 0, rejectCallback); |
+ appendCallbacks(acceptFutureCallback, rejectFutureCallback); |
+} |
+ |
+void Future::processAcceptCallbacks(const ScriptValue& value) |
+{ |
+ LOG(Network, "processAcceptCallbacks %d", refCount()); |
+ |
+ for (int i = 0; i < m_acceptCallbacks.size(); ++i) |
+ m_acceptCallbacks[i]->invoke(value); |
+ |
+ m_acceptCallbacks.clear(); |
+} |
+ |
+void Future::queueProcessAcceptCallbacksTask(const ScriptValue& value) |
+{ |
+ getScriptExecutionContext()->postTask(ProcessAcceptCallbacksTask::create(this, value)); |
+} |
+ |
+void Future::processRejectCallbacks(const ScriptValue& value) |
+{ |
+ LOG(Network, "processRejectCallbacks"); |
+ |
+ for (int i = 0; i < m_rejectCallbacks.size(); ++i) |
+ m_rejectCallbacks[i]->invoke(value); |
+ m_rejectCallbacks.clear(); |
+} |
+ |
+void Future::queueProcessRejectCallbacksTask(const ScriptValue& value) |
+{ |
+ getScriptExecutionContext()->postTask(ProcessRejectCallbacksTask::create(this, value)); |
+} |
+ |
+} // namespace WebCore |