mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Prevent JS execution and layout operations while DOM in inconsistent state.
This commit is contained in:
parent
231a37be24
commit
14b0de30db
4 changed files with 40 additions and 0 deletions
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue