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