Skip to content

Commit 2b2b3ea

Browse files
author
bors-servo
authored
Auto merge of #25572 - pshaughn:atomnames, r=jdm
Make name content attributes consistently atoms and put them in rare_data for fast access <!-- Please describe your changes on the following line: --> All codepaths setting the name content attribute now use an atom, which is also stored in rare_data for direct lookup by a get_name method. Paralleling the get_name method, I added a get_id method, which makes some internal id-lookup cases nicer. A new test tests for a name setter on every HTML element type. In addition to its overt and upstreamable purpose of checking IDL property reflection semantics, for us this test also hits some Servo assertions that make sure the name is an atom in every case. If the test doesn't crash, even a failed test case still has the attribute as an atom rather than some other type. The failed cases are for elements that we have unimplemented or completely stubbed; I added a few missing name IDL properties to otherwise implemented elements. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #25570 and make progress on #25057 <!-- Either: --> - [X] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
2 parents 43c558f + 02a3e59 commit 2b2b3ea

32 files changed

+270
-652
lines changed

components/atoms/static_atoms.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ radio
8484
range
8585
ratechange
8686
readystatechange
87+
referrer
8788
reftest-wait
8889
rejectionhandled
8990
removetrack

components/script/dom/document.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,7 @@ impl Document {
823823
}
824824

825825
fn get_anchor_by_name(&self, name: &str) -> Option<DomRoot<Element>> {
826+
// TODO faster name lookups (see #25548)
826827
let check_anchor = |node: &HTMLAnchorElement| {
827828
let elem = node.upcast::<Element>();
828829
elem.get_attribute(&ns!(), &local_name!("name"))
@@ -4091,9 +4092,7 @@ impl DocumentMethods for Document {
40914092
if element.namespace() != &ns!(html) {
40924093
return false;
40934094
}
4094-
element
4095-
.get_attribute(&ns!(), &local_name!("name"))
4096-
.map_or(false, |attr| &**attr.value() == &*name)
4095+
element.get_name().map_or(false, |atom| *atom == *name)
40974096
})
40984097
}
40994098

