aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/document.rs55
-rw-r--r--components/script/dom/domrectlist.rs11
-rw-r--r--components/script/dom/element.rs17
-rw-r--r--components/script/dom/htmlbodyelement.rs28
-rw-r--r--components/script/dom/node.rs7
-rw-r--r--components/script/dom/nodelist.rs7
-rw-r--r--components/script/dom/servohtmlparser.rs3
-rw-r--r--components/script/dom/window.rs2
8 files changed, 88 insertions, 42 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 13f035f3e3f..3d615df43de 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -148,6 +148,8 @@ pub struct Document {
loader: DOMRefCell<DocumentLoader>,
/// The current active HTML parser, to allow resuming after interruptions.
current_parser: MutNullableHeap<JS<ServoHTMLParser>>,
+ /// When we should kick off a reflow. This happens during parsing.
+ reflow_timeout: Cell<Option<u64>>,
}
impl DocumentDerived for EventTarget {
@@ -226,6 +228,9 @@ pub trait DocumentHelpers<'a> {
fn set_encoding_name(self, name: DOMString);
fn content_changed(self, node: JSRef<Node>, damage: NodeDamage);
fn content_and_heritage_changed(self, node: JSRef<Node>, damage: NodeDamage);
+ fn reflow_if_reflow_timer_expired(self);
+ fn set_reflow_timeout(self, timeout: u64);
+ fn disarm_reflow_timeout(self);
fn unregister_named_element(self, to_unregister: JSRef<Element>, id: Atom);
fn register_named_element(self, element: JSRef<Element>, id: Atom);
fn load_anchor_href(self, href: DOMString);
@@ -343,11 +348,42 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
}
fn content_and_heritage_changed(self, node: JSRef<Node>, damage: NodeDamage) {
- debug!("content_and_heritage_changed on {}", node.debug_str());
node.force_dirty_ancestors(damage);
node.dirty(damage);
}
+ /// Reflows and disarms the timer if the reflow timer has expired.
+ fn reflow_if_reflow_timer_expired(self) {
+ if let Some(reflow_timeout) = self.reflow_timeout.get() {
+ if time::precise_time_ns() < reflow_timeout {
+ return
+ }
+
+ self.reflow_timeout.set(None);
+ let window = self.window.root();
+ window.r().reflow(ReflowGoal::ForDisplay,
+ ReflowQueryType::NoQuery,
+ ReflowReason::RefreshTick);
+ }
+ }
+
+ /// Schedules a reflow to be kicked off at the given `timeout` (in `time::precise_time_ns()`
+ /// units). This reflow happens even if the event loop is busy. This is used to display initial
+ /// page content during parsing.
+ fn set_reflow_timeout(self, timeout: u64) {
+ if let Some(existing_timeout) = self.reflow_timeout.get() {
+ if existing_timeout < timeout {
+ return
+ }
+ }
+ self.reflow_timeout.set(Some(timeout))
+ }
+
+ /// Disables any pending reflow timeouts.
+ fn disarm_reflow_timeout(self) {
+ self.reflow_timeout.set(None)
+ }
+
/// Remove any existing association between the provided id and any elements in this document.
fn unregister_named_element(self,
to_unregister: JSRef<Element>,
@@ -1004,6 +1040,7 @@ impl Document {
animation_frame_list: RefCell::new(HashMap::new()),
loader: DOMRefCell::new(doc_loader),
current_parser: Default::default(),
+ reflow_timeout: Cell::new(None),
}
}
@@ -1045,17 +1082,11 @@ trait PrivateDocumentHelpers {
impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> {
fn create_node_list<F: Fn(JSRef<Node>) -> bool>(self, callback: F) -> Temporary<NodeList> {
let window = self.window.root();
- let document_element = self.GetDocumentElement().root();
- let mut nodes = RootedVec::new();
- if let Some(ref root) = document_element {
- for node in NodeCast::from_ref(root.r()).traverse_preorder() {
- let node = node.root();
- if callback(node.r()) {
- nodes.push(JS::from_rooted(node.r()));
- }
- }
- };
- NodeList::new_simple_list(window.r(), &nodes)
+ let doc = self.GetDocumentElement().root();
+ let maybe_node = doc.r().map(NodeCast::from_ref);
+ let iter = maybe_node.iter().flat_map(|node| node.traverse_preorder())
+ .filter(|node| callback(node.root().r()));
+ NodeList::new_simple_list(window.r(), iter)
}
fn get_html_element(self) -> Option<Temporary<HTMLHtmlElement>> {
diff --git a/components/script/dom/domrectlist.rs b/components/script/dom/domrectlist.rs
index a6ad5b50771..fe3a45ecf02 100644
--- a/components/script/dom/domrectlist.rs
+++ b/components/script/dom/domrectlist.rs
@@ -6,7 +6,6 @@ use dom::bindings::codegen::Bindings::DOMRectListBinding;
use dom::bindings::codegen::Bindings::DOMRectListBinding::DOMRectListMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, Temporary};
-use dom::bindings::trace::RootedVec;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::domrect::DOMRect;
use dom::window::Window;
@@ -19,17 +18,17 @@ pub struct DOMRectList {
}
impl DOMRectList {
- fn new_inherited(window: JSRef<Window>,
- rects: &RootedVec<JS<DOMRect>>) -> DOMRectList {
+ fn new_inherited<T>(window: JSRef<Window>, rects: T) -> DOMRectList
+ where T: Iterator<Item=Temporary<DOMRect>> {
DOMRectList {
reflector_: Reflector::new(),
- rects: (**rects).clone(),
+ rects: rects.map(JS::from_rooted).collect(),
window: JS::from_rooted(window),
}
}
- pub fn new(window: JSRef<Window>,
- rects: &RootedVec<JS<DOMRect>>) -> Temporary<DOMRectList> {
+ pub fn new<T>(window: JSRef<Window>, rects: T) -> Temporary<DOMRectList>
+ where T: Iterator<Item=Temporary<DOMRect>> {
reflect_dom_object(box DOMRectList::new_inherited(window, rects),
GlobalRef::Window(window), DOMRectListBinding::Wrap)
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 3b830a982d1..e0d0b79f640 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -1301,17 +1301,12 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
let win = window_from_node(self).root();
let node: JSRef<Node> = NodeCast::from_ref(self);
let raw_rects = node.get_content_boxes();
- let mut rects = RootedVec::new();
- for rect in raw_rects.iter() {
- let rect = DOMRect::new(win.r(),
- rect.origin.y,
- rect.origin.y + rect.size.height,
- rect.origin.x,
- rect.origin.x + rect.size.width);
- rects.push(JS::from_rooted(rect));
- }
-
- DOMRectList::new(win.r(), &rects)
+ let rects = raw_rects.iter().map(|rect| {
+ DOMRect::new(win.r(),
+ rect.origin.y, rect.origin.y + rect.size.height,
+ rect.origin.x, rect.origin.x + rect.size.width)
+ });
+ DOMRectList::new(win.r(), rects)
}
// http://dev.w3.org/csswg/cssom-view/#dom-element-getboundingclientrect
diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs
index 8145c2f3866..97cd615f910 100644
--- a/components/script/dom/htmlbodyelement.rs
+++ b/components/script/dom/htmlbodyelement.rs
@@ -6,11 +6,11 @@ use dom::attr::{Attr, AttrHelpers};
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyElementMethods};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
-use dom::bindings::codegen::InheritTypes::EventTargetCast;
+use dom::bindings::codegen::InheritTypes::{EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::{JSRef, Rootable, Temporary};
use dom::bindings::utils::Reflectable;
-use dom::document::Document;
+use dom::document::{Document, DocumentHelpers};
use dom::element::ElementTypeId;
use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers};
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
@@ -23,6 +23,11 @@ use util::str::{self, DOMString};
use std::borrow::ToOwned;
use std::cell::Cell;
+use time;
+
+/// How long we should wait before performing the initial reflow after `<body>` is parsed, in
+/// nanoseconds.
+const INITIAL_REFLOW_DELAY: u64 = 200_000_000;
#[dom_struct]
pub struct HTMLBodyElement {
@@ -32,9 +37,8 @@ pub struct HTMLBodyElement {
impl HTMLBodyElementDerived for EventTarget {
fn is_htmlbodyelement(&self) -> bool {
- *self.type_id() ==
- EventTargetTypeId::Node(
- NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)))
+ *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(
+ HTMLElementTypeId::HTMLBodyElement)))
}
}
@@ -91,6 +95,20 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
Some(element as &VirtualMethods)
}
+ fn bind_to_tree(&self, tree_in_doc: bool) {
+ if let Some(ref s) = self.super_type() {
+ s.bind_to_tree(tree_in_doc);
+ }
+
+ if !tree_in_doc {
+ return
+ }
+
+ let window = window_from_node(*self).root();
+ let document = window.r().Document().root();
+ document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
+ }
+
fn after_set_attr(&self, attr: JSRef<Attr>) {
if let Some(ref s) = self.super_type() {
s.after_set_attr(attr);
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index d9e9ef25b7c..50f4db71f8f 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -917,12 +917,9 @@ impl<'a> NodeHelpers for JSRef<'a, Node> {
// https://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
#[allow(unsafe_code)]
fn query_selector_all(self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
- let mut nodes = RootedVec::new();
- for node in try!(unsafe { self.query_selector_iter(selectors) }) {
- nodes.push(JS::from_rooted(node));
- }
let window = window_from_node(self).root();
- Ok(NodeList::new_simple_list(window.r(), &nodes))
+ let iter = try!(unsafe { self.query_selector_iter(selectors) });
+ Ok(NodeList::new_simple_list(window.r(), iter))
}
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index 66b2cb6c5c4..bb3df75e920 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -6,7 +6,6 @@ use dom::bindings::codegen::Bindings::NodeListBinding;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, Rootable, Temporary};
-use dom::bindings::trace::RootedVec;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::node::{Node, NodeHelpers};
use dom::window::Window;
@@ -39,8 +38,10 @@ impl NodeList {
GlobalRef::Window(window), NodeListBinding::Wrap)
}
- pub fn new_simple_list(window: JSRef<Window>, elements: &RootedVec<JS<Node>>) -> Temporary<NodeList> {
- NodeList::new(window, NodeListType::Simple((**elements).clone()))
+ pub fn new_simple_list<T>(window: JSRef<Window>, iter: T)
+ -> Temporary<NodeList>
+ where T: Iterator<Item=Temporary<Node>> {
+ NodeList::new(window, NodeListType::Simple(iter.map(JS::from_rooted).collect()))
}
pub fn new_child_list(window: JSRef<Window>, node: JSRef<Node>) -> Temporary<NodeList> {
diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs
index c4779a5666d..1d69b24c5c8 100644
--- a/components/script/dom/servohtmlparser.rs
+++ b/components/script/dom/servohtmlparser.rs
@@ -303,6 +303,9 @@ impl<'a> PrivateServoHTMLParserHelpers for JSRef<'a, ServoHTMLParser> {
break;
}
+ let document = self.document.root();
+ document.r().reflow_if_reflow_timer_expired();
+
let mut pending_input = self.pending_input.borrow_mut();
if !pending_input.is_empty() {
let chunk = pending_input.remove(0);
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 6ebff11c5f1..21e9bbc28f2 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -81,6 +81,7 @@ enum WindowState {
#[derive(Debug)]
pub enum ReflowReason {
CachedPageNeededReflow,
+ RefreshTick,
FirstLoad,
KeyEvent,
MouseEvent,
@@ -1046,6 +1047,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
debug_msg.push_str(match *reason {
ReflowReason::CachedPageNeededReflow => "\tCachedPageNeededReflow",
+ ReflowReason::RefreshTick => "\tRefreshTick",
ReflowReason::FirstLoad => "\tFirstLoad",
ReflowReason::KeyEvent => "\tKeyEvent",
ReflowReason::MouseEvent => "\tMouseEvent",