diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-12-18 09:03:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-18 08:03:50 +0000 |
commit | 9d986a8ab3cf180e966bed0bc7c20f5f66c6711a (patch) | |
tree | 8976cbbf6275b9fedb76a685f46da7cfa86eadd0 /components | |
parent | d54b68bc96eab9d90b2d9d9f42bde33d33123cfd (diff) | |
download | servo-9d986a8ab3cf180e966bed0bc7c20f5f66c6711a.tar.gz servo-9d986a8ab3cf180e966bed0bc7c20f5f66c6711a.zip |
script: Expose a constructor on `HTMLCollection` that takes a static function (#34667)
Expose a new constructor on `HTMLCollection`, `new_with_filter_fn`, that
filters elements using a simple static function -- a common pattern.
This allows more easily creating this `HTMLCollection` without having to
create a new data structure. Since the constructor takes a static
function, no data should be captured preventing garbage collection
issues.
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/document.rs | 80 | ||||
-rw-r--r-- | components/script/dom/htmlcollection.rs | 47 | ||||
-rw-r--r-- | components/script/dom/htmldatalistelement.rs | 16 | ||||
-rw-r--r-- | components/script/dom/htmlfieldsetelement.rs | 18 | ||||
-rw-r--r-- | components/script/dom/htmltableelement.rs | 22 | ||||
-rw-r--r-- | components/script/dom/htmltablerowelement.rs | 22 | ||||
-rw-r--r-- | components/script/dom/htmltablesectionelement.rs | 20 |
7 files changed, 90 insertions, 135 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 2f939a471a2..de06f82dc0e 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -497,55 +497,6 @@ pub struct Document { status_code: Option<u16>, } -#[derive(JSTraceable, MallocSizeOf)] -struct ImagesFilter; -impl CollectionFilter for ImagesFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLImageElement>() - } -} - -#[derive(JSTraceable, MallocSizeOf)] -struct EmbedsFilter; -impl CollectionFilter for EmbedsFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLEmbedElement>() - } -} - -#[derive(JSTraceable, MallocSizeOf)] -struct LinksFilter; -impl CollectionFilter for LinksFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - (elem.is::<HTMLAnchorElement>() || elem.is::<HTMLAreaElement>()) && - elem.has_attribute(&local_name!("href")) - } -} - -#[derive(JSTraceable, MallocSizeOf)] -struct FormsFilter; -impl CollectionFilter for FormsFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLFormElement>() - } -} - -#[derive(JSTraceable, MallocSizeOf)] -struct ScriptsFilter; -impl CollectionFilter for ScriptsFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLScriptElement>() - } -} - -#[derive(JSTraceable, MallocSizeOf)] -struct AnchorsFilter; -impl CollectionFilter for AnchorsFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLAnchorElement>() && elem.has_attribute(&local_name!("href")) - } -} - #[allow(non_snake_case)] impl Document { pub fn note_node_with_dirty_descendants(&self, node: &Node) { @@ -4907,16 +4858,18 @@ impl DocumentMethods<crate::DomTypeHolder> for Document { // https://html.spec.whatwg.org/multipage/#dom-document-images fn Images(&self) -> DomRoot<HTMLCollection> { self.images.or_init(|| { - let filter = Box::new(ImagesFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + element.is::<HTMLImageElement>() + }) }) } // https://html.spec.whatwg.org/multipage/#dom-document-embeds fn Embeds(&self) -> DomRoot<HTMLCollection> { self.embeds.or_init(|| { - let filter = Box::new(EmbedsFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + element.is::<HTMLEmbedElement>() + }) }) } @@ -4928,32 +4881,37 @@ impl DocumentMethods<crate::DomTypeHolder> for Document { // https://html.spec.whatwg.org/multipage/#dom-document-links fn Links(&self) -> DomRoot<HTMLCollection> { self.links.or_init(|| { - let filter = Box::new(LinksFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + (element.is::<HTMLAnchorElement>() || element.is::<HTMLAreaElement>()) && + element.has_attribute(&local_name!("href")) + }) }) } // https://html.spec.whatwg.org/multipage/#dom-document-forms fn Forms(&self) -> DomRoot<HTMLCollection> { self.forms.or_init(|| { - let filter = Box::new(FormsFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + element.is::<HTMLFormElement>() + }) }) } // https://html.spec.whatwg.org/multipage/#dom-document-scripts fn Scripts(&self) -> DomRoot<HTMLCollection> { self.scripts.or_init(|| { - let filter = Box::new(ScriptsFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + element.is::<HTMLScriptElement>() + }) }) } // https://html.spec.whatwg.org/multipage/#dom-document-anchors fn Anchors(&self) -> DomRoot<HTMLCollection> { self.anchors.or_init(|| { - let filter = Box::new(AnchorsFilter); - HTMLCollection::create(&self.window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&self.window, self.upcast(), |element, _| { + element.is::<HTMLAnchorElement>() && element.has_attribute(&local_name!("href")) + }) }) } diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs index b0659484b5a..5e2c1130b21 100644 --- a/components/script/dom/htmlcollection.rs +++ b/components/script/dom/htmlcollection.rs @@ -104,20 +104,46 @@ impl HTMLCollection { window: &Window, root: &Node, filter: Box<dyn CollectionFilter + 'static>, - ) -> DomRoot<HTMLCollection> { + ) -> DomRoot<Self> { reflect_dom_object( - Box::new(HTMLCollection::new_inherited(root, filter)), + Box::new(Self::new_inherited(root, filter)), window, CanGc::note(), ) } - pub fn create( + /// Create a new [`HTMLCollection`] that just filters element using a static function. + pub(crate) fn new_with_filter_fn( + window: &Window, + root: &Node, + filter_function: fn(&Element, &Node) -> bool, + ) -> DomRoot<Self> { + #[derive(JSTraceable, MallocSizeOf)] + pub(crate) struct StaticFunctionFilter( + // The function *must* be static so that it never holds references to DOM objects, which + // would cause issues with garbage collection -- since it isn't traced. + #[no_trace] + #[ignore_malloc_size_of = "Static function pointer"] + fn(&Element, &Node) -> bool, + ); + impl CollectionFilter for StaticFunctionFilter { + fn filter(&self, element: &Element, root: &Node) -> bool { + (self.0)(element, root) + } + } + Self::new( + window, + root, + Box::new(StaticFunctionFilter(filter_function)), + ) + } + + pub(crate) fn create( window: &Window, root: &Node, filter: Box<dyn CollectionFilter + 'static>, - ) -> DomRoot<HTMLCollection> { - HTMLCollection::new(window, root, filter) + ) -> DomRoot<Self> { + Self::new(window, root, filter) } fn validate_cache(&self) { @@ -275,14 +301,9 @@ impl HTMLCollection { } pub fn children(window: &Window, root: &Node) -> DomRoot<HTMLCollection> { - #[derive(JSTraceable, MallocSizeOf)] - struct ElementChildFilter; - impl CollectionFilter for ElementChildFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - root.is_parent_of(elem.upcast()) - } - } - HTMLCollection::create(window, root, Box::new(ElementChildFilter)) + HTMLCollection::new_with_filter_fn(window, root, |element, root| { + root.is_parent_of(element.upcast()) + }) } pub fn elements_iter_after<'a>( diff --git a/components/script/dom/htmldatalistelement.rs b/components/script/dom/htmldatalistelement.rs index e27d6aa969c..c54c5c41298 100644 --- a/components/script/dom/htmldatalistelement.rs +++ b/components/script/dom/htmldatalistelement.rs @@ -10,8 +10,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLDataListElementBinding::HTMLDat use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::root::DomRoot; use crate::dom::document::Document; -use crate::dom::element::Element; -use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; +use crate::dom::htmlcollection::HTMLCollection; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmloptionelement::HTMLOptionElement; use crate::dom::node::{window_from_node, Node}; @@ -55,15 +54,8 @@ impl HTMLDataListElement { impl HTMLDataListElementMethods<crate::DomTypeHolder> for HTMLDataListElement { // https://html.spec.whatwg.org/multipage/#dom-datalist-options fn Options(&self) -> DomRoot<HTMLCollection> { - #[derive(JSTraceable, MallocSizeOf)] - struct HTMLDataListOptionsFilter; - impl CollectionFilter for HTMLDataListOptionsFilter { - fn filter(&self, elem: &Element, _root: &Node) -> bool { - elem.is::<HTMLOptionElement>() - } - } - let filter = Box::new(HTMLDataListOptionsFilter); - let window = window_from_node(self); - HTMLCollection::create(&window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&window_from_node(self), self.upcast(), |element, _| { + element.is::<HTMLOptionElement>() + }) } } diff --git a/components/script/dom/htmlfieldsetelement.rs b/components/script/dom/htmlfieldsetelement.rs index d6f4f95fe6b..ee91fa4c6ba 100644 --- a/components/script/dom/htmlfieldsetelement.rs +++ b/components/script/dom/htmlfieldsetelement.rs @@ -17,7 +17,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::customelementregistry::CallbackReaction; use crate::dom::document::Document; use crate::dom::element::{AttributeMutation, Element}; -use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; +use crate::dom::htmlcollection::HTMLCollection; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlformelement::{FormControl, HTMLFormElement}; use crate::dom::htmllegendelement::HTMLLegendElement; @@ -88,17 +88,11 @@ impl HTMLFieldSetElement { impl HTMLFieldSetElementMethods<crate::DomTypeHolder> for HTMLFieldSetElement { // https://html.spec.whatwg.org/multipage/#dom-fieldset-elements fn Elements(&self) -> DomRoot<HTMLCollection> { - #[derive(JSTraceable, MallocSizeOf)] - struct ElementsFilter; - impl CollectionFilter for ElementsFilter { - fn filter<'a>(&self, elem: &'a Element, _root: &'a Node) -> bool { - elem.downcast::<HTMLElement>() - .is_some_and(HTMLElement::is_listed_element) - } - } - let filter = Box::new(ElementsFilter); - let window = window_from_node(self); - HTMLCollection::create(&window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn(&window_from_node(self), self.upcast(), |element, _| { + element + .downcast::<HTMLElement>() + .is_some_and(HTMLElement::is_listed_element) + }) } // https://html.spec.whatwg.org/multipage/#dom-fieldset-disabled diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index b4b3fceed9d..6699bc5975a 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -300,20 +300,16 @@ impl HTMLTableElementMethods<crate::DomTypeHolder> for HTMLTableElement { // https://html.spec.whatwg.org/multipage/#dom-table-tbodies fn TBodies(&self) -> DomRoot<HTMLCollection> { - #[derive(JSTraceable)] - struct TBodiesFilter; - impl CollectionFilter for TBodiesFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - elem.is::<HTMLTableSectionElement>() && - elem.local_name() == &local_name!("tbody") && - elem.upcast::<Node>().GetParentNode().as_deref() == Some(root) - } - } - self.tbodies.or_init(|| { - let window = window_from_node(self); - let filter = Box::new(TBodiesFilter); - HTMLCollection::create(&window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn( + &window_from_node(self), + self.upcast(), + |element, root| { + element.is::<HTMLTableSectionElement>() && + element.local_name() == &local_name!("tbody") && + element.upcast::<Node>().GetParentNode().as_deref() == Some(root) + }, + ) }) } diff --git a/components/script/dom/htmltablerowelement.rs b/components/script/dom/htmltablerowelement.rs index 790dce4dd73..00627511502 100644 --- a/components/script/dom/htmltablerowelement.rs +++ b/components/script/dom/htmltablerowelement.rs @@ -18,7 +18,7 @@ use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::{Element, LayoutElementHelpers}; -use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; +use crate::dom::htmlcollection::HTMLCollection; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmltablecellelement::HTMLTableCellElement; use crate::dom::htmltableelement::HTMLTableElement; @@ -27,15 +27,6 @@ use crate::dom::node::{window_from_node, Node}; use crate::dom::virtualmethods::VirtualMethods; use crate::script_runtime::CanGc; -#[derive(JSTraceable)] -struct CellsFilter; -impl CollectionFilter for CellsFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - (elem.is::<HTMLTableCellElement>()) && - elem.upcast::<Node>().GetParentNode().as_deref() == Some(root) - } -} - #[dom_struct] pub struct HTMLTableRowElement { htmlelement: HTMLElement, @@ -95,9 +86,14 @@ impl HTMLTableRowElementMethods<crate::DomTypeHolder> for HTMLTableRowElement { // https://html.spec.whatwg.org/multipage/#dom-tr-cells fn Cells(&self) -> DomRoot<HTMLCollection> { self.cells.or_init(|| { - let window = window_from_node(self); - let filter = Box::new(CellsFilter); - HTMLCollection::create(&window, self.upcast(), filter) + HTMLCollection::new_with_filter_fn( + &window_from_node(self), + self.upcast(), + |element, root| { + (element.is::<HTMLTableCellElement>()) && + element.upcast::<Node>().GetParentNode().as_deref() == Some(root) + }, + ) }) } diff --git a/components/script/dom/htmltablesectionelement.rs b/components/script/dom/htmltablesectionelement.rs index de6803ead41..55cfca59675 100644 --- a/components/script/dom/htmltablesectionelement.rs +++ b/components/script/dom/htmltablesectionelement.rs @@ -16,7 +16,7 @@ use crate::dom::bindings::root::{DomRoot, LayoutDom}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::element::{Element, LayoutElementHelpers}; -use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection}; +use crate::dom::htmlcollection::HTMLCollection; use crate::dom::htmlelement::HTMLElement; use crate::dom::htmltablerowelement::HTMLTableRowElement; use crate::dom::node::{window_from_node, Node}; @@ -61,19 +61,17 @@ impl HTMLTableSectionElement { } } -#[derive(JSTraceable)] -struct RowsFilter; -impl CollectionFilter for RowsFilter { - fn filter(&self, elem: &Element, root: &Node) -> bool { - elem.is::<HTMLTableRowElement>() && - elem.upcast::<Node>().GetParentNode().as_deref() == Some(root) - } -} - impl HTMLTableSectionElementMethods<crate::DomTypeHolder> for HTMLTableSectionElement { // https://html.spec.whatwg.org/multipage/#dom-tbody-rows fn Rows(&self) -> DomRoot<HTMLCollection> { - HTMLCollection::create(&window_from_node(self), self.upcast(), Box::new(RowsFilter)) + HTMLCollection::new_with_filter_fn( + &window_from_node(self), + self.upcast(), + |element, root| { + element.is::<HTMLTableRowElement>() && + element.upcast::<Node>().GetParentNode().as_deref() == Some(root) + }, + ) } // https://html.spec.whatwg.org/multipage/#dom-tbody-insertrow |