script: Cache the <iframe> list per-Document (#34702)

This change creates a new struct `IFrameCollection` that is used to
cache the list of `<iframe>`s in a `Document` as long as the
`Document`'s DOM has not changed. This prevent constantly iterating the
entire DOM during *update the rendering*, which runs up to 60 times per
second as well as for other operations.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2024-12-20 12:46:46 +01:00 committed by GitHub
parent adfee3daa5
commit a5c461146f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 225 additions and 107 deletions

View file

@ -55,8 +55,12 @@ impl DocumentCollection {
pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
) -> Option<DomRoot<HTMLIFrameElement>> {
self.find_document(pipeline_id)
.and_then(|doc| doc.find_iframe(browsing_context_id))
self.find_document(pipeline_id).and_then(|document| {
document
.iframes()
.get(browsing_context_id)
.map(|iframe| iframe.element.as_rooted())
})
}
pub fn iter(&self) -> DocumentsIter<'_> {
@ -83,9 +87,6 @@ impl DocumentCollection {
///
/// [update-the-rendering]: https://html.spec.whatwg.org/multipage/#update-the-rendering
pub(crate) fn documents_in_order(&self) -> Vec<PipelineId> {
// TODO: This is a fairly expensive operation, because iterating iframes requires walking
// the *entire* DOM for a document. Instead this should be cached and marked as dirty when
// the DOM of a document changes or documents are added or removed from our set.
DocumentTree::new(self).documents_in_order()
}
}
@ -140,7 +141,8 @@ impl DocumentTree {
let mut tree = DocumentTree::default();
for (id, document) in documents.iter() {
let children: Vec<PipelineId> = document
.iter_iframes()
.iframes()
.iter()
.filter_map(|iframe| iframe.pipeline_id())
.filter(|iframe_pipeline_id| documents.find_document(*iframe_pipeline_id).is_some())
.collect();