Bug 1486949 - Part 4: Implement TransformStream construction for GenericTransformStream r=smaug

Per the Streams spec, other specs that want to implement custom TransformStream should use [GenericTransformStream](https://streams.spec.whatwg.org/#other-specs-ts-wrapping) mixin and store a [new TransformStream](https://streams.spec.whatwg.org/#transformstream-set-up) in a slot. This implements the latter part.

Differential Revision: https://phabricator.services.mozilla.com/D153975
This commit is contained in:
Kagami Sascha Rosylight 2022-08-12 15:59:04 +00:00
parent bb449a5649
commit 237dffb194
6 changed files with 132 additions and 0 deletions

View File

@ -40,6 +40,63 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStream)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
// https://streams.spec.whatwg.org/#transformstream-set-up
// (except this instead creates a new TransformStream rather than accepting an
// existing instance)
already_AddRefed<TransformStream> TransformStream::CreateGeneric(
const GlobalObject& aGlobal, TransformerAlgorithmsWrapper& aAlgorithms,
ErrorResult& aRv) {
// Step 1. Let writableHighWaterMark be 1.
double writableHighWaterMark = 1;
// Step 2. Let writableSizeAlgorithm be an algorithm that returns 1.
// Note: Callers should recognize nullptr as a callback that returns 1. See
// also WritableStream::Constructor for this design decision.
RefPtr<QueuingStrategySize> writableSizeAlgorithm;
// Step 3. Let readableHighWaterMark be 0.
double readableHighWaterMark = 0;
// Step 4. Let readableSizeAlgorithm be an algorithm that returns 1.
// Note: Callers should recognize nullptr as a callback that returns 1. See
// also ReadableStream::Constructor for this design decision.
RefPtr<QueuingStrategySize> readableSizeAlgorithm;
// Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps
// given a value chunk:
// Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps:
// (Done by TransformerAlgorithmsWrapper)
// Step 7. Let startPromise be a promise resolved with undefined.
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<Promise> startPromise =
Promise::CreateResolvedWithUndefined(global, aRv);
if (!startPromise) {
return nullptr;
}
// Step 8. Perform ! InitializeTransformStream(stream, startPromise,
// writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark,
// readableSizeAlgorithm).
auto stream = MakeRefPtr<TransformStream>(global, nullptr, nullptr);
stream->Initialize(aGlobal.Context(), startPromise, writableHighWaterMark,
writableSizeAlgorithm, readableHighWaterMark,
readableSizeAlgorithm, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Step 9. Let controller be a new TransformStreamDefaultController.
auto controller = MakeRefPtr<TransformStreamDefaultController>(global);
// Step 10. Perform ! SetUpTransformStreamDefaultController(stream,
// controller, transformAlgorithmWrapper, flushAlgorithmWrapper).
SetUpTransformStreamDefaultController(aGlobal.Context(), *stream, *controller,
aAlgorithms);
return stream.forget();
}
TransformStream::TransformStream(nsIGlobalObject* aGlobal) : mGlobal(aGlobal) {
mozilla::HoldJSObjects(this);
}

View File

@ -21,12 +21,19 @@ class WritableStream;
class ReadableStream;
class UniqueMessagePortId;
class MessagePort;
class TransformerAlgorithmsWrapper;
class TransformStream final : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TransformStream)
// https://streams.spec.whatwg.org/#transformstream-set-up
// Intended to be used by interfaces using GenericTransformStream mixin.
MOZ_CAN_RUN_SCRIPT static already_AddRefed<TransformStream> CreateGeneric(
const GlobalObject& aGlobal, TransformerAlgorithmsWrapper& aAlgorithms,
ErrorResult& aRv);
TransformStream(nsIGlobalObject* aGlobal, ReadableStream* aReadable,
WritableStream* aWritable);

View File

@ -58,6 +58,11 @@ class TransformStreamDefaultController final : public nsISupports,
RefPtr<TransformerAlgorithmsBase> mTransformerAlgorithms;
};
void SetUpTransformStreamDefaultController(
JSContext* aCx, TransformStream& aStream,
TransformStreamDefaultController& aController,
TransformerAlgorithmsBase& aTransformerAlgorithms);
void SetUpTransformStreamDefaultControllerFromTransformer(
JSContext* aCx, TransformStream& aStream,
JS::Handle<JSObject*> aTransformer, Transformer& aTransformerDict);

View File

@ -83,3 +83,47 @@ already_AddRefed<Promise> TransformerAlgorithms::FlushCallback(
"TransformStreamDefaultController.[[flushAlgorithm]]",
CallbackObject::eRethrowExceptions);
}
// https://streams.spec.whatwg.org/#transformstream-set-up
// Step 5 and 6.
template <typename T>
MOZ_CAN_RUN_SCRIPT static already_AddRefed<Promise> Promisify(
nsIGlobalObject* aGlobal, T aFunc, mozilla::ErrorResult& aRv) {
// Step 1. Let result be the result of running (algorithm). If this throws an
// exception e, return a promise rejected with e.
aFunc(aRv);
if (aRv.Failed()) {
return Promise::CreateRejectedWithErrorResult(aGlobal, aRv);
}
// Step 2. If result is a Promise, then return result.
// (This supports no return value since currently no subclass needs one)
// Step 3. Return a promise resolved with undefined.
return Promise::CreateResolvedWithUndefined(aGlobal, aRv);
}
already_AddRefed<Promise> TransformerAlgorithmsWrapper::TransformCallback(
JSContext*, JS::Handle<JS::Value> aChunk,
TransformStreamDefaultController& aController, ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = aController.GetParentObject();
return Promisify(
global,
[this, &aChunk, &aController](ErrorResult& aRv)
MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
return TransformCallbackImpl(aChunk, aController, aRv);
},
aRv);
}
already_AddRefed<Promise> TransformerAlgorithmsWrapper::FlushCallback(
JSContext*, TransformStreamDefaultController& aController,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = aController.GetParentObject();
return Promisify(
global,
[this, &aController](ErrorResult& aRv) MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION {
return FlushCallbackImpl(aController, aRv);
},
aRv);
}

View File

@ -77,6 +77,24 @@ class TransformerAlgorithms final : public TransformerAlgorithmsBase {
MOZ_KNOWN_LIVE RefPtr<TransformerFlushCallback> mFlushCallback;
};
// https://streams.spec.whatwg.org/#transformstream-set-up
class TransformerAlgorithmsWrapper : public TransformerAlgorithmsBase {
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> TransformCallback(
JSContext*, JS::Handle<JS::Value> aChunk,
TransformStreamDefaultController& aController, ErrorResult& aRv) final;
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> FlushCallback(
JSContext*, TransformStreamDefaultController& aController,
ErrorResult& aRv) final;
MOZ_CAN_RUN_SCRIPT virtual void TransformCallbackImpl(
JS::Handle<JS::Value> aChunk,
TransformStreamDefaultController& aController, ErrorResult& aRv) = 0;
MOZ_CAN_RUN_SCRIPT virtual void FlushCallbackImpl(
TransformStreamDefaultController& aController, ErrorResult& aRv) = 0;
};
} // namespace mozilla::dom
#endif // DOM_STREAMS_TRANSFORMERCALLBACKHELPERS_H_

View File

@ -27,6 +27,7 @@ EXPORTS.mozilla.dom += [
"ReadRequest.h",
"StreamUtils.h",
"TeeState.h",
"TransformerCallbackHelpers.h",
"TransformStream.h",
"TransformStreamDefaultController.h",
"UnderlyingSinkCallbackHelpers.h",