mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
script: Only register one image callback per CSS image in use. (#36612)
When layout encounters a CSS image, the script thread is responsible for fetching the image from the image cache. When the image is not yet available, the script thread creates image cache listeners to perform actions in response to future updates from the image cache. In the current implementation, a cache listener would iterate over all nodes using a particular image and mark them as dirty. However, we mistakenly added one cache listener per node, leading to n^2 runtime while performing lots of redundant work. For cases like #36480 with over 1000 elements using the same image, this led to a completely unresponsive script thread. Testing: Manual testing on the provided testcase, and a new WPT test that times out without this PR's changes. Fixes: #36480 Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
c486c6f058
commit
3ab5b8c447
3 changed files with 34 additions and 2 deletions
|
@ -2019,8 +2019,7 @@ impl Window {
|
|||
}
|
||||
|
||||
let mut images = self.pending_layout_images.borrow_mut();
|
||||
let nodes = images.entry(id).or_default();
|
||||
if !nodes.iter().any(|n| std::ptr::eq(&**n, &*node)) {
|
||||
if !images.contains_key(&id) {
|
||||
let trusted_node = Trusted::new(&*node);
|
||||
let sender = self.register_image_cache_listener(id, move |response| {
|
||||
trusted_node
|
||||
|
@ -2031,6 +2030,10 @@ impl Window {
|
|||
|
||||
self.image_cache
|
||||
.add_listener(ImageResponder::new(sender, self.pipeline_id(), id));
|
||||
}
|
||||
|
||||
let nodes = images.entry(id).or_default();
|
||||
if !nodes.iter().any(|n| std::ptr::eq(&**n, &*node)) {
|
||||
nodes.push(Dom::from_ref(&*node));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue