mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			238 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- 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
 |