commit 385b95367724fb9618970585ba0b16f59f8edc88
parent c1908042576709900a40049826cc223cbc14b887
Author: Kagami Sascha Rosylight <krosylight@proton.me>
Date: Thu, 23 Oct 2025 21:34:48 +0000
Bug 1995999: Implement CompressionStreamAlgorithms as a superclass r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D269751
Diffstat:
6 files changed, 154 insertions(+), 137 deletions(-)
diff --git a/dom/compression/BaseAlgorithms.cpp b/dom/compression/BaseAlgorithms.cpp
@@ -13,17 +13,90 @@
namespace mozilla::dom::compression {
-NS_IMPL_CYCLE_COLLECTION_INHERITED(DecompressionStreamAlgorithms,
- TransformerAlgorithmsBase)
-NS_IMPL_ADDREF_INHERITED(DecompressionStreamAlgorithms,
- TransformerAlgorithmsBase)
-NS_IMPL_RELEASE_INHERITED(DecompressionStreamAlgorithms,
- TransformerAlgorithmsBase)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DecompressionStreamAlgorithms)
-NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
+// Step 3 of
+// https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream
+// Let transformAlgorithm be an algorithm which takes a chunk argument and
+// runs the compress and enqueue a chunk algorithm with this and chunk.
+MOZ_CAN_RUN_SCRIPT
+void CompressionStreamAlgorithms::TransformCallbackImpl(
+ JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController,
+ ErrorResult& aRv) {
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(aController.GetParentObject())) {
+ aRv.ThrowUnknownError("Internal error");
+ return;
+ }
+ JSContext* cx = jsapi.cx();
+
+ // https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk
+
+ // Step 1: If chunk is not a BufferSource type, then throw a TypeError.
+ RootedUnion<OwningBufferSource> bufferSource(cx);
+ if (!bufferSource.Init(cx, aChunk)) {
+ aRv.MightThrowJSException();
+ aRv.StealExceptionFromJSContext(cx);
+ return;
+ }
+
+ // Step 2 - 5: (Done in CompressAndEnqueue)
+ ProcessTypedArraysFixed(
+ bufferSource,
+ [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
+ CompressAndEnqueue(cx, aData, Flush::No, aController, aRv);
+ });
+}
+
+// Step 4 of
+// https://compression.spec.whatwg.org/#dom-compressionstream-compressionstream
+// Let flushAlgorithm be an algorithm which takes no argument and runs the
+// compress flush and enqueue algorithm with this.
+MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::FlushCallbackImpl(
+ TransformStreamDefaultController& aController, ErrorResult& aRv) {
+ AutoJSAPI jsapi;
+ if (!jsapi.Init(aController.GetParentObject())) {
+ aRv.ThrowUnknownError("Internal error");
+ return;
+ }
+ JSContext* cx = jsapi.cx();
+
+ // https://compression.spec.whatwg.org/#compress-flush-and-enqueue
+
+ // Step 1 - 4: (Done in CompressAndEnqueue)
+ CompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv);
+}
+
+// Shared by:
+// https://compression.spec.whatwg.org/#compress-and-enqueue-a-chunk
+// https://compression.spec.whatwg.org/#compress-flush-and-enqueue
+MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue(
+ JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
+ TransformStreamDefaultController& aController, ErrorResult& aRv) {
+ MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length());
+
+ JS::RootedVector<JSObject*> array(aCx);
+
+ // Step 2: Let buffer be the result of compressing chunk with cs’s
+ // format and context.
+ // Step 3: If buffer is empty, return. (implicit as array will be empty then)
+ // Step 4: Let arrays be the result of buffer into one or more non-empty
+ // pieces and converting them into Uint8Arrays.
+ Compress(aCx, aInput, &array, aFlush, aRv);
+ if (aRv.Failed()) {
+ return;
+ }
+
+ // Step 5: For each Uint8Array array, enqueue array in cs's transform.
+ for (const auto& view : array) {
+ JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view));
+ aController.Enqueue(aCx, value, aRv);
+ if (aRv.Failed()) {
+ return;
+ }
+ }
+}
// Step 3 of
-// https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream
+// https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream
// Let transformAlgorithm be an algorithm which takes a chunk argument and
// runs the compress and enqueue a chunk algorithm with this and chunk.
MOZ_CAN_RUN_SCRIPT
@@ -70,7 +143,7 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::FlushCallbackImpl(
}
JSContext* cx = jsapi.cx();
- // https://wicg.github.io/compression/#decompress-flush-and-enqueue
+ // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
// Step 1: Let buffer be the result of decompressing an empty input with
// ds's format and context, with the finish flag.
@@ -79,8 +152,8 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::FlushCallbackImpl(
}
// Shared by:
-// https://wicg.github.io/compression/#decompress-and-enqueue-a-chunk
-// https://wicg.github.io/compression/#decompress-flush-and-enqueue
+// https://compression.spec.whatwg.org/#decompress-and-enqueue-a-chunk
+// https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::DecompressAndEnqueue(
JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
TransformStreamDefaultController& aController, ErrorResult& aRv) {
@@ -116,7 +189,7 @@ MOZ_CAN_RUN_SCRIPT void DecompressionStreamAlgorithms::DecompressAndEnqueue(
}
// Step 3 of
- // https://wicg.github.io/compression/#decompress-flush-and-enqueue
+ // https://compression.spec.whatwg.org/#decompress-flush-and-enqueue
// If the end of the compressed input has not been reached, then throw a
// TypeError.
if (aFlush == Flush::Yes && !mObservedStreamEnd) {
diff --git a/dom/compression/BaseAlgorithms.h b/dom/compression/BaseAlgorithms.h
@@ -17,12 +17,41 @@ namespace mozilla::dom::compression {
// with a function defined below.
enum class Flush : bool { No, Yes };
-class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
+class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DecompressionStreamAlgorithms,
- TransformerAlgorithmsBase)
+ // Step 3 of
+ // https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream
+ // Let transformAlgorithm be an algorithm which takes a chunk argument and
+ // runs the compress and enqueue a chunk algorithm with this and chunk.
+ MOZ_CAN_RUN_SCRIPT
+ void TransformCallbackImpl(JS::Handle<JS::Value> aChunk,
+ TransformStreamDefaultController& aController,
+ ErrorResult& aRv) override;
+
+ // Step 4 of
+ // https://compression.spec.whatwg.org/#dom-decompressionstream-decompressionstream
+ // Let flushAlgorithm be an algorithm which takes no argument and runs the
+ // compress flush and enqueue algorithm with this.
+ MOZ_CAN_RUN_SCRIPT void FlushCallbackImpl(
+ TransformStreamDefaultController& aController, ErrorResult& aRv) override;
+
+ protected:
+ static const uint16_t kBufferSize = 16384;
+
+ ~CompressionStreamAlgorithms() = default;
+
+ virtual void Compress(JSContext* aCx, Span<const uint8_t> aInput,
+ JS::MutableHandleVector<JSObject*> aOutput,
+ Flush aFlush, ErrorResult& aRv) = 0;
+ private:
+ MOZ_CAN_RUN_SCRIPT void CompressAndEnqueue(
+ JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
+ TransformStreamDefaultController& aController, ErrorResult& aRv);
+};
+
+class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
+ public:
// Step 3 of
// https://wicg.github.io/compression/#dom-decompressionstream-decompressionstream
// Let transformAlgorithm be an algorithm which takes a chunk argument and
diff --git a/dom/compression/CompressionStream.cpp b/dom/compression/CompressionStream.cpp
@@ -60,7 +60,7 @@ already_AddRefed<CompressionStream> CompressionStream::Constructor(
// Step 6: Set up this's transform with transformAlgorithm set to
// transformAlgorithm and flushAlgorithm set to flushAlgorithm.
Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult> algorithms =
- CompressionStreamAlgorithms::Create(aFormat);
+ ZLibCompressionStreamAlgorithms::Create(aFormat);
if (algorithms.isErr()) {
aRv.ThrowUnknownError("Not enough memory");
return nullptr;
diff --git a/dom/compression/FormatZlib.cpp b/dom/compression/FormatZlib.cpp
@@ -7,30 +7,28 @@
#include "FormatZlib.h"
#include "BaseAlgorithms.h"
-#include "mozilla/dom/BufferSourceBinding.h"
-#include "mozilla/dom/BufferSourceBindingFwd.h"
#include "mozilla/dom/CompressionStreamBinding.h"
#include "mozilla/dom/TransformStreamDefaultController.h"
-#include "mozilla/dom/UnionTypes.h"
namespace mozilla::dom::compression {
-NS_IMPL_CYCLE_COLLECTION_INHERITED(CompressionStreamAlgorithms,
+NS_IMPL_CYCLE_COLLECTION_INHERITED(ZLibCompressionStreamAlgorithms,
TransformerAlgorithmsBase)
-NS_IMPL_ADDREF_INHERITED(CompressionStreamAlgorithms, TransformerAlgorithmsBase)
-NS_IMPL_RELEASE_INHERITED(CompressionStreamAlgorithms,
+NS_IMPL_ADDREF_INHERITED(ZLibCompressionStreamAlgorithms,
+ TransformerAlgorithmsBase)
+NS_IMPL_RELEASE_INHERITED(ZLibCompressionStreamAlgorithms,
TransformerAlgorithmsBase)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompressionStreamAlgorithms)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZLibCompressionStreamAlgorithms)
NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ZLibDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_IMPL_ADDREF_INHERITED(ZLibDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_IMPL_RELEASE_INHERITED(ZLibDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZLibDecompressionStreamAlgorithms)
-NS_INTERFACE_MAP_END_INHERITING(DecompressionStreamAlgorithms)
+NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
inline uint8_t intoZLibFlush(Flush aFlush) {
switch (aFlush) {
@@ -72,14 +70,15 @@ inline int8_t ZLibWindowBits(CompressionFormat format) {
}
}
-Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult>
-CompressionStreamAlgorithms::Create(CompressionFormat format) {
- RefPtr<CompressionStreamAlgorithms> alg = new CompressionStreamAlgorithms();
+Result<already_AddRefed<ZLibCompressionStreamAlgorithms>, nsresult>
+ZLibCompressionStreamAlgorithms::Create(CompressionFormat format) {
+ RefPtr<ZLibCompressionStreamAlgorithms> alg =
+ new ZLibCompressionStreamAlgorithms();
MOZ_TRY(alg->Init(format));
return alg.forget();
}
-[[nodiscard]] nsresult CompressionStreamAlgorithms::Init(
+[[nodiscard]] nsresult ZLibCompressionStreamAlgorithms::Init(
CompressionFormat format) {
int8_t err = deflateInit2(&mZStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
ZLibWindowBits(format), 8 /* default memLevel */,
@@ -91,75 +90,16 @@ CompressionStreamAlgorithms::Create(CompressionFormat format) {
return NS_OK;
}
-// Step 3 of
-// https://wicg.github.io/compression/#dom-compressionstream-compressionstream
-// Let transformAlgorithm be an algorithm which takes a chunk argument and
-// runs the compress and enqueue a chunk algorithm with this and chunk.
-MOZ_CAN_RUN_SCRIPT
-void CompressionStreamAlgorithms::TransformCallbackImpl(
- JS::Handle<JS::Value> aChunk, TransformStreamDefaultController& aController,
- ErrorResult& aRv) {
- AutoJSAPI jsapi;
- if (!jsapi.Init(aController.GetParentObject())) {
- aRv.ThrowUnknownError("Internal error");
- return;
- }
- JSContext* cx = jsapi.cx();
-
- // https://wicg.github.io/compression/#compress-and-enqueue-a-chunk
-
- // Step 1: If chunk is not a BufferSource type, then throw a TypeError.
- RootedUnion<OwningBufferSource> bufferSource(cx);
- if (!bufferSource.Init(cx, aChunk)) {
- aRv.MightThrowJSException();
- aRv.StealExceptionFromJSContext(cx);
- return;
- }
-
- // Step 2: Let buffer be the result of compressing chunk with cs's format
- // and context.
- // Step 3 - 5: (Done in CompressAndEnqueue)
- ProcessTypedArraysFixed(
- bufferSource,
- [&](const Span<uint8_t>& aData) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
- CompressAndEnqueue(cx, aData, Flush::No, aController, aRv);
- });
-}
-
-// Step 4 of
-// https://wicg.github.io/compression/#dom-compressionstream-compressionstream
-// Let flushAlgorithm be an algorithm which takes no argument and runs the
-// compress flush and enqueue algorithm with this.
-MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::FlushCallbackImpl(
- TransformStreamDefaultController& aController, ErrorResult& aRv) {
- AutoJSAPI jsapi;
- if (!jsapi.Init(aController.GetParentObject())) {
- aRv.ThrowUnknownError("Internal error");
- return;
- }
- JSContext* cx = jsapi.cx();
-
- // https://wicg.github.io/compression/#compress-flush-and-enqueue
-
- // Step 1: Let buffer be the result of compressing an empty input with cs's
- // format and context, with the finish flag.
- // Step 2 - 4: (Done in CompressAndEnqueue)
- CompressAndEnqueue(cx, Span<const uint8_t>(), Flush::Yes, aController, aRv);
-}
-
// Shared by:
// https://wicg.github.io/compression/#compress-and-enqueue-a-chunk
// https://wicg.github.io/compression/#compress-flush-and-enqueue
-MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue(
- JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
- TransformStreamDefaultController& aController, ErrorResult& aRv) {
- MOZ_ASSERT_IF(aFlush == Flush::Yes, !aInput.Length());
-
+void ZLibCompressionStreamAlgorithms::Compress(
+ JSContext* aCx, Span<const uint8_t> aInput,
+ JS::MutableHandleVector<JSObject*> aOutput, Flush aFlush,
+ ErrorResult& aRv) {
mZStream.avail_in = aInput.Length();
mZStream.next_in = const_cast<uint8_t*>(aInput.Elements());
- JS::RootedVector<JSObject*> array(aCx);
-
do {
static uint16_t kBufferSize = 16384;
UniquePtr<uint8_t[], JS::FreePolicy> buffer(
@@ -220,7 +160,7 @@ MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue(
JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array(
aCx, written, std::move(buffer)));
- if (!view || !array.append(view)) {
+ if (!view || !aOutput.append(view)) {
JS_ClearPendingException(aCx);
aRv.ThrowTypeError("Out of memory");
return;
@@ -230,18 +170,9 @@ MOZ_CAN_RUN_SCRIPT void CompressionStreamAlgorithms::CompressAndEnqueue(
// If deflate returns with avail_out == 0, this function must be called
// again with the same value of the flush parameter and more output space
// (updated avail_out)
-
- // Step 5: For each Uint8Array array, enqueue array in cs's transform.
- for (const auto& view : array) {
- JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*view));
- aController.Enqueue(aCx, value, aRv);
- if (aRv.Failed()) {
- return;
- }
- }
}
-CompressionStreamAlgorithms::~CompressionStreamAlgorithms() {
+ZLibCompressionStreamAlgorithms::~ZLibCompressionStreamAlgorithms() {
deflateEnd(&mZStream);
};
diff --git a/dom/compression/FormatZlib.h b/dom/compression/FormatZlib.h
@@ -20,44 +20,28 @@ enum class CompressionFormat : uint8_t;
namespace mozilla::dom::compression {
-class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
+class ZLibCompressionStreamAlgorithms : public CompressionStreamAlgorithms {
public:
NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompressionStreamAlgorithms,
- TransformerAlgorithmsBase)
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ZLibCompressionStreamAlgorithms,
+ CompressionStreamAlgorithms)
- static Result<already_AddRefed<CompressionStreamAlgorithms>, nsresult> Create(
- CompressionFormat format);
+ static Result<already_AddRefed<ZLibCompressionStreamAlgorithms>, nsresult>
+ Create(CompressionFormat format);
private:
- CompressionStreamAlgorithms() = default;
+ ZLibCompressionStreamAlgorithms() = default;
[[nodiscard]] nsresult Init(CompressionFormat format);
- // Step 3 of
- // https://wicg.github.io/compression/#dom-compressionstream-compressionstream
- // Let transformAlgorithm be an algorithm which takes a chunk argument and
- // runs the compress and enqueue a chunk algorithm with this and chunk.
- MOZ_CAN_RUN_SCRIPT
- void TransformCallbackImpl(JS::Handle<JS::Value> aChunk,
- TransformStreamDefaultController& aController,
- ErrorResult& aRv) override;
-
- // Step 4 of
- // https://wicg.github.io/compression/#dom-compressionstream-compressionstream
- // Let flushAlgorithm be an algorithm which takes no argument and runs the
- // compress flush and enqueue algorithm with this.
- MOZ_CAN_RUN_SCRIPT void FlushCallbackImpl(
- TransformStreamDefaultController& aController, ErrorResult& aRv) override;
-
// Shared by:
// https://wicg.github.io/compression/#compress-and-enqueue-a-chunk
// https://wicg.github.io/compression/#compress-flush-and-enqueue
- MOZ_CAN_RUN_SCRIPT void CompressAndEnqueue(
- JSContext* aCx, Span<const uint8_t> aInput, Flush aFlush,
- TransformStreamDefaultController& aController, ErrorResult& aRv);
+ void Compress(JSContext* aCx, Span<const uint8_t> aInput,
+ JS::MutableHandleVector<JSObject*> aOutput, Flush aFlush,
+ ErrorResult& aRv) override;
- ~CompressionStreamAlgorithms() override;
+ ~ZLibCompressionStreamAlgorithms() override;
z_stream mZStream = {};
};
diff --git a/dom/compression/FormatZstd.cpp b/dom/compression/FormatZstd.cpp
@@ -13,13 +13,13 @@
namespace mozilla::dom::compression {
NS_IMPL_CYCLE_COLLECTION_INHERITED(ZstdDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_IMPL_ADDREF_INHERITED(ZstdDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_IMPL_RELEASE_INHERITED(ZstdDecompressionStreamAlgorithms,
- DecompressionStreamAlgorithms)
+ TransformerAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZstdDecompressionStreamAlgorithms)
-NS_INTERFACE_MAP_END_INHERITING(DecompressionStreamAlgorithms)
+NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
Result<already_AddRefed<ZstdDecompressionStreamAlgorithms>, nsresult>
ZstdDecompressionStreamAlgorithms::Create() {