8000 Script: Implement `TextDecoderStream` (#38112) · servo/servo@554b2da · GitHub
[go: up one dir, main page]

Skip to content

Commit 554b2da

Browse files
author
minghuaw
authored
Script: Implement TextDecoderStream (#38112)
This PR implements the `TextDecoderStream`. Other than introducing the necessary mod and webidl files corresponding to `TextDecoderStream`, this PR also involves some changes in `TextDecoder` and `TrasnformStream`: - The common part that can be shared between `TextDecoder` and `TextDecoderStream` are extracted into a separate type `script::dom::textdecodercommon::TextDecoderCommon`. This type could probably use a different name because there is an interface called `TextDecoderCommon` in the spec (https://encoding.spec.whatwg.org/#textdecodercommon) which just gets included in `TextDecoder` and `TextDecoderStream`. - The three algorithms in `TransformStream` (`cancel`, `flush`, and `transform`) all have become `enum` that has a `Js` variant for a JS function object and a `Native` variant for a rust trait object. Whether the cancel algorithm needs this enum type is debatable as I did not find any interface in the spec that explicitly sets the cancel algorithm. Testing: Existing WPT tests `tests/wpt/tests/encoding/stream` should be sufficient Fixes: #37723 --------- Signed-off-by: minghuaw <michael.wu1107@gmail.com> Signed-off-by: minghuaw <wuminghua7@huawei.com> Signed-off-by: Minghua Wu <michael.wu1107@gmail.com>
1 parent 2582292 commit 554b2da

25 files changed

+799
-754
lines changed

components/script/dom/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ pub(crate) mod testworkletglobalscope;
590590
pub(crate) mod text;
591591
pub(crate) mod textcontrol;
592592
pub(crate) mod textdecoder;
593+
pub(crate) mod textdecodercommon;
594+
pub(crate) mod textdecoderstream;
593595
pub(crate) mod textencoder;
594596
pub(crate) mod textmetrics;
595597
pub(crate) mod texttrack;

components/script/dom/textdecoder.rs

Lines changed: 44 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

55
use std::borrow::ToOwned;
6-
use std::cell::{Cell, RefCell};
6+
use std::cell::Cell;
77

88
use dom_struct::dom_struct;
9-
use encoding_rs::{Decoder, DecoderResult, Encoding};
9+
use encoding_rs::Encoding;
1010
use js::rust::HandleObject;
1111

1212
use crate::dom::bindings::codegen::Bindings::TextDecoderBinding;
@@ -19,37 +19,29 @@ use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
1919
use crate::dom::bindings::root::DomRoot;
2020
use crate::dom::bindings::str::{DOMString, USVString};
2121
use crate::dom::globalscope::GlobalScope;
22+
use crate::dom::textdecodercommon::TextDecoderCommon;
2223
use crate::script_runtime::CanGc;
2324

25+
/// <https://encoding.spec.whatwg.org/#textdecoder>
2426
#[dom_struct]
2527
#[allow(non_snake_case)]
2628
pub(crate) struct TextDecoder {
2729
reflector_: Reflector,
28-
#[no_trace]
29-
encoding: &'static Encoding,
30-
fatal: bool,
31-
ignoreBOM: bool,
32-
#[ignore_malloc_size_of = "defined in encoding_rs"]
33-
#[no_trace]
34-
decoder: RefCell<Decoder>,
35-
in_stream: RefCell<Vec<u8>>,
30+
31+
/// <https://encoding.spec.whatwg.org/#textdecodercommon>
32+
decoder: TextDecoderCommon,
33+
34+
/// <https://encoding.spec.whatwg.org/#textdecoder-do-not-flush-flag>
3635
do_not_flush: Cell<bool>,
3736
}
3837

3938
#[allow(non_snake_case)]
4039
impl TextDecoder {
4140
fn new_inherited(encoding: &'static Encoding, fatal: bool, ignoreBOM: bool) -> TextDecoder {
41+
let decoder = TextDecoderCommon::new_inherited(encoding, fatal, ignoreBOM);
4242
TextDecoder {
4343
reflector_: Reflector::new(),
44-
encoding,
45-
fatal,
46-
ignoreBOM,
47-
decoder: RefCell::new(if ignoreBOM {
48-
encoding.new_decoder()
49-
} else {
50-
encoding.new_decoder_without_bom_handling()
51-
}),
52-
in_stream: RefCell::new(Vec::new()),
44+
decoder,
5345
do_not_flush: Cell::new(false),
5446
}
5547
}
@@ -77,6 +69,7 @@ impl TextDecoder {
7769
}
7870
}
7971

72+
#[allow(non_snake_case)]
8073
impl TextDecoderMethods<crate::DomTypeHolder> for TextDecoder {
8174
/// <https://encoding.spec.whatwg.org/#dom-textdecoder>
8275
fn Constructor(
@@ -100,85 +93,59 @@ impl TextDecoderMethods<crate::DomTypeHolder> for TextDecoder {
10093
))
10194
}
10295

103-
// https://encoding.spec.whatwg.org/#dom-textdecoder-encoding
96+
/// <https://encoding.spec.whatwg.org/#dom-textdecoder-encoding>
10497
fn Encoding(&self) -> DOMString {
105-
DOMString::from(self.encoding.name().to_ascii_lowercase())
98+
DOMString::from(self.decoder.encoding().name().to_ascii_lowercase())
10699
}
107100

108-
// https://encoding.spec.whatwg.org/#dom-textdecoder-fatal
101+
/// <https://encoding.spec.whatwg.org/#dom-textdecoder-fatal>
109102
fn Fatal(&self) -> bool {
110-
self.fatal
103+
self.decoder.fatal()
111104
}
112105

113-
// https://encoding.spec.whatwg.org/#dom-textdecoder-ignorebom
106+
/// <https://encoding.spec.whatwg.org/#dom-textdecoder-ignorebom>
114107
fn IgnoreBOM(&self) -> bool {
115-
self.ignoreBOM
108+
self.decoder.ignore_bom()
116109
}
117110

118-
// https://encoding.spec.whatwg.org/#dom-textdecoder-decode
111+
/// <https://encoding.spec.whatwg.org/#dom-textdecoder-decode>
119112
fn Decode(
120113
&self,
121114
input: Option<ArrayBufferViewOrArrayBuffer>,
122115
options: &TextDecodeOptions,
123116
) -> Fallible<USVString> {
124-
// Step 1.
117+
// Step 1. If this’s do not flush is false, then set this’s decoder to a new
118+
// instance of this’s encoding’s decoder, this’s I/O queue to the I/O queue
119+
// of bytes « end-of-queue », and this’s BOM seen to false.
125120
if !self.do_not_flush.get() {
126-
if self.ignoreBOM {
121+
if self.decoder.ignore_bom() {
127122
self.decoder
128-
.replace(self.encoding.new_decoder_without_bom_handling());
123+
.decoder()
124+
.replace(self.decoder.encoding().new_decoder_without_bom_handling());
129125
} else {
130-
self.decoder.replace(self.encoding.new_decoder());
126+
self.decoder
127+
.decoder()
128+
.replace(self.decoder.encoding().new_decoder_with_bom_removal());
131129
}
132-
self.in_stream.replace(Vec::new());
130+
self.decoder.io_queue().replace(Vec::new());
133131
}
134132

135-
// Step 2.
133+
// Step 2. Set this’s do not flush to options["stream"].
136134
self.do_not_flush.set(options.stream);
137135

138-
// Step 3.
139-
match input {
140-
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref a)) => {
141-
self.in_stream.borrow_mut().extend_from_slice(&a.to_vec());
142-
},
143-
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref a)) => {
144-
self.in_stream.borrow_mut().extend_from_slice(&a.to_vec());
145-
},
146-
None => {},
147-
};
148-
149-
let mut decoder = self.decoder.borrow_mut();
150-
let (remaining, s) = {
151-
let mut in_stream = self.in_stream.borrow_mut();
152-
153-
let (remaining, s) = if self.fatal {
154-
// Step 4.
155-
let mut out_stream = String::with_capacity(
156-
decoder
157-
.max_utf8_buffer_length_without_replacement(in_stream.len())
158-
.unwrap(),
159-
);
160-
// Step 5: Implemented by encoding_rs::Decoder.
161-
match decoder.decode_to_string_without_replacement(
162-
&in_stream,
163-
&mut out_stream,
164-
!options.stream,
165-
) {
166-
(DecoderResult::InputEmpty, read) => (in_stream.split_off(read), out_stream),
167-
// Step 5.3.3.
168-
_ => return Err(Error::Type("Decoding failed".to_owned())),
169-
}
170-
} else {
171-
// Step 4.
172-
let mut out_stream =
173-
String::with_capacity(decoder.max_utf8_buffer_length(in_stream.len()).unwrap());
174-
// Step 5: Implemented by encoding_rs::Decoder.
175-
let (_result, read, _replaced) =
176-
decoder.decode_to_string(&in_stream, &mut out_stream, !options.stream);
177-
(in_stream.split_off(read), out_stream)
178-
};
179-
(remaining, s)
180-
};
181-
self.in_stream.replace(remaining);
182-
Ok(USVString(s))
136+
// Step 3. If input is given, then push a copy of input to this’s I/O queue.
137+
// Step 4. Let output be the I/O queue of scalar values « end-of-queue ».
138+
// Step 5. While true:
139+
// Step 5.1 Let item be the result of reading from this’s I/O queue.
140+
// Step 5.2 If item is end-of-queue and this’s do not flush is true,
141+
// then return the result of running serialize I/O queue with this and output.
142+
// Step 5.3 Otherwise:
143+
// Step 5.3.1 Let result be the result of processing an item with item, this’s decoder,
144+
// this’s I/O queue, output, and this’s error mode.
145+
// Step 5.3.2 If result is finished, then return the result of running serialize I/O
146+
// queue with this and output.
147+
self.decoder
148+
.decode(input.as_ref(), !options.stream)
149+
.map(USVString)
183150
}
184151
}

0 commit comments

Comments
 (0)
0