RadioNodeList now reflects changes to the parent, but has room for performance optimization

This commit is contained in:
Patrick Shaughnessy 2020-01-05 12:58:28 -05:00
parent 6b79a8f042
commit d59aed606d
6 changed files with 167 additions and 67 deletions

View file

@ -7,7 +7,9 @@ use crate::dom::bindings::codegen::Bindings::NodeListBinding;
use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlformelement::HTMLFormElement;
use crate::dom::node::{ChildrenMutation, Node};
use crate::dom::window::Window;
use dom_struct::dom_struct;
@ -19,6 +21,7 @@ pub enum NodeListType {
Simple(Vec<Dom<Node>>),
Children(ChildrenList),
Labels(LabelsList),
Radio(RadioList),
}
// https://dom.spec.whatwg.org/#interface-nodelist
@ -83,6 +86,7 @@ impl NodeListMethods for NodeList {
NodeListType::Simple(ref elems) => elems.len() as u32,
NodeListType::Children(ref list) => list.len(),
NodeListType::Labels(ref list) => list.len(),
NodeListType::Radio(ref list) => list.len(),
}
}
@ -94,6 +98,7 @@ impl NodeListMethods for NodeList {
.map(|node| DomRoot::from_ref(&**node)),
NodeListType::Children(ref list) => list.item(index),
NodeListType::Labels(ref list) => list.item(index),
NodeListType::Radio(ref list) => list.item(index),
}
}
@ -108,20 +113,22 @@ impl NodeList {
if let NodeListType::Children(ref list) = self.list_type {
list
} else {
panic!("called as_children_list() on a simple node list")
panic!("called as_children_list() on a non-children node list")
}
}
pub fn as_simple_list(&self) -> &Vec<Dom<Node>> {
if let NodeListType::Simple(ref list) = self.list_type {
pub fn as_radio_list(&self) -> &RadioList {
if let NodeListType::Radio(ref list) = self.list_type {
list
} else {
panic!("called as_simple_list() on a children node list")
panic!("called as_radio_list() on a non-radio node list")
}
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item = DomRoot<Node>> + 'a {
let len = self.Length();
// There is room for optimization here in non-simple cases,
// as calling Item repeatedly on a live list can involve redundant work.
(0..len).flat_map(move |i| self.Item(i))
}
}
@ -328,7 +335,7 @@ impl ChildrenList {
}
}
// Labels lists: There might room for performance optimization
// Labels lists: There might be room for performance optimization
// analogous to the ChildrenMutation case of a children list,
// in which we can keep information from an older access live
// if we know nothing has happened that would change it.
@ -357,3 +364,40 @@ impl LabelsList {
self.element.label_at(index)
}
}
// Radio node lists: There is room for performance improvement here;
// a form is already aware of changes to its set of controls,
// so a radio list can cache and cache-invalidate its contents
// just by hooking into what the form already knows without a
// separate mutation observer. FIXME #25482
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
pub enum RadioListMode {
ControlsExceptImageInputs,
Images,
}
#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
pub struct RadioList {
form: Dom<HTMLFormElement>,
mode: RadioListMode,
name: DOMString,
}
impl RadioList {
pub fn new(form: &HTMLFormElement, mode: RadioListMode, name: DOMString) -> RadioList {
RadioList {
form: Dom::from_ref(form),
mode: mode,
name: name,
}
}
pub fn len(&self) -> u32 {
self.form.count_for_radio_list(self.mode, &self.name)
}
pub fn item(&self, index: u32) -> Option<DomRoot<Node>> {
self.form.nth_for_radio_list(index, self.mode, &self.name)
}
}