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]
27#[allow(non_snake_case)]
28pub(crate) struct TextDecoder {
29 reflector_: Reflector,
30
31 decoder: TextDecoderCommon,
33
34 do_not_flush: Cell<bool>,
36}
37
38#[allow(non_snake_case)]
39impl TextDecoder {
40 fn new_inherited(encoding: &'static Encoding, fatal: bool, ignoreBOM: bool) -> TextDecoder {
41 let decoder = TextDecoderCommon::new_inherited(encoding, fatal, ignoreBOM);
42 TextDecoder {
43 reflector_: Reflector::new(),
44 decoder,
45 do_not_flush: Cell::new(false),
46 }
47 }
48
49 fn make_range_error() -> Fallible<DomRoot<TextDecoder>> {
50 Err(Error::Range(
51 "The given encoding is not supported.".to_owned(),
52 ))
53 }
54
55 fn new(
56 global: &GlobalScope,
57 proto: Option<HandleObject>,
58 encoding: &'static Encoding,
59 fatal: bool,
60 ignoreBOM: bool,
61 can_gc: CanGc,
62 ) -> DomRoot<TextDecoder> {
63 reflect_dom_object_with_proto(
64 Box::new(TextDecoder::new_inherited(encoding, fatal, ignoreBOM)),
65 global,
66 proto,
67 can_gc,
68 )
69 }
70}
71
72#[allow(non_snake_case)]
73impl TextDecoderMethods<crate::DomTypeHolder> for TextDecoder {
74 fn Constructor(
76 global: &GlobalScope,
77 proto: Option<HandleObject>,
78 can_gc: CanGc,
79 label: DOMString,
80 options: &TextDecoderBinding::TextDecoderOptions,
81 ) -> Fallible<DomRoot<TextDecoder>> {
82 let encoding = match Encoding::for_label_no_replacement(label.as_bytes()) {
83 None => return TextDecoder::make_range_error(),
84 Some(enc) => enc,
85 };
86 Ok(TextDecoder::new(
87 global,
88 proto,
89 encoding,
90 options.fatal,
91 options.ignoreBOM,
92 can_gc,
93 ))
94 }
95
96 fn Encoding(&self) -> DOMString {
98 DOMString::from(self.decoder.encoding().name().to_ascii_lowercase())
99 }
100
101 fn Fatal(&self) -> bool {
103 self.decoder.fatal()
104 }
105
106 fn IgnoreBOM(&self) -> bool {
108 self.decoder.ignore_bom()
109 }
110
111 fn Decode(
113 &self,
114 input: Option<ArrayBufferViewOrArrayBuffer>,
115 options: &TextDecodeOptions,
116 ) -> Fallible<USVString> {
117 if !self.do_not_flush.get() {
121 if self.decoder.ignore_bom() {
122 self.decoder
123 .decoder()
124 .replace(self.decoder.encoding().new_decoder_without_bom_handling());
125 } else {
126 self.decoder
127 .decoder()
128 .replace(self.decoder.encoding().new_decoder_with_bom_removal());
129 }
130 self.decoder.io_queue().replace(Vec::new());
131 }
132
133 self.do_not_flush.set(options.stream);
135
136 self.decoder
148 .decode(input.as_ref(), !options.stream)
149 .map(USVString)
150 }
151}