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