1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/TransformStreamDefaultController.h"
9 #include "TransformerCallbackHelpers.h"
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/Promise.h"
12 #include "mozilla/dom/ReadableStream.h"
13 #include "mozilla/dom/ReadableStreamDefaultController.h"
14 #include "mozilla/dom/TransformStream.h"
15 #include "mozilla/dom/TransformStreamDefaultControllerBinding.h"
16 #include "nsWrapperCache.h"
18 namespace mozilla::dom
{
20 using namespace streams_abstract
;
22 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TransformStreamDefaultController
, mGlobal
,
23 mStream
, mTransformerAlgorithms
)
24 NS_IMPL_CYCLE_COLLECTING_ADDREF(TransformStreamDefaultController
)
25 NS_IMPL_CYCLE_COLLECTING_RELEASE(TransformStreamDefaultController
)
26 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStreamDefaultController
)
27 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
28 NS_INTERFACE_MAP_ENTRY(nsISupports
)
31 TransformStream
* TransformStreamDefaultController::Stream() { return mStream
; }
33 void TransformStreamDefaultController::SetStream(TransformStream
& aStream
) {
38 TransformerAlgorithmsBase
* TransformStreamDefaultController::Algorithms() {
39 return mTransformerAlgorithms
;
42 void TransformStreamDefaultController::SetAlgorithms(
43 TransformerAlgorithmsBase
* aTransformerAlgorithms
) {
44 mTransformerAlgorithms
= aTransformerAlgorithms
;
47 TransformStreamDefaultController::TransformStreamDefaultController(
48 nsIGlobalObject
* aGlobal
)
50 mozilla::HoldJSObjects(this);
53 TransformStreamDefaultController::~TransformStreamDefaultController() {
54 mozilla::DropJSObjects(this);
57 JSObject
* TransformStreamDefaultController::WrapObject(
58 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
59 return TransformStreamDefaultController_Binding::Wrap(aCx
, this, aGivenProto
);
62 // https://streams.spec.whatwg.org/#ts-default-controller-desired-size
63 Nullable
<double> TransformStreamDefaultController::GetDesiredSize() const {
64 // Step 1. Let readableController be
65 // this.[[stream]].[[readable]].[[controller]].
66 RefPtr
<ReadableStreamDefaultController
> readableController
=
67 mStream
->Readable()->Controller()->AsDefault();
70 // ReadableStreamDefaultControllerGetDesiredSize(readableController).
71 return ReadableStreamDefaultControllerGetDesiredSize(readableController
);
74 // https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure
75 // Looks like a readable stream thing but the spec explicitly says this is for
77 static bool ReadableStreamDefaultControllerHasBackpressure(
78 ReadableStreamDefaultController
* aController
) {
79 // Step 1: If ! ReadableStreamDefaultControllerShouldCallPull(controller) is
80 // true, return false.
81 // Step 2: Otherwise, return true.
82 return !ReadableStreamDefaultControllerShouldCallPull(aController
);
85 void TransformStreamDefaultController::Enqueue(JSContext
* aCx
,
86 JS::Handle
<JS::Value
> aChunk
,
88 // Step 1: Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
90 // Inlining TransformStreamDefaultControllerEnqueue here.
91 // https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue
93 // Step 1: Let stream be controller.[[stream]].
94 RefPtr
<TransformStream
> stream
= mStream
;
96 // Step 2: Let readableController be stream.[[readable]].[[controller]].
97 RefPtr
<ReadableStreamDefaultController
> readableController
=
98 stream
->Readable()->Controller()->AsDefault();
101 // ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
102 // false, throw a TypeError exception.
103 if (!ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow(
104 readableController
, CloseOrEnqueue::Enqueue
, aRv
)) {
108 // Step 4: Let enqueueResult be
109 // ReadableStreamDefaultControllerEnqueue(readableController, chunk).
111 ReadableStreamDefaultControllerEnqueue(aCx
, readableController
, aChunk
, rv
);
113 // Step 5: If enqueueResult is an abrupt completion,
114 if (rv
.MaybeSetPendingException(aCx
)) {
115 JS::Rooted
<JS::Value
> error(aCx
);
116 if (!JS_GetPendingException(aCx
, &error
)) {
117 // Uncatchable exception; we should mark aRv and return.
118 aRv
.StealExceptionFromJSContext(aCx
);
121 JS_ClearPendingException(aCx
);
123 // Step 5.1: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
124 // enqueueResult.[[Value]]).
125 TransformStreamErrorWritableAndUnblockWrite(aCx
, stream
, error
, aRv
);
127 // Step 5.2: Throw stream.[[readable]].[[storedError]].
128 JS::Rooted
<JS::Value
> storedError(aCx
, stream
->Readable()->StoredError());
129 aRv
.MightThrowJSException();
130 aRv
.ThrowJSException(aCx
, storedError
);
134 // Step 6: Let backpressure be !
135 // ReadableStreamDefaultControllerHasBackpressure(readableController).
137 ReadableStreamDefaultControllerHasBackpressure(readableController
);
139 // Step 7: If backpressure is not stream.[[backpressure]],
140 if (backpressure
!= stream
->Backpressure()) {
141 // Step 7.1: Assert: backpressure is true.
142 MOZ_ASSERT(backpressure
);
144 // Step 7.2: Perform ! TransformStreamSetBackpressure(true).
145 stream
->SetBackpressure(true);
149 // https://streams.spec.whatwg.org/#ts-default-controller-error
150 void TransformStreamDefaultController::Error(JSContext
* aCx
,
151 JS::Handle
<JS::Value
> aError
,
153 // Step 1: Perform ? TransformStreamDefaultControllerError(this, e).
155 // Inlining TransformStreamDefaultControllerError here.
156 // https://streams.spec.whatwg.org/#transform-stream-default-controller-error
158 // Perform ! TransformStreamError(controller.[[stream]], e).
159 // mStream is set in initialization step and only modified in cycle
161 // TODO: Move mStream initialization to a method/constructor and make it
162 // MOZ_KNOWN_LIVE again. (See bug 1769854)
163 TransformStreamError(aCx
, MOZ_KnownLive(mStream
), aError
, aRv
);
166 // https://streams.spec.whatwg.org/#ts-default-controller-terminate
168 void TransformStreamDefaultController::Terminate(JSContext
* aCx
,
170 // Step 1: Perform ? TransformStreamDefaultControllerTerminate(this).
172 // Inlining TransformStreamDefaultControllerTerminate here.
173 // https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate
175 // Step 1: Let stream be controller.[[stream]].
176 RefPtr
<TransformStream
> stream
= mStream
;
178 // Step 2: Let readableController be stream.[[readable]].[[controller]].
179 RefPtr
<ReadableStreamDefaultController
> readableController
=
180 stream
->Readable()->Controller()->AsDefault();
182 // Step 3: Perform ! ReadableStreamDefaultControllerClose(readableController).
183 ReadableStreamDefaultControllerClose(aCx
, readableController
, aRv
);
185 // Step 4: Let error be a TypeError exception indicating that the stream has
188 rv
.ThrowTypeError("Terminating the stream");
189 JS::Rooted
<JS::Value
> error(aCx
);
190 MOZ_ALWAYS_TRUE(ToJSValue(aCx
, std::move(rv
), &error
));
192 // Step 5: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
194 TransformStreamErrorWritableAndUnblockWrite(aCx
, stream
, error
, aRv
);
197 namespace streams_abstract
{
199 // https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller
200 void SetUpTransformStreamDefaultController(
201 JSContext
* aCx
, TransformStream
& aStream
,
202 TransformStreamDefaultController
& aController
,
203 TransformerAlgorithmsBase
& aTransformerAlgorithms
) {
204 // Step 1. Assert: stream implements TransformStream.
205 // Step 2. Assert: stream.[[controller]] is undefined.
206 MOZ_ASSERT(!aStream
.Controller());
208 // Step 3. Set controller.[[stream]] to stream.
209 aController
.SetStream(aStream
);
211 // Step 4. Set stream.[[controller]] to controller.
212 aStream
.SetController(aController
);
214 // Step 5. Set controller.[[transformAlgorithm]] to transformAlgorithm.
215 // Step 6. Set controller.[[flushAlgorithm]] to flushAlgorithm.
216 aController
.SetAlgorithms(&aTransformerAlgorithms
);
219 // https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer
220 void SetUpTransformStreamDefaultControllerFromTransformer(
221 JSContext
* aCx
, TransformStream
& aStream
,
222 JS::Handle
<JSObject
*> aTransformer
, Transformer
& aTransformerDict
) {
223 // Step 1. Let controller be a new TransformStreamDefaultController.
225 MakeRefPtr
<TransformStreamDefaultController
>(aStream
.GetParentObject());
228 auto algorithms
= MakeRefPtr
<TransformerAlgorithms
>(
229 aStream
.GetParentObject(), aTransformer
, aTransformerDict
);
231 // Step 6: Perform ! SetUpTransformStreamDefaultController(stream, controller,
232 // transformAlgorithm, flushAlgorithm).
233 SetUpTransformStreamDefaultController(aCx
, aStream
, *controller
, *algorithms
);
236 } // namespace streams_abstract
238 } // namespace mozilla::dom