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 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TransformStreamDefaultController
, mGlobal
,
21 mStream
, mTransformerAlgorithms
)
22 NS_IMPL_CYCLE_COLLECTING_ADDREF(TransformStreamDefaultController
)
23 NS_IMPL_CYCLE_COLLECTING_RELEASE(TransformStreamDefaultController
)
24 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStreamDefaultController
)
25 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
26 NS_INTERFACE_MAP_ENTRY(nsISupports
)
29 TransformStream
* TransformStreamDefaultController::Stream() { return mStream
; }
31 void TransformStreamDefaultController::SetStream(TransformStream
& aStream
) {
36 TransformerAlgorithms
* TransformStreamDefaultController::Algorithms() {
37 return mTransformerAlgorithms
;
40 void TransformStreamDefaultController::SetAlgorithms(
41 TransformerAlgorithms
* aTransformerAlgorithms
) {
42 mTransformerAlgorithms
= aTransformerAlgorithms
;
45 TransformStreamDefaultController::TransformStreamDefaultController(
46 nsIGlobalObject
* aGlobal
)
48 mozilla::HoldJSObjects(this);
51 TransformStreamDefaultController::~TransformStreamDefaultController() {
52 mozilla::DropJSObjects(this);
55 JSObject
* TransformStreamDefaultController::WrapObject(
56 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
57 return TransformStreamDefaultController_Binding::Wrap(aCx
, this, aGivenProto
);
60 // https://streams.spec.whatwg.org/#ts-default-controller-desired-size
61 Nullable
<double> TransformStreamDefaultController::GetDesiredSize() const {
62 // Step 1. Let readableController be
63 // this.[[stream]].[[readable]].[[controller]].
64 RefPtr
<ReadableStreamDefaultController
> readableController
=
65 mStream
->Readable()->Controller()->AsDefault();
68 // ReadableStreamDefaultControllerGetDesiredSize(readableController).
69 return ReadableStreamDefaultControllerGetDesiredSize(readableController
);
72 // https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure
73 // Looks like a readable stream thing but the spec explicitly says this is for
75 static bool ReadableStreamDefaultControllerHasBackpressure(
76 ReadableStreamDefaultController
* aController
) {
77 // Step 1: If ! ReadableStreamDefaultControllerShouldCallPull(controller) is
78 // true, return false.
79 // Step 2: Otherwise, return true.
80 return !ReadableStreamDefaultControllerShouldCallPull(aController
);
83 void TransformStreamDefaultController::Enqueue(JSContext
* aCx
,
84 JS::Handle
<JS::Value
> aChunk
,
86 // Step 1: Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
88 // Inlining TransformStreamDefaultControllerEnqueue here.
89 // https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue
91 // Step 1: Let stream be controller.[[stream]].
92 RefPtr
<TransformStream
> stream
= mStream
;
94 // Step 2: Let readableController be stream.[[readable]].[[controller]].
95 RefPtr
<ReadableStreamDefaultController
> readableController
=
96 stream
->Readable()->Controller()->AsDefault();
99 // ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
100 // false, throw a TypeError exception.
101 if (!ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow(
102 readableController
, CloseOrEnqueue::Enqueue
, aRv
)) {
106 // Step 4: Let enqueueResult be
107 // ReadableStreamDefaultControllerEnqueue(readableController, chunk).
109 ReadableStreamDefaultControllerEnqueue(aCx
, readableController
, aChunk
, rv
);
111 // Step 5: If enqueueResult is an abrupt completion,
112 if (rv
.MaybeSetPendingException(aCx
)) {
113 JS::Rooted
<JS::Value
> error(aCx
);
114 if (!JS_GetPendingException(aCx
, &error
)) {
115 // Uncatchable exception; we should mark aRv and return.
116 aRv
.StealExceptionFromJSContext(aCx
);
119 JS_ClearPendingException(aCx
);
121 // Step 5.1: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
122 // enqueueResult.[[Value]]).
123 TransformStreamErrorWritableAndUnblockWrite(aCx
, stream
, error
, aRv
);
125 // Step 5.2: Throw stream.[[readable]].[[storedError]].
126 JS::Rooted
<JS::Value
> storedError(aCx
, stream
->Readable()->StoredError());
127 aRv
.MightThrowJSException();
128 aRv
.ThrowJSException(aCx
, storedError
);
132 // Step 6: Let backpressure be !
133 // ReadableStreamDefaultControllerHasBackpressure(readableController).
135 ReadableStreamDefaultControllerHasBackpressure(readableController
);
137 // Step 7: If backpressure is not stream.[[backpressure]],
138 if (backpressure
!= stream
->Backpressure()) {
139 // Step 7.1: Assert: backpressure is true.
140 MOZ_ASSERT(backpressure
);
142 // Step 7.2: Perform ! TransformStreamSetBackpressure(stream, true).
143 TransformStreamSetBackpressure(stream
, true, aRv
);
147 // https://streams.spec.whatwg.org/#ts-default-controller-error
148 void TransformStreamDefaultController::Error(JSContext
* aCx
,
149 JS::Handle
<JS::Value
> aError
,
151 // Step 1: Perform ? TransformStreamDefaultControllerError(this, e).
153 // Inlining TransformStreamDefaultControllerError here.
154 // https://streams.spec.whatwg.org/#transform-stream-default-controller-error
156 // Perform ! TransformStreamError(controller.[[stream]], e).
157 TransformStreamError(aCx
, mStream
, aError
, aRv
);
160 // https://streams.spec.whatwg.org/#ts-default-controller-terminate
162 void TransformStreamDefaultController::Terminate(JSContext
* aCx
,
164 // Step 1: Perform ? TransformStreamDefaultControllerTerminate(this).
166 // Inlining TransformStreamDefaultControllerTerminate here.
167 // https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate
169 // Step 1: Let stream be controller.[[stream]].
170 RefPtr
<TransformStream
> stream
= mStream
;
172 // Step 2: Let readableController be stream.[[readable]].[[controller]].
173 RefPtr
<ReadableStreamDefaultController
> readableController
=
174 stream
->Readable()->Controller()->AsDefault();
176 // Step 3: Perform ! ReadableStreamDefaultControllerClose(readableController).
177 ReadableStreamDefaultControllerClose(aCx
, readableController
, aRv
);
179 // Step 4: Let error be a TypeError exception indicating that the stream has
182 rv
.ThrowTypeError("Terminating the stream");
183 JS::Rooted
<JS::Value
> error(aCx
);
184 MOZ_ALWAYS_TRUE(ToJSValue(aCx
, std::move(rv
), &error
));
186 // Step 5: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
188 TransformStreamErrorWritableAndUnblockWrite(aCx
, stream
, error
, aRv
);
191 // https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller
192 void SetUpTransformStreamDefaultController(
193 JSContext
* aCx
, TransformStream
& aStream
,
194 TransformStreamDefaultController
& aController
,
195 TransformerAlgorithms
& aTransformerAlgorithms
) {
196 // Step 1. Assert: stream implements TransformStream.
197 // Step 2. Assert: stream.[[controller]] is undefined.
198 MOZ_ASSERT(!aStream
.Controller());
200 // Step 3. Set controller.[[stream]] to stream.
201 aController
.SetStream(aStream
);
203 // Step 4. Set stream.[[controller]] to controller.
204 aStream
.SetController(aController
);
206 // Step 5. Set controller.[[transformAlgorithm]] to transformAlgorithm.
207 // Step 6. Set controller.[[flushAlgorithm]] to flushAlgorithm.
208 aController
.SetAlgorithms(&aTransformerAlgorithms
);
211 // https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer
212 void SetUpTransformStreamDefaultControllerFromTransformer(
213 JSContext
* aCx
, TransformStream
& aStream
,
214 JS::Handle
<JSObject
*> aTransformer
, Transformer
& aTransformerDict
) {
215 // Step 1. Let controller be a new TransformStreamDefaultController.
217 MakeRefPtr
<TransformStreamDefaultController
>(aStream
.GetParentObject());
220 auto algorithms
= MakeRefPtr
<TransformerAlgorithms
>(
221 aStream
.GetParentObject(), aTransformer
, aTransformerDict
);
223 // Step 6: Perform ! SetUpTransformStreamDefaultController(stream, controller,
224 // transformAlgorithm, flushAlgorithm).
225 SetUpTransformStreamDefaultController(aCx
, aStream
, *controller
, *algorithms
);
228 } // namespace mozilla::dom