Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6d7d185

Browse files
authored
script: Introduce Element::get_attribute_string_value (servo#45023)
Not all accesses to attributes require a `cx`, since most of them don't actually need the `Attr` node, but only the value contained within. Therefore, introduce a variant that directly accesses the value, to avoid materializing attribute nodes. Doing so removes the need for one of the `temp_cx` in XPath, since it only requires the attribute value and not the full node. Part of servo#45022 Testing: WPT Signed-off-by: Tim van der Lippe <[email protected]>
1 parent 5491975 commit 6d7d185

5 files changed

Lines changed: 50 additions & 35 deletions

File tree

components/script/dom/element/attributes/accessors.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use servo_arc::Arc as ServoArc;
88
use style::attr::AttrValue;
99
use stylo_atoms::Atom;
1010

11-
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
1211
use crate::dom::bindings::codegen::UnionTypes::{TrustedHTMLOrString, TrustedScriptURLOrUSVString};
1312
use crate::dom::bindings::str::{DOMString, USVString};
1413
use crate::dom::element::attributes::storage::AttrRef;
@@ -90,8 +89,8 @@ impl Element {
9089
}
9190

9291
pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
93-
self.get_attribute(local_name)
94-
.map(|attribute| attribute.Value())
92+
self.get_attribute_string_value(local_name)
93+
.map(|value| value.into())
9594
.unwrap_or_default()
9695
}
9796

components/script/dom/element/element.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,30 @@ impl Element {
20302030
self.handle_attribute_changes(cx, AttrRef::Dom(attr), None, Some(&*attr.value()), reason);
20312031
}
20322032

