2 * Copyright (C) 2015 Canon Inc.
3 * Copyright (C) 2015 Igalia S.L.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted, provided that the following conditions
7 * are required to be met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Canon Inc. nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "ReadableJSStream.h"
33 #if ENABLE(STREAMS_API)
35 #include "DOMWrapperWorld.h"
36 #include "JSDOMPromise.h"
37 #include "JSReadableStream.h"
38 #include "JSReadableStreamController.h"
39 #include "NotImplemented.h"
40 #include "ScriptExecutionContext.h"
41 #include <runtime/Error.h>
42 #include <runtime/JSCJSValueInlines.h>
43 #include <runtime/JSString.h>
44 #include <runtime/StructureInlines.h>
50 static inline JSValue getPropertyFromObject(ExecState& exec, JSObject* object, const char* identifier)
52 return object->get(&exec, Identifier::fromString(&exec, identifier));
55 static inline JSValue callFunction(ExecState& exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments)
58 CallType callType = getCallData(jsFunction, callData);
59 return call(&exec, jsFunction, callType, callData, thisValue, arguments);
62 JSValue ReadableJSStream::invoke(ExecState& exec, const char* propertyName)
64 JSValue function = getPropertyFromObject(exec, m_source.get(), propertyName);
65 if (exec.hadException())
68 if (!function.isFunction()) {
69 if (!function.isUndefined())
70 throwVMError(&exec, createTypeError(&exec, ASCIILiteral("ReadableStream trying to call a property that is not callable")));
74 MarkedArgumentBuffer arguments;
75 arguments.append(jsController(exec, globalObject()));
76 return callFunction(exec, function, m_source.get(), arguments);
79 JSDOMGlobalObject* ReadableJSStream::globalObject()
81 return jsDynamicCast<JSDOMGlobalObject*>(m_source->globalObject());
84 static void startReadableStreamAsync(ReadableStream& readableStream)
86 RefPtr<ReadableStream> stream = &readableStream;
87 stream->scriptExecutionContext()->postTask([stream](ScriptExecutionContext&) {
92 void ReadableJSStream::doStart(ExecState& exec)
94 JSLockHolder lock(&exec);
96 invoke(exec, "start");
98 if (exec.hadException())
101 // FIXME: Implement handling promise as result of calling start function.
102 startReadableStreamAsync(*this);
105 RefPtr<ReadableJSStream> ReadableJSStream::create(ExecState& exec, ScriptExecutionContext& scriptExecutionContext)
108 JSValue value = exec.argument(0);
109 if (value.isObject())
110 jsSource = value.getObject();
111 else if (!value.isUndefined()) {
112 throwVMError(&exec, createTypeError(&exec, ASCIILiteral("ReadableStream constructor first argument, if any, should be an object")));
115 jsSource = JSFinalObject::create(exec.vm(), JSFinalObject::createStructure(exec.vm(), exec.callee()->globalObject(), jsNull(), 1));
117 RefPtr<ReadableJSStream> readableStream = adoptRef(*new ReadableJSStream(scriptExecutionContext, exec, jsSource));
118 readableStream->doStart(exec);
120 if (exec.hadException())
123 return readableStream;
126 ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, ExecState& exec, JSObject* source)
127 : ReadableStream(scriptExecutionContext)
129 m_source.set(exec.vm(), source);
132 JSValue ReadableJSStream::jsController(ExecState& exec, JSDOMGlobalObject* globalObject)
135 m_controller = std::make_unique<ReadableStreamController>(*this);
136 return toJS(&exec, globalObject, m_controller.get());
139 void ReadableJSStream::storeError(JSC::ExecState& exec)
143 JSValue error = exec.argumentCount() ? exec.argument(0) : createError(&exec, ASCIILiteral("Error function called."));
144 m_error.set(exec.vm(), error);
146 changeStateToErrored();
149 bool ReadableJSStream::hasValue() const
151 return m_chunkQueue.size();
154 JSValue ReadableJSStream::read()
158 return m_chunkQueue.takeFirst().get();
161 void ReadableJSStream::enqueue(ExecState& exec)
163 ASSERT(!isCloseRequested());
168 JSValue chunk = exec.argumentCount() ? exec.argument(0) : jsUndefined();
169 if (resolveReadCallback(chunk))
172 m_chunkQueue.append(JSC::Strong<JSC::Unknown>(exec.vm(), chunk));
173 // FIXME: Compute chunk size.
174 // FIXME: Add pulling of data here and also when data is passed to resolve callback.
177 } // namespace WebCore