script/dom/element/attributes/
accessors.rs1use html5ever::{LocalName, local_name, ns};
6use js::context::JSContext;
7use servo_arc::Arc as ServoArc;
8use style::attr::AttrValue;
9use stylo_atoms::Atom;
10
11use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
12use crate::dom::bindings::codegen::UnionTypes::{TrustedHTMLOrString, TrustedScriptURLOrUSVString};
13use crate::dom::bindings::str::{DOMString, USVString};
14use crate::dom::element::attributes::storage::AttrRef;
15use crate::dom::element::{AttributeMutationReason, Element};
16use crate::dom::node::NodeTraits;
17
18impl Element {
19 pub(crate) fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
20 match self.get_attribute(local_name) {
21 Some(ref attribute) => match *attribute.value() {
22 AttrValue::Int(_, value) => value,
23 _ => unreachable!("Expected an AttrValue::Int: implement parse_plain_attribute"),
24 },
25 None => default,
26 }
27 }
28
29 pub(crate) fn set_atomic_attribute(
30 &self,
31 cx: &mut JSContext,
32 local_name: &LocalName,
33 value: DOMString,
34 ) {
35 self.set_attribute(cx, local_name, AttrValue::from_atomic(value.into()));
36 }
37
38 pub(crate) fn set_bool_attribute(
39 &self,
40 cx: &mut JSContext,
41 local_name: &LocalName,
42 value: bool,
43 ) {
44 if self.has_attribute(local_name) == value {
45 return;
46 }
47 if value {
48 self.set_string_attribute(cx, local_name, DOMString::new());
49 } else {
50 self.remove_attribute(cx, &ns!(), local_name);
51 }
52 }
53
54 pub(crate) fn get_url_attribute(&self, local_name: &LocalName) -> USVString {
55 let Some(attribute) = self.get_attribute(local_name) else {
56 return Default::default();
57 };
58 let value = &**attribute.value();
59 self.owner_document()
60 .encoding_parse_a_url(value)
61 .map(|parsed| USVString(parsed.into_string()))
62 .unwrap_or_else(|_| USVString(value.to_owned()))
63 }
64
65 pub(crate) fn set_url_attribute(
66 &self,
67 cx: &mut JSContext,
68 local_name: &LocalName,
69 value: USVString,
70 ) {
71 self.set_attribute(cx, local_name, AttrValue::String(value.to_string()));
72 }
73
74 pub(crate) fn get_trusted_type_url_attribute(
75 &self,
76 local_name: &LocalName,
77 ) -> TrustedScriptURLOrUSVString {
78 let Some(attribute) = self.get_attribute(local_name) else {
79 return TrustedScriptURLOrUSVString::USVString(USVString::default());
80 };
81 let value = &**attribute.value();
82 self.owner_document()
83 .encoding_parse_a_url(value)
84 .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
85 .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
86 }
87
88 pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
89 TrustedHTMLOrString::String(self.get_string_attribute(local_name))
90 }
91
92 pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
93 self.get_attribute(local_name)
94 .map(|attribute| attribute.Value())
95 .unwrap_or_default()
96 }
97
98 pub(crate) fn set_string_attribute(
99 &self,
100 cx: &mut JSContext,
101 local_name: &LocalName,
102 value: DOMString,
103 ) {
104 self.set_attribute(cx, local_name, AttrValue::String(value.into()));
105 }
106
107 pub(crate) fn get_nullable_string_attribute(
110 &self,
111 local_name: &LocalName,
112 ) -> Option<DOMString> {
113 if self.has_attribute(local_name) {
114 Some(self.get_string_attribute(local_name))
115 } else {
116 None
117 }
118 }
119
120 pub(crate) fn set_nullable_string_attribute(
123 &self,
124 cx: &mut JSContext,
125 local_name: &LocalName,
126 value: Option<DOMString>,
127 ) {
128 match value {
129 Some(val) => {
130 self.set_string_attribute(cx, local_name, val);
131 },
132 None => {
133 self.remove_attribute(cx, &ns!(), local_name);
134 },
135 }
136 }
137
138 pub(crate) fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
139 self.get_attribute(local_name)
140 .map(|attribute| attribute.value().as_tokens().to_vec())
141 .unwrap_or_default()
142 }
143
144 pub(crate) fn set_tokenlist_attribute(
145 &self,
146 cx: &mut JSContext,
147 local_name: &LocalName,
148 value: DOMString,
149 ) {
150 self.set_attribute(
151 cx,
152 local_name,
153 AttrValue::from_serialized_tokenlist(value.into()),
154 );
155 }
156
157 pub(crate) fn set_atomic_tokenlist_attribute(
158 &self,
159 cx: &mut JSContext,
160 local_name: &LocalName,
161 tokens: Vec<Atom>,
162 ) {
163 self.set_attribute(cx, local_name, AttrValue::from_atomic_tokens(tokens));
164 }
165
166 pub(crate) fn set_int_attribute(&self, cx: &mut JSContext, local_name: &LocalName, value: i32) {
167 self.set_attribute(cx, local_name, AttrValue::Int(value.to_string(), value));
168 }
169
170 pub(crate) fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
171 match self.get_attribute(local_name) {
172 Some(ref attribute) => match *attribute.value() {
173 AttrValue::UInt(_, value) => value,
174 _ => unreachable!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
175 },
176 None => default,
177 }
178 }
179
180 pub(crate) fn set_uint_attribute(
181 &self,
182 cx: &mut JSContext,
183 local_name: &LocalName,
184 value: u32,
185 ) {
186 self.set_attribute(cx, local_name, AttrValue::UInt(value.to_string(), value));
187 }
188
189 fn compute_attribute_value_with_style_fast_path(&self, attr: AttrRef<'_>) -> AttrValue {
195 if *attr.local_name() == local_name!("style") {
196 if let Some(ref pdb) = *self.style_attribute().borrow() {
197 let document = self.owner_document();
198 let shared_lock = document.style_shared_lock();
199 let new_pdb = pdb.read_with(&shared_lock.read()).clone();
200 return AttrValue::Declaration(
201 (**attr.value()).to_owned(),
202 ServoArc::new(shared_lock.wrap(new_pdb)),
203 );
204 }
205 }
206
207 attr.value().clone()
208 }
209
210 pub(crate) fn copy_all_attributes_to_other_element(
212 &self,
213 cx: &mut JSContext,
214 target_element: &Element,
215 ) {
216 for attr in self.attrs().borrow().iter() {
218 let new_value = self.compute_attribute_value_with_style_fast_path(attr);
220 target_element.push_new_attribute(
222 cx,
223 attr.local_name().clone(),
224 new_value,
225 attr.name().clone(),
226 attr.namespace().clone(),
227 attr.prefix().cloned(),
228 AttributeMutationReason::ByCloning,
229 );
230 }
231 }
232}