no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / encoding / TextDecoderStream.cpp
blobb7b89e3362403fd6c03179fdbd77397b5a703e5e
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/TextDecoderStream.h"
9 #include "nsContentUtils.h"
10 #include "nsIGlobalObject.h"
11 #include "mozilla/Encoding.h"
12 #include "mozilla/dom/Promise.h"
13 #include "mozilla/dom/TextDecoderStreamBinding.h"
14 #include "mozilla/dom/TransformerCallbackHelpers.h"
15 #include "mozilla/dom/TransformStream.h"
16 #include "mozilla/dom/UnionTypes.h"
18 namespace mozilla::dom {
20 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextDecoderStream, mGlobal, mStream)
21 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextDecoderStream)
22 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextDecoderStream)
23 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoderStream)
24 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
25 NS_INTERFACE_MAP_ENTRY(nsISupports)
26 NS_INTERFACE_MAP_END
28 TextDecoderStream::TextDecoderStream(nsISupports* aGlobal,
29 const Encoding& aEncoding, bool aFatal,
30 bool aIgnoreBOM, TransformStream& aStream)
31 : mGlobal(aGlobal), mStream(&aStream) {
32 mFatal = aFatal;
33 mIgnoreBOM = aIgnoreBOM;
34 aEncoding.Name(mEncoding);
35 if (aIgnoreBOM) {
36 mDecoder = aEncoding.NewDecoderWithoutBOMHandling();
37 } else {
38 mDecoder = aEncoding.NewDecoderWithBOMRemoval();
42 TextDecoderStream::~TextDecoderStream() = default;
44 JSObject* TextDecoderStream::WrapObject(JSContext* aCx,
45 JS::Handle<JSObject*> aGivenProto) {
46 return TextDecoderStream_Binding::Wrap(aCx, this, aGivenProto);
49 class TextDecoderStreamAlgorithms : public TransformerAlgorithmsWrapper {
50 NS_DECL_ISUPPORTS_INHERITED
51 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextDecoderStreamAlgorithms,
52 TransformerAlgorithmsBase)
54 void SetDecoderStream(TextDecoderStream& aStream) {
55 mDecoderStream = &aStream;
58 // The common part of decode-and-enqueue and flush-and-enqueue.
59 // Note that the most of the decoding algorithm is implemented in
60 // mozilla::Decoder, and this is mainly about calling it properly.
61 // https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk
62 // TODO: This does not allow shared array buffers, just as the non-stream
63 // TextDecoder/Encoder don't. (Bug 1561594)
64 MOZ_CAN_RUN_SCRIPT void DecodeBufferSourceAndEnqueue(
65 JSContext* aCx, OwningArrayBufferViewOrArrayBuffer* aInput, bool aFlush,
66 TransformStreamDefaultController& aController, ErrorResult& aRv) {
67 nsString outDecodedString;
68 if (aInput) {
69 ProcessTypedArrays(*aInput, [&](const Span<const uint8_t>& aData,
70 JS::AutoCheckCannotGC&&) {
71 mDecoderStream->DecodeNative(aData, !aFlush, outDecodedString, aRv);
72 });
73 } else {
74 mDecoderStream->DecodeNative(Span<const uint8_t>(), !aFlush,
75 outDecodedString, aRv);
78 if (aRv.Failed()) {
79 return;
82 if (outDecodedString.Length()) {
83 // Step 4.2. If outputChunk is non-empty, then enqueue outputChunk in
84 // decoder’s transform.
85 JS::Rooted<JS::Value> outputChunk(aCx);
86 if (!ToJSValue(aCx, outDecodedString, &outputChunk)) {
87 JS_ClearPendingException(aCx);
88 aRv.Throw(NS_ERROR_UNEXPECTED);
89 return;
91 aController.Enqueue(aCx, outputChunk, aRv);
95 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
96 MOZ_CAN_RUN_SCRIPT void TransformCallbackImpl(
97 JS::Handle<JS::Value> aChunk,
98 TransformStreamDefaultController& aController,
99 ErrorResult& aRv) override {
100 // Step 7. Let transformAlgorithm be an algorithm which takes a chunk
101 // argument and runs the decode and enqueue a chunk algorithm with this and
102 // chunk.
104 // https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk
106 AutoJSAPI jsapi;
107 if (!jsapi.Init(aController.GetParentObject())) {
108 aRv.ThrowUnknownError("Internal error");
109 return;
111 JSContext* cx = jsapi.cx();
113 // Step 1. Let bufferSource be the result of converting chunk to an
114 // [AllowShared] BufferSource.
115 RootedUnion<OwningArrayBufferViewOrArrayBuffer> bufferSource(cx);
116 if (!bufferSource.Init(cx, aChunk)) {
117 aRv.MightThrowJSException();
118 aRv.StealExceptionFromJSContext(cx);
119 return;
122 DecodeBufferSourceAndEnqueue(cx, &bufferSource, false, aController, aRv);
125 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
126 MOZ_CAN_RUN_SCRIPT void FlushCallbackImpl(
127 TransformStreamDefaultController& aController,
128 ErrorResult& aRv) override {
129 // Step 8. Let flushAlgorithm be an algorithm which takes no arguments and
130 // runs the flush and enqueue algorithm with this.
132 AutoJSAPI jsapi;
133 if (!jsapi.Init(aController.GetParentObject())) {
134 aRv.ThrowUnknownError("Internal error");
135 return;
137 JSContext* cx = jsapi.cx();
139 // https://encoding.spec.whatwg.org/#flush-and-enqueue
140 // (The flush and enqueue algorithm is basically a subset of decode and
141 // enqueue one, so let's reuse it)
142 DecodeBufferSourceAndEnqueue(cx, nullptr, true, aController, aRv);
145 private:
146 ~TextDecoderStreamAlgorithms() override = default;
148 RefPtr<TextDecoderStream> mDecoderStream;
151 NS_IMPL_CYCLE_COLLECTION_INHERITED(TextDecoderStreamAlgorithms,
152 TransformerAlgorithmsBase, mDecoderStream)
153 NS_IMPL_ADDREF_INHERITED(TextDecoderStreamAlgorithms, TransformerAlgorithmsBase)
154 NS_IMPL_RELEASE_INHERITED(TextDecoderStreamAlgorithms,
155 TransformerAlgorithmsBase)
156 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoderStreamAlgorithms)
157 NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
159 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
160 already_AddRefed<TextDecoderStream> TextDecoderStream::Constructor(
161 const GlobalObject& aGlobal, const nsAString& aLabel,
162 const TextDecoderOptions& aOptions, ErrorResult& aRv) {
163 // Step 1. Let encoding be the result of getting an encoding from label.
164 const Encoding* encoding = Encoding::ForLabelNoReplacement(aLabel);
166 // Step 2. If encoding is failure or replacement, then throw a RangeError
167 if (!encoding) {
168 NS_ConvertUTF16toUTF8 label(aLabel);
169 label.Trim(" \t\n\f\r");
170 aRv.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(label);
171 return nullptr;
174 // Step 3-6. (Done in the constructor)
176 // Step 7-8.
177 auto algorithms = MakeRefPtr<TextDecoderStreamAlgorithms>();
179 // Step 9-10.
180 RefPtr<TransformStream> transformStream =
181 TransformStream::CreateGeneric(aGlobal, *algorithms, aRv);
182 if (aRv.Failed()) {
183 return nullptr;
186 // Step 11. (Done in the constructor)
187 auto decoderStream = MakeRefPtr<TextDecoderStream>(
188 aGlobal.GetAsSupports(), *encoding, aOptions.mFatal, aOptions.mIgnoreBOM,
189 *transformStream);
190 algorithms->SetDecoderStream(*decoderStream);
191 return decoderStream.forget();
194 ReadableStream* TextDecoderStream::Readable() const {
195 return mStream->Readable();
198 WritableStream* TextDecoderStream::Writable() const {
199 return mStream->Writable();
202 } // namespace mozilla::dom