script/dom/
textencoder.rs1use std::ptr;
6
7use dom_struct::dom_struct;
8use js::gc::CustomAutoRooterGuard;
9use js::jsapi::JSObject;
10use js::rust::HandleObject;
11use js::typedarray;
12use js::typedarray::Uint8Array;
13
14use crate::dom::bindings::buffer_source::create_buffer_source;
15use crate::dom::bindings::codegen::Bindings::TextEncoderBinding::{
16 TextEncoderEncodeIntoResult, TextEncoderMethods,
17};
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::str::{DOMString, USVString};
22use crate::dom::globalscope::GlobalScope;
23use crate::script_runtime::{CanGc, JSContext};
24
25#[dom_struct]
26pub(crate) struct TextEncoder {
27 reflector_: Reflector,
28}
29
30impl TextEncoder {
31 fn new_inherited() -> TextEncoder {
32 TextEncoder {
33 reflector_: Reflector::new(),
34 }
35 }
36
37 fn new(
38 global: &GlobalScope,
39 proto: Option<HandleObject>,
40 can_gc: CanGc,
41 ) -> DomRoot<TextEncoder> {
42 reflect_dom_object_with_proto(
43 Box::new(TextEncoder::new_inherited()),
44 global,
45 proto,
46 can_gc,
47 )
48 }
49}
50
51impl TextEncoderMethods<crate::DomTypeHolder> for TextEncoder {
52 fn Constructor(
54 global: &GlobalScope,
55 proto: Option<HandleObject>,
56 can_gc: CanGc,
57 ) -> Fallible<DomRoot<TextEncoder>> {
58 Ok(TextEncoder::new(global, proto, can_gc))
59 }
60
61 fn Encoding(&self) -> DOMString {
63 DOMString::from("utf-8")
64 }
65
66 fn Encode(&self, cx: JSContext, input: USVString, can_gc: CanGc) -> Uint8Array {
68 let encoded = input.0.as_bytes();
69
70 rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
71 create_buffer_source(cx, encoded, js_object.handle_mut(), can_gc)
72 .expect("Converting input to uint8 array should never fail")
73 }
74
75 #[allow(unsafe_code)]
77 fn EncodeInto(
78 &self,
79 source: USVString,
80 mut destination: CustomAutoRooterGuard<typedarray::Uint8Array>,
81 ) -> TextEncoderEncodeIntoResult {
82 let available = destination.len();
83
84 if available == 0 {
86 return TextEncoderEncodeIntoResult {
87 read: Some(0),
88 written: Some(0),
89 };
90 }
91
92 let mut read = 0;
93 let mut written = 0;
94
95 let dest = unsafe { destination.as_mut_slice() };
96
97 for result in source.0.chars() {
101 let utf8_len = result.len_utf8();
102 if available - written >= utf8_len {
103 read += if result > '\u{FFFF}' { 2 } else { 1 };
106
107 let target = &mut dest[written..written + utf8_len];
109 result.encode_utf8(target);
110
111 written += utf8_len;
113 } else {
114 break;
117 }
118 }
119
120 TextEncoderEncodeIntoResult {
121 read: Some(read),
122 written: Some(written as _),
123 }
124 }
125}