@@ -4303,6 +4302,7 @@ impl DocumentMethods for Document {
43034302
}
43044303
// https://html.spec.whatwg.org/multipage/#dom-document-nameditem-filter
43054304
fn filter_by_name(name: &Atom, node: &Node) -> bool {
4305+
// TODO faster name lookups (see #25548)
43064306
let html_elem_type = match node.type_id() {
43074307
NodeTypeId::Element(ElementTypeId::HTMLElement(type_)) => type_,
43084308
_ => return false,

components/script/dom/element.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,11 +1401,28 @@ impl Element {
14011401
// https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
14021402
pub fn get_attribute_by_name(&self, name: DOMString) -> Option<DomRoot<Attr>> {
14031403
let name = &self.parsed_name(name);
1404-
self.attrs
1404+
let maybe_attribute = self
1405+
.attrs
14051406
.borrow()
14061407
.iter()
14071408
.find(|a| a.name() == name)
1408-
.map(|js| DomRoot::from_ref(&**js))
1409+
.map(|js| DomRoot::from_ref(&**js));
1410+
1411+
fn id_and_name_must_be_atoms(name: &LocalName, maybe_attr: &Option<DomRoot<Attr>>) -> bool {
1412+
if *name == local_name!("id") || *name == local_name!("name") {
1413+
match maybe_attr {
1414+
None => true,
1415+
Some(ref attr) => match *attr.value() {
1416+
AttrValue::Atom(_) => true,
1417+
_ => false,
1418+
},
1419+
}
1420+
} else {
1421+
true
1422+
}
1423+
}
1424+
debug_assert!(id_and_name_must_be_atoms(name, &maybe_attribute));
1425+
maybe_attribute
14091426
}
14101427

14111428
pub fn set_attribute_from_parser(
@@ -1800,6 +1817,14 @@ impl Element {
18001817
let other = other.upcast::<Element>();
18011818
self.root_element() == other.root_element()
18021819
}
1820+
1821+
pub fn get_id(&self) -> Option<Atom> {
1822+
self.id_attribute.borrow().clone()
1823+
}
1824+
1825+
pub fn get_name(&self) -> Option<Atom> {
1826+
self.rare_data().as_ref()?.name_attribute.clone()
1827+
}
18031828
}
18041829

18051830
impl ElementMethods for Element {
@@ -1836,6 +1861,8 @@ impl ElementMethods for Element {
18361861
}
18371862

18381863
// https://dom.spec.whatwg.org/#dom-element-id
1864+
// This always returns a string; if you'd rather see None
1865+
// on a null id, call get_id
18391866
fn Id(&self) -> DOMString {
18401867
self.get_string_attribute(&local_name!("id"))
18411868
}
@@ -2783,6 +2810,20 @@ impl VirtualMethods for Element {
27832810
}
27842811
}
27852812
},
2813+
&local_name!("name") => {
2814+
// Keep the name in rare data for fast access
2815+
self.ensure_rare_data().name_attribute =
2816+
mutation.new_value(attr).and_then(|value| {
2817+
let value = value.as_atom();
2818+
if value != &atom!("") {
2819+
Some(value.clone())
2820+
} else {
2821+
None
2822+
}
2823+
});
2824+
// TODO: notify the document about the name change
2825+
// once it has a name_map (#25548)
2826+
},
27862827
_ => {
27872828
// FIXME(emilio): This is pretty dubious, and should be done in
27882829
// the relevant super-classes.
@@ -2801,6 +2842,7 @@ impl VirtualMethods for Element {
28012842
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
28022843
match name {
28032844
&local_name!("id") => AttrValue::from_atomic(value.into()),
2845+
&local_name!("name") => AttrValue::from_atomic(value.into()),
28042846
&local_name!("class") => AttrValue::from_serialized_tokenlist(value.into()),
28052847
_ => self
28062848
.super_type()

components/script/dom/htmlanchorelement.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl HTMLAnchorElementMethods for HTMLAnchorElement {
152152
make_getter!(Name, "name");
153153

154154
// https://html.spec.whatwg.org/multipage/#dom-a-name
155-
make_setter!(SetName, "name");
155+
make_atomic_setter!(SetName, "name");
156156

157157
// https://html.spec.whatwg.org/multipage/#dom-a-rev
158158
make_getter!(Rev, "rev");

components/script/dom/htmlbuttonelement.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl HTMLButtonElementMethods for HTMLButtonElement {
142142
make_getter!(Name, "name");
143143

144144
// https://html.spec.whatwg.org/multipage/#dom-fe-name
145-
make_setter!(SetName, "name");
145+
make_atomic_setter!(SetName, "name");
146146

147147
// https://html.spec.whatwg.org/multipage/#dom-button-value
148148
make_getter!(Value, "value");

components/script/dom/htmlcollection.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,12 @@ impl HTMLCollectionMethods for HTMLCollection {
366366
return None;
367367
}
368368

369+
let key = Atom::from(key);
370+
369371
// Step 2.
370372
self.elements_iter().find(|elem| {
371-
elem.get_string_attribute(&local_name!("id")) == key ||
372-
(elem.namespace() == &ns!(html) &&
373-
elem.get_string_attribute(&local_name!("name")) == key)
373+
elem.get_id().map_or(false, |id| id == key) ||
374+
(elem.namespace() == &ns!(html) && elem.get_name().map_or(false, |id| id == key))
374375
})
375376
}
376377

@@ -392,17 +393,20 @@ impl HTMLCollectionMethods for HTMLCollection {
392393
// Step 2
393394
for elem in self.elements_iter() {
394395
// Step 2.1
395-
let id_attr = elem.get_string_attribute(&local_name!("id"));
396-
if !id_attr.is_empty() && !result.contains(&id_attr) {
397-
result.push(id_attr)
396+
if let Some(id_atom) = elem.get_id() {
397+
let id_str = DOMString::from(&*id_atom);
398+
if !result.contains(&id_str) {
399+
result.push(id_str);
400+
}
398401
}
399402
// Step 2.2
400-
let name_attr = elem.get_string_attribute(&local_name!("name"));
401-
if !name_attr.is_empty() &&
402-
!result.contains(&name_attr) &&
403-
*elem.namespace() == ns!(html)
404-
{
405-
result.push(name_attr)
403+
if *elem.namespace() == ns!(html) {
404+
if let Some(name_atom) = elem.get_name() {
405+
let name_str = DOMString::from(&*name_atom);
406+
if !result.contains(&name_str) {
407+
result.push(name_str)
408+
}
409+
}
406410
}
407411
}
408412

components/script/dom/htmlfieldsetelement.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding;
77
use crate::dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding::HTMLFieldSetElementMethods;
88
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
99
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
10+
use crate::dom::bindings::str::DOMString;
1011
use crate::dom::document::Document;
1112
use crate::dom::element::{AttributeMutation, Element};
1213
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
@@ -88,6 +89,12 @@ impl HTMLFieldSetElementMethods for HTMLFieldSetElement {
8889
// https://html.spec.whatwg.org/multipage/#dom-fieldset-disabled
8990
make_bool_setter!(SetDisabled, "disabled");
9091

92+
// https://html.spec.whatwg.org/multipage/#dom-fe-name
93+
make_atomic_setter!(SetName, "name");
94+
95+
// https://html.spec.whatwg.org/multipage/#dom-fe-name
96+
make_getter!(Name, "name");
97+
9198
// https://html.spec.whatwg.org/multipage/#dom-fae-form
9299
fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
93100
self.form_owner()

components/script/dom/htmlformcontrolscollection.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::dom::node::Node;
1818
use crate::dom::radionodelist::RadioNodeList;
1919
use crate::dom::window::Window;
2020
use dom_struct::dom_struct;
21+
use servo_atoms::Atom;
2122

2223
#[dom_struct]
2324
pub struct HTMLFormControlsCollection {
@@ -67,9 +68,11 @@ impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
6768
return None;
6869
}
6970

71+
let name = Atom::from(name);
72+
7073
let mut filter_map = self.collection.elements_iter().filter_map(|elem| {
71-
if elem.get_string_attribute(&local_name!("name")) == name ||
72-
elem.get_string_attribute(&local_name!("id")) == name
74+
if elem.get_name().map_or(false, |n| n == name) ||
75+
elem.get_id().map_or(false, |i| i == name)
7376
{
7477
Some(elem)
7578
} else {
@@ -90,7 +93,7 @@ impl HTMLFormControlsCollectionMethods for HTMLFormControlsCollection {
9093
// specifically HTMLFormElement::Elements(),
9194
// and the collection filter excludes image inputs.
9295
Some(RadioNodeListOrElement::RadioNodeList(
93-
RadioNodeList::new_controls_except_image_inputs(window, &*self.form, name),
96+
RadioNodeList::new_controls_except_image_inputs(window, &*self.form, &name),
9497
))
9598
}
9699
// Step 3

0 commit comments

Comments
 (0)