summaryrefslogtreecommitdiffstats
path: root/dom/streams/TransformStreamDefaultController.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/streams/TransformStreamDefaultController.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/dom/streams/TransformStreamDefaultController.cpp b/dom/streams/TransformStreamDefaultController.cpp
new file mode 100644
index 0000000000..bbcb7f94f2
--- /dev/null
+++ b/dom/streams/TransformStreamDefaultController.cpp
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/TransformStreamDefaultController.h"
+
+#include "TransformerCallbackHelpers.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/ReadableStream.h"
+#include "mozilla/dom/ReadableStreamDefaultController.h"
+#include "mozilla/dom/TransformStream.h"
+#include "mozilla/dom/TransformStreamDefaultControllerBinding.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla::dom {
+
+using namespace streams_abstract;
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TransformStreamDefaultController, mGlobal,
+ mStream, mTransformerAlgorithms)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TransformStreamDefaultController)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TransformStreamDefaultController)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStreamDefaultController)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+TransformStream* TransformStreamDefaultController::Stream() { return mStream; }
+
+void TransformStreamDefaultController::SetStream(TransformStream& aStream) {
+ MOZ_ASSERT(!mStream);
+ mStream = &aStream;
+}
+
+TransformerAlgorithmsBase* TransformStreamDefaultController::Algorithms() {
+ return mTransformerAlgorithms;
+}
+
+void TransformStreamDefaultController::SetAlgorithms(
+ TransformerAlgorithmsBase* aTransformerAlgorithms) {
+ mTransformerAlgorithms = aTransformerAlgorithms;
+}
+
+TransformStreamDefaultController::TransformStreamDefaultController(
+ nsIGlobalObject* aGlobal)
+ : mGlobal(aGlobal) {
+ mozilla::HoldJSObjects(this);
+}
+
+TransformStreamDefaultController::~TransformStreamDefaultController() {
+ mozilla::DropJSObjects(this);
+}
+
+JSObject* TransformStreamDefaultController::WrapObject(
+ JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
+ return TransformStreamDefaultController_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+// https://streams.spec.whatwg.org/#ts-default-controller-desired-size
+Nullable<double> TransformStreamDefaultController::GetDesiredSize() const {
+ // Step 1. Let readableController be
+ // this.[[stream]].[[readable]].[[controller]].
+ RefPtr<ReadableStreamDefaultController> readableController =
+ mStream->Readable()->Controller()->AsDefault();
+
+ // Step 2. Return !
+ // ReadableStreamDefaultControllerGetDesiredSize(readableController).
+ return ReadableStreamDefaultControllerGetDesiredSize(readableController);
+}
+
+// https://streams.spec.whatwg.org/#rs-default-controller-has-backpressure
+// Looks like a readable stream thing but the spec explicitly says this is for
+// TransformStream.
+static bool ReadableStreamDefaultControllerHasBackpressure(
+ ReadableStreamDefaultController* aController) {
+ // Step 1: If ! ReadableStreamDefaultControllerShouldCallPull(controller) is
+ // true, return false.
+ // Step 2: Otherwise, return true.
+ return !ReadableStreamDefaultControllerShouldCallPull(aController);
+}
+
+void TransformStreamDefaultController::Enqueue(JSContext* aCx,
+ JS::Handle<JS::Value> aChunk,
+ ErrorResult& aRv) {
+ // Step 1: Perform ? TransformStreamDefaultControllerEnqueue(this, chunk).
+
+ // Inlining TransformStreamDefaultControllerEnqueue here.
+ // https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue
+
+ // Step 1: Let stream be controller.[[stream]].
+ RefPtr<TransformStream> stream = mStream;
+
+ // Step 2: Let readableController be stream.[[readable]].[[controller]].
+ RefPtr<ReadableStreamDefaultController> readableController =
+ stream->Readable()->Controller()->AsDefault();
+
+ // Step 3: If !
+ // ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) is
+ // false, throw a TypeError exception.
+ if (!ReadableStreamDefaultControllerCanCloseOrEnqueueAndThrow(
+ readableController, CloseOrEnqueue::Enqueue, aRv)) {
+ return;
+ }
+
+ // Step 4: Let enqueueResult be
+ // ReadableStreamDefaultControllerEnqueue(readableController, chunk).
+ ErrorResult rv;
+ ReadableStreamDefaultControllerEnqueue(aCx, readableController, aChunk, rv);
+
+ // Step 5: If enqueueResult is an abrupt completion,
+ if (rv.MaybeSetPendingException(aCx)) {
+ JS::Rooted<JS::Value> error(aCx);
+ if (!JS_GetPendingException(aCx, &error)) {
+ // Uncatchable exception; we should mark aRv and return.
+ aRv.StealExceptionFromJSContext(aCx);
+ return;
+ }
+ JS_ClearPendingException(aCx);
+
+ // Step 5.1: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
+ // enqueueResult.[[Value]]).
+ TransformStreamErrorWritableAndUnblockWrite(aCx, stream, error, aRv);
+
+ // Step 5.2: Throw stream.[[readable]].[[storedError]].
+ JS::Rooted<JS::Value> storedError(aCx, stream->Readable()->StoredError());
+ aRv.MightThrowJSException();
+ aRv.ThrowJSException(aCx, storedError);
+ return;
+ }
+
+ // Step 6: Let backpressure be !
+ // ReadableStreamDefaultControllerHasBackpressure(readableController).
+ bool backpressure =
+ ReadableStreamDefaultControllerHasBackpressure(readableController);
+
+ // Step 7: If backpressure is not stream.[[backpressure]],
+ if (backpressure != stream->Backpressure()) {
+ // Step 7.1: Assert: backpressure is true.
+ MOZ_ASSERT(backpressure);
+
+ // Step 7.2: Perform ! TransformStreamSetBackpressure(true).
+ stream->SetBackpressure(true);
+ }
+}
+
+// https://streams.spec.whatwg.org/#ts-default-controller-error
+void TransformStreamDefaultController::Error(JSContext* aCx,
+ JS::Handle<JS::Value> aError,
+ ErrorResult& aRv) {
+ // Step 1: Perform ? TransformStreamDefaultControllerError(this, e).
+
+ // Inlining TransformStreamDefaultControllerError here.
+ // https://streams.spec.whatwg.org/#transform-stream-default-controller-error
+
+ // Perform ! TransformStreamError(controller.[[stream]], e).
+ // mStream is set in initialization step and only modified in cycle
+ // collection.
+ // TODO: Move mStream initialization to a method/constructor and make it
+ // MOZ_KNOWN_LIVE again. (See bug 1769854)
+ TransformStreamError(aCx, MOZ_KnownLive(mStream), aError, aRv);
+}
+
+// https://streams.spec.whatwg.org/#ts-default-controller-terminate
+
+void TransformStreamDefaultController::Terminate(JSContext* aCx,
+ ErrorResult& aRv) {
+ // Step 1: Perform ? TransformStreamDefaultControllerTerminate(this).
+
+ // Inlining TransformStreamDefaultControllerTerminate here.
+ // https://streams.spec.whatwg.org/#transform-stream-default-controller-terminate
+
+ // Step 1: Let stream be controller.[[stream]].
+ RefPtr<TransformStream> stream = mStream;
+
+ // Step 2: Let readableController be stream.[[readable]].[[controller]].
+ RefPtr<ReadableStreamDefaultController> readableController =
+ stream->Readable()->Controller()->AsDefault();
+
+ // Step 3: Perform ! ReadableStreamDefaultControllerClose(readableController).
+ ReadableStreamDefaultControllerClose(aCx, readableController, aRv);
+
+ // Step 4: Let error be a TypeError exception indicating that the stream has
+ // been terminated.
+ ErrorResult rv;
+ rv.ThrowTypeError("Terminating the stream");
+ JS::Rooted<JS::Value> error(aCx);
+ MOZ_ALWAYS_TRUE(ToJSValue(aCx, std::move(rv), &error));
+
+ // Step 5: Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
+ // error).
+ TransformStreamErrorWritableAndUnblockWrite(aCx, stream, error, aRv);
+}
+
+namespace streams_abstract {
+
+// https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller
+void SetUpTransformStreamDefaultController(
+ JSContext* aCx, TransformStream& aStream,
+ TransformStreamDefaultController& aController,
+ TransformerAlgorithmsBase& aTransformerAlgorithms) {
+ // Step 1. Assert: stream implements TransformStream.
+ // Step 2. Assert: stream.[[controller]] is undefined.
+ MOZ_ASSERT(!aStream.Controller());
+
+ // Step 3. Set controller.[[stream]] to stream.
+ aController.SetStream(aStream);
+
+ // Step 4. Set stream.[[controller]] to controller.
+ aStream.SetController(aController);
+
+ // Step 5. Set controller.[[transformAlgorithm]] to transformAlgorithm.
+ // Step 6. Set controller.[[flushAlgorithm]] to flushAlgorithm.
+ aController.SetAlgorithms(&aTransformerAlgorithms);
+}
+
+// https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer
+void SetUpTransformStreamDefaultControllerFromTransformer(
+ JSContext* aCx, TransformStream& aStream,
+ JS::Handle<JSObject*> aTransformer, Transformer& aTransformerDict) {
+ // Step 1. Let controller be a new TransformStreamDefaultController.
+ auto controller =
+ MakeRefPtr<TransformStreamDefaultController>(aStream.GetParentObject());
+
+ // Step 2 - 5:
+ auto algorithms = MakeRefPtr<TransformerAlgorithms>(
+ aStream.GetParentObject(), aTransformer, aTransformerDict);
+
+ // Step 6: Perform ! SetUpTransformStreamDefaultController(stream, controller,
+ // transformAlgorithm, flushAlgorithm).
+ SetUpTransformStreamDefaultController(aCx, aStream, *controller, *algorithms);
+}
+
+} // namespace streams_abstract
+
+} // namespace mozilla::dom