script/dom/
textdecoder.rs1use std::borrow::ToOwned;
6use std::cell::Cell;
7
8use dom_struct::dom_struct;
9use encoding_rs::Encoding;
10use js::rust::HandleObject;
11
12use crate::dom::bindings::codegen::Bindings::TextDecoderBinding;
13use crate::dom::bindings::codegen::Bindings::TextDecoderBinding::{
14 TextDecodeOptions, TextDecoderMethods,
15};
16use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
17use crate::dom::bindings::error::{Error, Fallible};
18use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
19use crate::dom::bindings::root::DomRoot;
20use crate::dom::bindings::str::{DOMString, USVString};
21use crate::dom::globalscope::GlobalScope;
22use crate::dom::textdecodercommon::TextDecoderCommon;
23use crate::script_runtime::CanGc;
24
25#[dom_struct]
27pub(crate) struct TextDecoder {
28 reflector_: Reflector,
29
30 decoder: TextDecoderCommon,
32
33 do_not_flush: Cell<bool>,
35}
36
37#[expect(non_snake_case)]
38impl TextDecoder {
39 fn new_inherited(encoding: &'static Encoding, fatal: bool, ignoreBOM: bool) -> TextDecoder {
40 let decoder = TextDecoderCommon::new_inherited(encoding, fatal, ignoreBOM);
41 TextDecoder {
42 reflector_: Reflector::new(),
43 decoder,
44 do_not_flush: Cell::new(false),
45 }
46 }
47
48 fn make_range_error() -> Fallible<DomRoot<TextDecoder>> {
49 Err(Error::Range(
50 "The given encoding is not supported.".to_owned(),
51 ))
52 }
53
54 fn new(
55 global: &GlobalScope,
56 proto: Option<HandleObject>,
57 encoding: &'static Encoding,
58 fatal: bool,
59 ignoreBOM: bool,
60 can_gc: CanGc,
61 ) -> DomRoot<TextDecoder> {
62 reflect_dom_object_with_proto(
63 Box::new(TextDecoder::new_inherited(encoding, fatal, ignoreBOM)),
64 global,
65 proto,
66 can_gc,
67 )
68 }
69}
70
71impl TextDecoderMethods<crate::DomTypeHolder> for TextDecoder {
72 fn Constructor(
74 global: &GlobalScope,
75 proto: Option<HandleObject>,
76 can_gc: CanGc,
77 label: DOMString,
78 options: &TextDecoderBinding::TextDecoderOptions,
79 ) -> Fallible<DomRoot<TextDecoder>> {
80 let encoding = match Encoding::for_label_no_replacement(&label.as_bytes()) {
81 None => return TextDecoder::make_range_error(),
82 Some(enc) => enc,
83 };
84 Ok(TextDecoder::new(
85 global,
86 proto,
87 encoding,
88 options.fatal,
89 options.ignoreBOM,
90 can_gc,
91 ))
92 }
93
94 fn Encoding(&self) -> DOMString {
96 DOMString::from(self.decoder.encoding().name().to_ascii_lowercase())
97 }
98
99 fn Fatal(&self) -> bool {
101 self.decoder.fatal()
102 }
103
104 fn IgnoreBOM(&self) -> bool {
106 self.decoder.ignore_bom()
107 }
108
109 fn Decode(
111 &self,
112 input: Option<ArrayBufferViewOrArrayBuffer>,
113 options: &TextDecodeOptions,
114 ) -> Fallible<USVString> {
115 if !self.do_not_flush.get() {
119 if self.decoder.ignore_bom() {
120 self.decoder
121 .decoder()
122 .replace(self.decoder.encoding().new_decoder_without_bom_handling());
123 } else {
124 self.decoder
125 .decoder()
126 .replace(self.decoder.encoding().new_decoder_with_bom_removal());
127 }
128 self.decoder.io_queue().replace(Vec::new());
129 }
130
131 self.do_not_flush.set(options.stream);
133
134 self.decoder
146 .decode(input.as_ref(), !options.stream)
147 .map(USVString)
148 }
149}