aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/bindings/callback.rs6
-rw-r--r--components/script/dom/document.rs20
-rw-r--r--components/script/dom/node.rs12
-rw-r--r--components/script/dom/window.rs2
4 files changed, 40 insertions, 0 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs
index 2cd289d29c9..88bb02ce44e 100644
--- a/components/script/dom/bindings/callback.rs
+++ b/components/script/dom/bindings/callback.rs
@@ -4,12 +4,15 @@
//! Base classes to work with IDL callbacks.
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
+use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::settings_stack::{AutoEntryScript, AutoIncumbentScript};
use crate::dom::bindings::utils::AsCCharPtrPtr;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use js::jsapi::Heap;
use js::jsapi::JSAutoCompartment;
use js::jsapi::{AddRawValueRoot, IsCallable, JSContext, JSObject};
@@ -242,6 +245,9 @@ impl CallSetup {
#[allow(unrooted_must_root)]
pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
let global = unsafe { GlobalScope::from_object(callback.callback()) };
+ if let Some(window) = global.downcast::<Window>() {
+ window.Document().ensure_safe_to_run_script_or_layout();
+ }
let cx = global.get_cx();
let aes = AutoEntryScript::new(&global);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 5ee154658d7..709305f697a 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -410,6 +410,8 @@ pub struct Document {
responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
/// Number of redirects for the document load
redirect_count: Cell<u16>,
+ ///
+ script_and_layout_blockers: Cell<u32>,
}
#[derive(JSTraceable, MallocSizeOf)]
@@ -2695,9 +2697,27 @@ impl Document {
fired_unload: Cell::new(false),
responsive_images: Default::default(),
redirect_count: Cell::new(0),
+ script_and_layout_blockers: Cell::new(0),
}
}
+ pub fn add_script_and_layout_blocker(&self) {
+ self.script_and_layout_blockers.set(
+ self.script_and_layout_blockers.get() + 1
+ );
+ }
+
+ pub fn remove_script_and_layout_blocker(&self) {
+ assert!(self.script_and_layout_blockers.get() > 0);
+ self.script_and_layout_blockers.set(
+ self.script_and_layout_blockers.get() - 1
+ );
+ }
+
+ pub fn ensure_safe_to_run_script_or_layout(&self) {
+ assert_eq!(self.script_and_layout_blockers.get(), 0);
+ }
+
// https://dom.spec.whatwg.org/#dom-document-document
pub fn Constructor(window: &Window) -> Fallible<DomRoot<Document>> {
let doc = window.Document();
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index c059137b21b..ff6374a8b99 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -1504,8 +1504,11 @@ impl Node {
// https://dom.spec.whatwg.org/#concept-node-adopt
pub fn adopt(node: &Node, document: &Document) {
+ document.add_script_and_layout_blocker();
+
// Step 1.
let old_doc = node.owner_doc();
+ old_doc.add_script_and_layout_blocker();
// Step 2.
node.remove_self();
// Step 3.
@@ -1530,6 +1533,9 @@ impl Node {
vtable_for(&descendant).adopting_steps(&old_doc);
}
}
+
+ old_doc.remove_script_and_layout_blocker();
+ document.remove_script_and_layout_blocker();
}
// https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
@@ -1685,6 +1691,7 @@ impl Node {
child: Option<&Node>,
suppress_observers: SuppressObserver,
) {
+ node.owner_doc().add_script_and_layout_blocker();
debug_assert!(&*node.owner_doc() == &*parent.owner_doc());
debug_assert!(child.map_or(true, |child| Some(parent) == child.GetParentNode().r()));
@@ -1774,10 +1781,12 @@ impl Node {
};
MutationObserver::queue_a_mutation_record(&parent, mutation);
}
+ node.owner_doc().remove_script_and_layout_blocker();
}
// https://dom.spec.whatwg.org/#concept-node-replace-all
pub fn replace_all(node: Option<&Node>, parent: &Node) {
+ parent.owner_doc().add_script_and_layout_blocker();
// Step 1.
if let Some(node) = node {
Node::adopt(node, &*parent.owner_doc());
@@ -1819,6 +1828,7 @@ impl Node {
};
MutationObserver::queue_a_mutation_record(&parent, mutation);
}
+ parent.owner_doc().remove_script_and_layout_blocker();
}
// https://dom.spec.whatwg.org/#concept-node-pre-remove
@@ -1839,6 +1849,7 @@ impl Node {
// https://dom.spec.whatwg.org/#concept-node-remove
fn remove(node: &Node, parent: &Node, suppress_observers: SuppressObserver) {
+ parent.owner_doc().add_script_and_layout_blocker();
assert!(
node.GetParentNode()
.map_or(false, |node_parent| &*node_parent == parent)
@@ -1884,6 +1895,7 @@ impl Node {
};
MutationObserver::queue_a_mutation_record(&parent, mutation);
}
+ parent.owner_doc().remove_script_and_layout_blocker();
}
// https://dom.spec.whatwg.org/#concept-node-clone
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 785404454bd..639d4677993 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1361,6 +1361,7 @@ impl Window {
/// Returns true if layout actually happened, false otherwise.
#[allow(unsafe_code)]
pub fn force_reflow(&self, reflow_goal: ReflowGoal, reason: ReflowReason) -> bool {
+ self.Document().ensure_safe_to_run_script_or_layout();
// Check if we need to unsuppress reflow. Note that this needs to be
// *before* any early bailouts, or reflow might never be unsuppresed!
match reason {
@@ -1497,6 +1498,7 @@ impl Window {
/// may happen in the only case a query reflow may bail out, that is, if the
/// viewport size is not present). See #11223 for an example of that.
pub fn reflow(&self, reflow_goal: ReflowGoal, reason: ReflowReason) -> bool {
+ self.Document().ensure_safe_to_run_script_or_layout();
let for_display = reflow_goal == ReflowGoal::Full;
let mut issued_reflow = false;