diff options
author | Josh Matthews <josh@joshmatthews.net> | 2024-12-26 01:06:09 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-26 06:06:09 +0000 |
commit | 981616f91868de481f55e793a7632e6e133a743e (patch) | |
tree | 59d1f960e7d5e5d407dd80613cc6dc471271c99f /components/script/dom/htmlscriptelement.rs | |
parent | 20d67bdc441eeb61c52c38dd034eaec6504b3b32 (diff) | |
download | servo-981616f91868de481f55e793a7632e6e133a743e.tar.gz servo-981616f91868de481f55e793a7632e6e133a743e.zip |
Don't run scripts while DOM tree is undergoing mutations (#34505)
* script: Implement node insertion post-connection hook. Ensure script elements only run scripts when the DOM has stabilized.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* script: Make iframe element use post-connection steps when handling initial document insertion.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* script: Use a delayed task when running post-connection steps.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* script: Add explanatory comment.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
* Tidy.
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
---------
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components/script/dom/htmlscriptelement.rs')
-rw-r--r-- | components/script/dom/htmlscriptelement.rs | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 4ab12c60df1..244a18568c4 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -55,7 +55,7 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlelement::HTMLElement; use crate::dom::node::{ - document_from_node, window_from_node, BindContext, ChildrenMutation, CloneChildrenFlag, Node, + document_from_node, window_from_node, ChildrenMutation, CloneChildrenFlag, Node, }; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::virtualmethods::VirtualMethods; @@ -1188,25 +1188,32 @@ impl VirtualMethods for HTMLScriptElement { } } + /// <https://html.spec.whatwg.org/multipage/#script-processing-model:the-script-element-26> fn children_changed(&self, mutation: &ChildrenMutation) { if let Some(s) = self.super_type() { s.children_changed(mutation); } - if !self.parser_inserted.get() && self.upcast::<Node>().is_connected() { - self.prepare(CanGc::note()); + + if self.upcast::<Node>().is_connected() && !self.parser_inserted.get() { + let script = Trusted::new(self); + // This method can be invoked while there are script/layout blockers present + // as DOM mutations have not yet settled. We use a delayed task to avoid + // running any scripts until the DOM tree is safe for interactions. + document_from_node(self).add_delayed_task(task!(ScriptPrepare: move || { + let this = script.root(); + this.prepare(CanGc::note()); + })); } } - fn bind_to_tree(&self, context: &BindContext) { + /// <https://html.spec.whatwg.org/multipage/#script-processing-model:the-script-element-20> + fn post_connection_steps(&self) { if let Some(s) = self.super_type() { - s.bind_to_tree(context); + s.post_connection_steps(); } - if context.tree_connected && !self.parser_inserted.get() { - let script = Trusted::new(self); - document_from_node(self).add_delayed_task(task!(ScriptDelayedInitialize: move || { - script.root().prepare(CanGc::note()); - })); + if self.upcast::<Node>().is_connected() && !self.parser_inserted.get() { + self.prepare(CanGc::note()); } } |