2033+
pub(crate) fn get_attribute_string_value(&self, local_name: &LocalName) -> Option<String> {
2034+
debug_assert_eq!(
2035+
*local_name,
2036+
local_name.to_ascii_lowercase(),
2037+
"All namespace-less attribute accesses should use a lowercase ASCII name"
2038+
);
2039+
2040+
self.get_attribute_string_value_with_namespace(&ns!(), local_name)
2041+
}
2042+
2043+
pub(crate) fn get_attribute_string_value_with_namespace(
2044+
&self,
2045+
namespace: &Namespace,
2046+
local_name: &LocalName,
2047+
) -> Option<String> {
2048+
self.attrs
2049+
.borrow()
2050+
.iter()
2051+
.find(|attribute| {
2052+
attribute.local_name() == local_name && attribute.namespace() == namespace
2053+
})
2054+
.map(|attribute| String::from(&**attribute.value()))
2055+
}
2056+
20332057
/// This is the inner logic for:
20342058
/// <https://dom.spec.whatwg.org/#concept-element-attributes-get-by-namespace>
20352059
///
@@ -5104,9 +5128,9 @@ impl TagName {
51045128
/// <https://html.spec.whatwg.org/multipage/#cors-settings-attribute>
51055129
pub(crate) fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
51065130
element
5107-
.get_attribute(&local_name!("crossorigin"))
5108-
.map(|attribute| {
5109-
let value = attribute.value().to_ascii_lowercase();
5131+
.get_attribute_string_value(&local_name!("crossorigin"))
5132+
.map(|value| {
5133+
let value = value.to_ascii_lowercase();
51105134
if value == "anonymous" || value == "use-credentials" {
51115135
DOMString::from(value)
51125136
} else {
@@ -5131,9 +5155,9 @@ pub(crate) fn set_cross_origin_attribute(
51315155
/// <https://html.spec.whatwg.org/multipage/#referrer-policy-attribute>
51325156
pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString {
51335157
element
5134-
.get_attribute(&local_name!("referrerpolicy"))
5135-
.map(|attribute| {
5136-
let value = attribute.value().to_ascii_lowercase();
5158+
.get_attribute_string_value(&local_name!("referrerpolicy"))
5159+
.map(|value| {
5160+
let value = value.to_ascii_lowercase();
51375161
if value == "no-referrer" ||
51385162
value == "no-referrer-when-downgrade" ||
51395163
value == "same-origin" ||
@@ -5153,23 +5177,23 @@ pub(crate) fn reflect_referrer_policy_attribute(element: &Element) -> DOMString
51535177

51545178
pub(crate) fn referrer_policy_for_element(element: &Element) -> ReferrerPolicy {
51555179
element
5156-
.get_attribute(&local_name!("referrerpolicy"))
5157-
.map(|attribute| ReferrerPolicy::from(&**attribute.value()))
5180+
.get_attribute_string_value(&local_name!("referrerpolicy"))
5181+
.map(|value| ReferrerPolicy::from(value.as_ref()))
51585182
.unwrap_or(element.owner_document().get_referrer_policy())
51595183
}
51605184

51615185
pub(crate) fn cors_setting_for_element(element: &Element) -> Option<CorsSettings> {
51625186
element
5163-
.get_attribute(&local_name!("crossorigin"))
5164-
.map(|attribute| CorsSettings::from_enumerated_attribute(&attribute.value()))
5187+
.get_attribute_string_value(&local_name!("crossorigin"))
5188+
.map(|value| CorsSettings::from_enumerated_attribute(value.as_ref()))
51655189
}
51665190

51675191
/// <https://html.spec.whatwg.org/multipage/#cors-settings-attribute-credentials-mode>
51685192
pub(crate) fn cors_settings_attribute_credential_mode(element: &Element) -> CredentialsMode {
51695193
element
5170-
.get_attribute(&local_name!("crossorigin"))
5171-
.map(|attr| {
5172-
if attr.value().eq_ignore_ascii_case("use-credentials") {
5194+
.get_attribute_string_value(&local_name!("crossorigin"))
5195+
.map(|value| {
5196+
if value.eq_ignore_ascii_case("use-credentials") {
51735197
CredentialsMode::Include
51745198
} else {
51755199
// The attribute's invalid value default and empty value default are both the Anonymous state.

components/script/dom/node/node.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,13 +1922,12 @@ impl Node {
19221922
}
19231923

19241924
/// <https://html.spec.whatwg.org/multipage/#language>
1925-
pub(crate) fn get_lang(&self, cx: &mut JSContext) -> Option<String> {
1925+
pub(crate) fn get_lang(&self) -> Option<String> {
19261926
self.inclusive_ancestors(ShadowIncluding::Yes)
19271927
.find_map(|node| {
19281928
node.downcast::<Element>().and_then(|el| {
1929-
el.get_attribute_with_namespace(cx, &ns!(xml), &local_name!("lang"))
1930-
.or_else(|| el.get_attribute(&local_name!("lang")))
1931-
.map(|attr| String::from(attr.Value()))
1929+
el.get_attribute_string_value_with_namespace(&ns!(xml), &local_name!("lang"))
1930+
.or_else(|| el.get_attribute_string_value(&local_name!("lang")))
19321931
})
19331932
// TODO: Check meta tags for a pragma-set default language
19341933
// TODO: Check HTTP Content-Language header

components/script/links.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use net_traits::request::Referrer;
1111
use servo_constellation_traits::{LoadData, LoadOrigin, NavigationHistoryBehavior};
1212
use style::str::HTML_SPACE_CHARACTERS;
1313

14-
use crate::dom::bindings::codegen::Bindings::AttrBinding::Attr_Binding::AttrMethods;
1514
use crate::dom::bindings::inheritance::Castable;
1615
use crate::dom::bindings::refcounted::Trusted;
1716
use crate::dom::bindings::str::DOMString;
@@ -183,10 +182,7 @@ impl LinkRelations {
183182
/// [`<area>`]: https://html.spec.whatwg.org/multipage/#the-area-element
184183
/// [`<form>`]: https://html.spec.whatwg.org/multipage/#the-form-element
185184
pub(crate) fn for_element(element: &Element) -> Self {
186-
let rel = element.get_attribute(&local_name!("rel")).map(|e| {
187-
let value = e.value();
188-
(**value).to_owned()
189-
});
185+
let rel = element.get_attribute_string_value(&local_name!("rel"));
190186

191187
let mut relations = rel
192188
.map(|attribute| {
@@ -199,8 +195,8 @@ impl LinkRelations {
199195

200196
// For historical reasons, "rev=made" is treated as if the "author" relation was specified
201197
let has_legacy_author_relation = element
202-
.get_attribute(&local_name!("rev"))
203-
.is_some_and(|rev| &**rev.value() == "made");
198+
.get_attribute_string_value(&local_name!("rev"))
199+
.is_some_and(|rev| rev == "made");
204200
if has_legacy_author_relation {
205201
relations |= Self::AUTHOR;
206202
}
@@ -459,14 +455,15 @@ pub(crate) fn follow_hyperlink(
459455
// Step 9: Let urlString be the result of applying the URL serializer to urlRecord.
460456
// TODO: Implement this.
461457

462-
let attribute = subject.get_attribute(&local_name!("href")).unwrap();
463-
let mut href = attribute.Value();
458+
let mut href = subject
459+
.get_attribute_string_value(&local_name!("href"))
460+
.unwrap();
464461

465462
// Step 10: If hyperlinkSuffix is non-null, then append it to urlString.
466463
if let Some(suffix) = hyperlink_suffix {
467464
href.push_str(&suffix);
468465
}
469-
let Ok(url) = document.encoding_parse_a_url(&href.str()) else {
466+
let Ok(url) = document.encoding_parse_a_url(&href) else {
470467
return;
471468
};
472469

components/script/xpath.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,8 @@ impl xpath::Node for XPathWrapper<DomRoot<Node>> {
6565
self.0.GetTextContent().unwrap_or_default().into()
6666
}
6767

68-
#[expect(unsafe_code)]
6968
fn language(&self) -> Option<String> {
70-
let mut cx = unsafe { script_bindings::script_runtime::temp_cx() };
71-
let cx = &mut cx;
72-
73-
self.0.get_lang(cx)
69+
self.0.get_lang()
7470
}
7571

7672
fn parent(&self) -> Option<Self> {

0 commit comments

Comments
 (0)