f067d169395f4b6fd8cc89a3de68bf1de89d2e61
[WebKit-https.git] / Source / WebCore / bindings / js / ReadableJSStream.cpp
1 /*
2  * Copyright (C) 2015 Canon Inc.
3  * Copyright (C) 2015 Igalia S.L.
4  *
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:
8  *
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.
17  *
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.
28  */
29
30 #include "config.h"
31 #include "ReadableJSStream.h"
32
33 #if ENABLE(STREAMS_API)
34
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>
45
46 using namespace JSC;
47
48 namespace WebCore {
49
50 void setInternalSlotToObject(ExecState* exec, JSValue objectValue, PrivateName& name, JSValue value)
51 {
52     JSObject* object = objectValue.toObject(exec);
53     PutPropertySlot propertySlot(objectValue);
54     object->put(object, exec, Identifier::fromUid(name), value, propertySlot);
55 }
56
57 JSValue getInternalSlotFromObject(ExecState* exec, JSValue objectValue, PrivateName& name)
58 {
59     JSObject* object = objectValue.toObject(exec);
60     PropertySlot propertySlot(objectValue);
61
62     Identifier propertyName = Identifier::fromUid(name);
63     if (!object->getOwnPropertySlot(object, exec, propertyName, propertySlot))
64         return JSValue();
65     return propertySlot.getValue(exec, propertyName);
66 }
67
68 static inline JSValue getPropertyFromObject(ExecState* exec, JSObject* object, const char* identifier)
69 {
70     return object->get(exec, Identifier::fromString(exec, identifier));
71 }
72
73 static inline JSValue callFunction(ExecState* exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments, JSValue* exception)
74 {
75     CallData callData;
76     CallType callType = getCallData(jsFunction, callData);
77     return call(exec, jsFunction, callType, callData, thisValue, arguments, exception);
78 }
79
80 Ref<ReadableJSStream::Source> ReadableJSStream::Source::create(ExecState& exec)
81 {
82     return adoptRef(*new Source(exec));
83 }
84
85 ReadableJSStream::Source::Source(ExecState& exec)
86 {
87     ASSERT_WITH_MESSAGE(!exec.argumentCount() || exec.argument(0).isObject(), "Caller of ReadableJSStream::Source constructor should ensure that passed argument if any is an object.");
88     JSObject* source =  exec.argumentCount() ? exec.argument(0).getObject() : JSFinalObject::create(exec.vm(), JSFinalObject::createStructure(exec.vm(), exec.callee()->globalObject(), jsNull(), 1));
89     m_source.set(exec.vm(), source);
90 }
91
92 JSDOMGlobalObject* ReadableJSStream::Source::globalObject()
93 {
94     return jsDynamicCast<JSDOMGlobalObject*>(m_source->globalObject());
95 }
96
97 static void startReadableStreamAsync(ReadableStream& readableStream)
98 {
99     RefPtr<ReadableStream> stream = &readableStream;
100     stream->scriptExecutionContext()->postTask([stream](ScriptExecutionContext&) {
101         stream->start();
102     });
103 }
104
105 void ReadableJSStream::Source::start(ExecState& exec, ReadableJSStream& readableStream)
106 {
107     JSLockHolder lock(&exec);
108
109     JSValue startFunction = getPropertyFromObject(&exec, m_source.get(), "start");
110     if (!startFunction.isFunction()) {
111         if (!startFunction.isUndefined())
112             throwVMError(&exec, createTypeError(&exec, ASCIILiteral("ReadableStream constructor object start property should be a function.")));
113         else
114             startReadableStreamAsync(readableStream);
115         return;
116     }
117
118     MarkedArgumentBuffer arguments;
119     arguments.append(readableStream.jsController(exec, globalObject()));
120
121     JSValue exception;
122     callFunction(&exec, startFunction, m_source.get(), arguments, &exception);
123
124     if (exception) {
125         throwVMError(&exec, exception);
126         return;
127     }
128
129     // FIXME: Implement handling promise as result of calling start function.
130     startReadableStreamAsync(readableStream);
131 }
132
133 Ref<ReadableJSStream> ReadableJSStream::create(ExecState& exec, ScriptExecutionContext& scriptExecutionContext)
134 {
135     Ref<ReadableJSStream::Source> source = ReadableJSStream::Source::create(exec);
136     Ref<ReadableJSStream> readableStream = adoptRef(*new ReadableJSStream(scriptExecutionContext, WTF::move(source)));
137
138     static_cast<ReadableJSStream::Source&>(readableStream->source()).start(exec, readableStream.get());
139     return readableStream;
140 }
141
142 Ref<ReadableStreamReader> ReadableJSStream::createReader()
143 {
144     return Reader::create(*this);
145 }
146
147 ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, Ref<ReadableJSStream::Source>&& source)
148     : ReadableStream(scriptExecutionContext, WTF::move(source))
149 {
150 }
151
152 ReadableJSStream::Source& ReadableJSStream::jsSource()
153 {
154     return static_cast<ReadableJSStream::Source&>(source());
155 }
156
157 JSValue ReadableJSStream::jsController(ExecState& exec, JSDOMGlobalObject* globalObject)
158 {
159     if (!m_controller)
160         m_controller = std::make_unique<ReadableStreamController>(*this);
161     return toJS(&exec, globalObject, m_controller.get());
162 }
163
164 Ref<ReadableJSStream::Reader> ReadableJSStream::Reader::create(ReadableJSStream& stream)
165 {
166     return adoptRef(*new Reader(stream));
167 }
168
169 ReadableJSStream::Reader::Reader(ReadableJSStream& readableStream)
170     : ReadableStreamReader(readableStream)
171 {
172 }
173
174 } // namespace WebCore
175
176 #endif