Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initialize iframe viewport immediately #22395

Merged
merged 5 commits into from Dec 18, 2018

Prevent JS execution and layout operations while DOM in inconsistent …

…state.
  • Loading branch information
jdm committed Dec 14, 2018
commit 14b0de30dbf90793c3b6c9017e4c65df9281c5ae
@@ -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);

This comment has been minimized.

Copy link
@Manishearth

Manishearth Dec 10, 2018

Member

This should have an assertion message

}

// 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;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.