05228f7958c2e79067b75f6dd3cb376f41991dc7
[WebKit-https.git] / Source / WebCore / bindings / js / ReadableStreamJSSource.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 "ReadableStreamJSSource.h"
32
33 #if ENABLE(STREAMS_API)
34
35 #include "DOMWrapperWorld.h"
36 #include "JSDOMPromise.h"
37 #include "JSReadableStream.h"
38 #include "NotImplemented.h"
39 #include "ScriptExecutionContext.h"
40 #include <runtime/Error.h>
41 #include <runtime/JSCJSValueInlines.h>
42 #include <runtime/JSString.h>
43 #include <runtime/StructureInlines.h>
44
45 using namespace JSC;
46
47 namespace WebCore {
48
49 void setInternalSlotToObject(ExecState* exec, JSValue objectValue, PrivateName& name, JSValue value)
50 {
51     JSObject* object = objectValue.toObject(exec);
52     PutPropertySlot propertySlot(objectValue);
53     object->put(object, exec, Identifier::fromUid(name), value, propertySlot);
54 }
55
56 JSValue getInternalSlotFromObject(ExecState* exec, JSValue objectValue, PrivateName& name)
57 {
58     JSObject* object = objectValue.toObject(exec);
59     PropertySlot propertySlot(objectValue);
60
61     Identifier propertyName = Identifier::fromUid(name);
62     if (!object->getOwnPropertySlot(object, exec, propertyName, propertySlot))
63         return JSValue();
64     return propertySlot.getValue(exec, propertyName);
65 }
66
67 static inline JSValue getPropertyFromObject(ExecState* exec, JSObject* object, const char* identifier)
68 {
69     return object->get(exec, Identifier::fromString(exec, identifier));
70 }
71
72 static inline JSValue callFunction(ExecState* exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments, JSValue* exception)
73 {
74     CallData callData;
75     CallType callType = getCallData(jsFunction, callData);
76     return call(exec, jsFunction, callType, callData, thisValue, arguments, exception);
77 }
78
79 Ref<ReadableStreamJSSource> ReadableStreamJSSource::create(JSC::ExecState* exec)
80 {
81     return adoptRef(*new ReadableStreamJSSource(exec));
82 }
83
84 ReadableStreamJSSource::ReadableStreamJSSource(JSC::ExecState* exec)
85 {
86     ASSERT_WITH_MESSAGE(!exec->argumentCount() || exec->argument(0).isObject(), "Caller of ReadableStreamJSSource constructor should ensure that passed argument if any is an object.");
87     JSObject* source =  exec->argumentCount() ? exec->argument(0).getObject() : JSFinalObject::create(exec->vm(), JSFinalObject::createStructure(exec->vm(), exec->callee()->globalObject(), jsNull(), 1));
88     m_source.set(exec->vm(), source);
89 }
90
91 ReadableStreamJSSource::~ReadableStreamJSSource()
92 {
93     if (m_controller)
94         m_controller.get()->impl().resetStream();
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 ReadableStreamJSSource::start(JSC::ExecState* exec, JSReadableStream* readableStream)
106 {
107     JSLockHolder lock(exec);
108
109     Ref<ReadableStreamController> controller = ReadableStreamController::create(static_cast<ReadableJSStream&>(readableStream->impl()));
110     m_controller.set(exec->vm(), jsDynamicCast<JSReadableStreamController*>(toJS(exec, readableStream->globalObject(), controller)));
111
112     JSValue startFunction = getPropertyFromObject(exec, m_source.get(), "start");
113     if (!startFunction.isFunction()) {
114         if (!startFunction.isUndefined())
115             throwVMError(exec, createTypeError(exec, ASCIILiteral("ReadableStream constructor object start property should be a function.")));
116         else
117             startReadableStreamAsync(readableStream->impl());
118         return;
119     }
120
121     MarkedArgumentBuffer arguments;
122     arguments.append(m_controller.get());
123
124     JSValue exception;
125     callFunction(exec, startFunction, m_source.get(), arguments, &exception);
126
127     if (exception) {
128         throwVMError(exec, exception);
129         return;
130     }
131
132     // FIXME: Implement handling promise as result of calling start function.
133     startReadableStreamAsync(readableStream->impl());
134 }
135
136 Ref<ReadableJSStream> ReadableJSStream::create(ScriptExecutionContext& scriptExecutionContext, Ref<ReadableStreamJSSource>&& source)
137 {
138     auto readableStream = adoptRef(*new ReadableJSStream(scriptExecutionContext, WTF::move(source)));
139     return readableStream;
140 }
141
142 Ref<ReadableStreamReader> ReadableJSStream::createReader()
143 {
144     RefPtr<ReadableStreamReader> reader = ReadableJSStreamReader::create(*this);
145     return reader.releaseNonNull();
146 }
147
148 ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, Ref<ReadableStreamJSSource>&& source)
149     : ReadableStream(scriptExecutionContext, WTF::move(source))
150 {
151 }
152
153 Ref<ReadableJSStreamReader> ReadableJSStreamReader::create(ReadableJSStream& stream)
154 {
155     auto readableStreamReader = adoptRef(*new ReadableJSStreamReader(stream));
156     return readableStreamReader;
157 }
158
159 ReadableJSStreamReader::ReadableJSStreamReader(ReadableJSStream& readableStream)
160     : ReadableStreamReader(readableStream)
161 {
162 }
163
164 } // namespace WebCore
165
166 #endif