aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2014-10-29 19:02:31 -0700
committerMartin Robinson <mrobinson@igalia.com>2014-11-03 10:30:28 -0800
commit2d72f00ccf8abfd5805dccdca5a635fa4e8e0cb8 (patch)
treeb49ad076db1f72b40102aaaa99683775749d883f /components/script
parent1a3ff8739c2a17d61f295f213f31ddee25e0b3ae (diff)
downloadservo-2d72f00ccf8abfd5805dccdca5a635fa4e8e0cb8.tar.gz
servo-2d72f00ccf8abfd5805dccdca5a635fa4e8e0cb8.zip
Have ContentBox(es)Queries consult the flow tree
Instead of looking at the display tree, have ContentBox(es)Query consult the flow tree. This allow optimizing away parts of the display tree later. To do this we need to be more careful about how we send reflow requests, only querying the flow tree when possible. Fixes #3790.
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/node.rs16
-rw-r--r--components/script/dom/window.rs8
-rw-r--r--components/script/layout_interface.rs15
-rw-r--r--components/script/page.rs55
-rw-r--r--components/script/script_task.rs8
5 files changed, 64 insertions, 38 deletions
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index af1afccc3b1..54bda6acc03 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -45,8 +45,7 @@ use dom::text::Text;
use dom::virtualmethods::{VirtualMethods, vtable_for};
use dom::window::Window;
use geom::rect::Rect;
-use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC,
- LayoutChan, ReapLayoutDataMsg};
+use layout_interface::{LayoutChan, ReapLayoutDataMsg};
use devtools_traits::NodeInfo;
use script_traits::UntrustedNodeAddress;
use servo_util::geometry::Au;
@@ -689,20 +688,11 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
}
fn get_bounding_content_box(self) -> Rect<Au> {
- let window = window_from_node(self).root();
- let page = window.page();
- let addr = self.to_trusted_node_address();
-
- let ContentBoxResponse(rect) = page.layout().content_box(addr);
- rect
+ window_from_node(self).root().page().content_box_query(self.to_trusted_node_address())
}
fn get_content_boxes(self) -> Vec<Rect<Au>> {
- let window = window_from_node(self).root();
- let page = window.page();
- let addr = self.to_trusted_node_address();
- let ContentBoxesResponse(rects) = page.layout().content_boxes(addr);
- rects
+ window_from_node(self).root().page().content_boxes_query(self.to_trusted_node_address())
}
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 71c8890ab6f..c9eeedc2a2a 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -19,7 +19,7 @@ use dom::location::Location;
use dom::navigator::Navigator;
use dom::performance::Performance;
use dom::screen::Screen;
-use layout_interface::ReflowGoal;
+use layout_interface::NoQuery;
use page::Page;
use script_task::{ExitWindowMsg, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg};
use script_task::FromWindow;
@@ -312,7 +312,7 @@ impl Reflectable for Window {
pub trait WindowHelpers {
fn reflow(self);
- fn flush_layout(self, goal: ReflowGoal);
+ fn flush_layout(self);
fn wait_until_safe_to_modify_dom(self);
fn init_browser_context(self, doc: JSRef<Document>);
fn load_url(self, href: DOMString);
@@ -350,8 +350,8 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
self.page().damage();
}
- fn flush_layout(self, goal: ReflowGoal) {
- self.page().flush_layout(goal);
+ fn flush_layout(self) {
+ self.page().flush_layout(NoQuery);
}
fn wait_until_safe_to_modify_dom(self) {
diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs
index 735893f497a..2cf64f961fb 100644
--- a/components/script/layout_interface.rs
+++ b/components/script/layout_interface.rs
@@ -60,9 +60,9 @@ pub enum Msg {
// 3) and really needs to be fast.
pub trait LayoutRPC {
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
- fn content_box(&self, node: TrustedNodeAddress) -> ContentBoxResponse;
+ fn content_box(&self) -> ContentBoxResponse;
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
- fn content_boxes(&self, node: TrustedNodeAddress) -> ContentBoxesResponse;
+ fn content_boxes(&self) -> ContentBoxesResponse;
/// Requests the node containing the point of interest
fn hit_test(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()>;
fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>;
@@ -82,6 +82,13 @@ pub enum ReflowGoal {
ReflowForScriptQuery,
}
+/// Any query to perform with this reflow.
+pub enum ReflowQueryType {
+ NoQuery,
+ ContentBoxQuery(TrustedNodeAddress),
+ ContentBoxesQuery(TrustedNodeAddress),
+}
+
/// Information needed for a reflow.
pub struct Reflow {
/// The document node.
@@ -99,7 +106,9 @@ pub struct Reflow {
/// The channel that we send a notification to.
pub script_join_chan: Sender<()>,
/// Unique identifier
- pub id: uint
+ pub id: uint,
+ /// The type of query if any to perform during this reflow.
+ pub query_type: ReflowQueryType,
}
/// Encapsulates a channel to the layout task.
diff --git a/components/script/page.rs b/components/script/page.rs
index 9fc7d74d2e9..01b396126ad 100644
--- a/components/script/page.rs
+++ b/components/script/page.rs
@@ -11,19 +11,22 @@ use dom::document::{Document, DocumentHelpers};
use dom::element::Element;
use dom::node::{Node, NodeHelpers};
use dom::window::Window;
-use layout_interface::{ReflowForDisplay};
-use layout_interface::{HitTestResponse, MouseOverResponse};
-use layout_interface::{GetRPCMsg, LayoutChan, LayoutRPC};
-use layout_interface::{Reflow, ReflowGoal, ReflowMsg};
+use layout_interface::{
+ ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery, ContentBoxesResponse,
+ GetRPCMsg, HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse, NoQuery,
+ Reflow, ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg,
+ ReflowQueryType, TrustedNodeAddress
+};
use script_traits::{UntrustedNodeAddress, ScriptControlChan};
-use geom::point::Point2D;
+use geom::{Point2D, Rect};
use js::rust::Cx;
use servo_msg::compositor_msg::PerformingLayout;
use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_net::resource_task::ResourceTask;
+use servo_util::geometry::Au;
use servo_util::str::DOMString;
use servo_util::smallvec::{SmallVec1, SmallVec};
use std::cell::Cell;
@@ -164,26 +167,48 @@ impl Page {
}
}
- pub fn flush_layout(&self, goal: ReflowGoal) {
- if self.damaged.get() {
+ pub fn flush_layout(&self, query: ReflowQueryType) {
+ // If we are damaged, we need to force a full reflow, so that queries interact with
+ // an accurate flow tree.
+ let (reflow_goal, force_reflow) = if self.damaged.get() {
+ (ReflowForDisplay, true)
+ } else {
+ match query {
+ ContentBoxQuery(_) | ContentBoxesQuery(_) => (ReflowForScriptQuery, true),
+ NoQuery => (ReflowForDisplay, false),
+ }
+ };
+
+ if force_reflow {
let frame = self.frame();
let window = frame.as_ref().unwrap().window.root();
- self.reflow(goal, window.control_chan().clone(), window.compositor());
+ self.reflow(reflow_goal, window.control_chan().clone(), window.compositor(), query);
} else {
self.avoided_reflows.set(self.avoided_reflows.get() + 1);
}
}
- pub fn layout(&self) -> &LayoutRPC {
- // FIXME This should probably be ReflowForQuery, not Display. All queries currently
- // currently rely on the display list, which means we can't destroy it by
- // doing a query reflow.
- self.flush_layout(ReflowForDisplay);
+ pub fn layout(&self) -> &LayoutRPC {
+ self.flush_layout(NoQuery);
self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough?
let layout_rpc: &LayoutRPC = &*self.layout_rpc;
layout_rpc
}
+ pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Rect<Au> {
+ self.flush_layout(ContentBoxQuery(content_box_request));
+ self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough?
+ let ContentBoxResponse(rect) = self.layout_rpc.content_box();
+ rect
+ }
+
+ pub fn content_boxes_query(&self, content_boxes_request: TrustedNodeAddress) -> Vec<Rect<Au>> {
+ self.flush_layout(ContentBoxesQuery(content_boxes_request));
+ self.join_layout(); //FIXME: is this necessary, or is layout_rpc's mutex good enough?
+ let ContentBoxesResponse(rects) = self.layout_rpc.content_boxes();
+ rects
+ }
+
// must handle root case separately
pub fn remove(&self, id: PipelineId) -> Option<Rc<Page>> {
let remove_idx = {
@@ -303,7 +328,8 @@ impl Page {
pub fn reflow(&self,
goal: ReflowGoal,
script_chan: ScriptControlChan,
- compositor: &ScriptListener) {
+ compositor: &ScriptListener,
+ query_type: ReflowQueryType) {
let root = match *self.frame() {
None => return,
@@ -349,6 +375,7 @@ impl Page {
script_chan: script_chan,
script_join_chan: join_chan,
id: last_reflow_id.get(),
+ query_type: query_type,
};
let LayoutChan(ref chan) = self.layout_chan;
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index deb6aaded80..7ef0d095545 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -29,7 +29,7 @@ use dom::window::{Window, WindowHelpers};
use dom::worker::{Worker, TrustedWorkerAddress};
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
use parse::html::{InputString, InputUrl, parse_html};
-use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowForDisplay};
+use layout_interface::{ScriptLayoutChan, LayoutChan, NoQuery, ReflowForDisplay};
use layout_interface;
use page::{Page, IterablePage, Frame};
use timers::TimerId;
@@ -815,7 +815,7 @@ impl ScriptTask {
let document_as_node = NodeCast::from_ref(document_js_ref);
document.content_changed(document_as_node);
}
- window.flush_layout(ReflowForDisplay);
+ window.flush_layout();
{
// No more reflow required
@@ -870,7 +870,7 @@ impl ScriptTask {
}
page.damage();
- page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor);
+ page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor, NoQuery);
}
/// This is the main entry point for receiving and dispatching DOM events.
@@ -969,7 +969,7 @@ impl ScriptTask {
let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(node);
let _ = eventtarget.dispatch_event_with_target(None, *event);
- window.flush_layout(ReflowForDisplay);
+ window.flush_layout();
}
None => {}
}