aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2014-09-04 22:14:18 -0400
committerJosh Matthews <josh@joshmatthews.net>2014-09-04 22:14:18 -0400
commit94f7f46dd89ed225e22f5a5a35eacaa85d641de5 (patch)
tree00c834a7084ea88eb5fdb0968abb43c1a9b14e63 /src/components/script
parentb940828a8aac8f39b6e156760c8a6fc40f352f95 (diff)
parentdafd0b652d8b5452e485a8430c8e120029fcdbbd (diff)
downloadservo-94f7f46dd89ed225e22f5a5a35eacaa85d641de5.tar.gz
servo-94f7f46dd89ed225e22f5a5a35eacaa85d641de5.zip
Merge pull request #3164 from cgaebel/layout-rpc
Avoid using message passing for simple JS -> Layout "rpc-like" queries.
Diffstat (limited to 'src/components/script')
-rw-r--r--src/components/script/dom/node.rs9
-rw-r--r--src/components/script/layout_interface.rs25
-rw-r--r--src/components/script/page.rs35
3 files changed, 36 insertions, 33 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 33a8674d97e..bf629122605 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -43,7 +43,7 @@ use dom::virtualmethods::{VirtualMethods, vtable_for};
use dom::window::Window;
use geom::rect::Rect;
use html::hubbub_html_parser::build_element_from_tag;
-use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery, ContentBoxesResponse,
+use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC,
LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress};
use servo_util::geometry::Au;
use servo_util::str::{DOMString, null_str_as_empty};
@@ -586,18 +586,17 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
fn get_bounding_content_box(&self) -> Rect<Au> {
let window = window_from_node(self).root();
let page = window.deref().page();
- let (chan, port) = channel();
let addr = self.to_trusted_node_address();
- let ContentBoxResponse(rect) = page.query_layout(ContentBoxQuery(addr, chan), port);
+
+ let ContentBoxResponse(rect) = page.layout_rpc.content_box(addr);
rect
}
fn get_content_boxes(&self) -> Vec<Rect<Au>> {
let window = window_from_node(self).root();
let page = window.deref().page();
- let (chan, port) = channel();
let addr = self.to_trusted_node_address();
- let ContentBoxesResponse(rects) = page.query_layout(ContentBoxesQuery(addr, chan), port);
+ let ContentBoxesResponse(rects) = page.layout_rpc.content_boxes(addr);
rects
}
diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs
index f36c3e83167..1e5e23f9c9a 100644
--- a/src/components/script/layout_interface.rs
+++ b/src/components/script/layout_interface.rs
@@ -25,8 +25,6 @@ use url::Url;
use serialize::{Encodable, Encoder};
/// Asynchronous messages that script can send to layout.
-///
-/// FIXME(pcwalton): I think this should probably be merged with `LayoutQuery` below.
pub enum Msg {
/// Adds the given stylesheet to the document.
AddStylesheetMsg(Stylesheet),
@@ -34,10 +32,8 @@ pub enum Msg {
/// Requests a reflow.
ReflowMsg(Box<Reflow>),
- /// Performs a synchronous layout request.
- ///
- /// FIXME(pcwalton): As noted below, this isn't very type safe.
- QueryMsg(LayoutQuery),
+ /// Get an RPC interface.
+ GetRPCMsg(Sender<Box<LayoutRPC + Send>>),
/// Destroys layout data associated with a DOM node.
///
@@ -55,14 +51,21 @@ pub enum Msg {
}
/// Synchronous messages that script can send to layout.
-pub enum LayoutQuery {
+///
+/// In general, you should use messages to talk to Layout. Use the RPC interface
+/// if and only if the work is
+///
+/// 1) read-only with respect to LayoutTaskData,
+/// 2) small,
+// 3) and really needs to be fast.
+pub trait LayoutRPC {
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
- ContentBoxQuery(TrustedNodeAddress, Sender<ContentBoxResponse>),
+ fn content_box(&self, node: TrustedNodeAddress) -> ContentBoxResponse;
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
- ContentBoxesQuery(TrustedNodeAddress, Sender<ContentBoxesResponse>),
+ fn content_boxes(&self, node: TrustedNodeAddress) -> ContentBoxesResponse;
/// Requests the node containing the point of interest
- HitTestQuery(TrustedNodeAddress, Point2D<f32>, Sender<Result<HitTestResponse, ()>>),
- MouseOverQuery(TrustedNodeAddress, Point2D<f32>, Sender<Result<MouseOverResponse, ()>>),
+ fn hit_test(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()>;
+ fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>;
}
/// The address of a node known to be valid. These must only be sent from content -> layout,
diff --git a/src/components/script/page.rs b/src/components/script/page.rs
index 227a6e66e3c..633a7de204b 100644
--- a/src/components/script/page.rs
+++ b/src/components/script/page.rs
@@ -13,8 +13,8 @@ use dom::element::{Element, AttributeHandlers};
use dom::node::{Node, NodeHelpers};
use dom::window::Window;
use layout_interface::{DocumentDamage};
-use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery, MouseOverQuery, MouseOverResponse};
-use layout_interface::{LayoutChan, QueryMsg};
+use layout_interface::{DocumentDamageLevel, HitTestResponse, MouseOverResponse};
+use layout_interface::{GetRPCMsg, LayoutChan, LayoutRPC};
use layout_interface::{Reflow, ReflowGoal, ReflowMsg};
use layout_interface::UntrustedNodeAddress;
use script_traits::ScriptControlChan;
@@ -54,6 +54,9 @@ pub struct Page {
/// A handle for communicating messages to the layout task.
pub layout_chan: Untraceable<LayoutChan>,
+ /// A handle to perform RPC calls into the layout, quickly.
+ pub layout_rpc: Untraceable<Box<LayoutRPC>>,
+
/// The port that we will use to join layout. If this is `None`, then layout is not running.
pub layout_join_port: Untraceable<RefCell<Option<Receiver<()>>>>,
@@ -126,11 +129,18 @@ impl Page {
dom_static: GlobalStaticData(),
js_context: Untraceable::new(js_context),
};
+ let layout_rpc: Box<LayoutRPC> = {
+ let (rpc_send, rpc_recv) = channel();
+ let LayoutChan(ref lchan) = layout_chan;
+ lchan.send(GetRPCMsg(rpc_send));
+ rpc_recv.recv()
+ };
Page {
id: id,
subpage_id: subpage_id,
frame: Traceable::new(RefCell::new(None)),
layout_chan: Untraceable::new(layout_chan),
+ layout_rpc: Untraceable::new(layout_rpc),
layout_join_port: Untraceable::new(RefCell::new(None)),
damage: Traceable::new(RefCell::new(None)),
window_size: Traceable::new(Cell::new(window_size)),
@@ -255,6 +265,10 @@ impl Page {
self.url().get_ref().ref0().clone()
}
+ // FIXME(cgaebel): join_layout is racey. What if the compositor triggers a
+ // reflow between the "join complete" message and returning from this
+ // function?
+
/// Sends a ping to layout and waits for the response. The response will arrive when the
/// layout task has finished any pending request messages.
pub fn join_layout(&self) {
@@ -281,17 +295,6 @@ impl Page {
}
}
- /// Sends the given query to layout.
- pub fn query_layout<T: Send>(&self,
- query: LayoutQuery,
- response_port: Receiver<T>)
- -> T {
- self.join_layout();
- let LayoutChan(ref chan) = *self.layout_chan;
- chan.send(QueryMsg(query));
- response_port.recv()
- }
-
/// Reflows the page if it's possible to do so. This method will wait until the layout task has
/// completed its current action, join the layout task, and then request a new layout run. It
/// won't wait for the new layout computation to finish.
@@ -382,8 +385,7 @@ impl Page {
}
let root = root.unwrap();
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
- let (chan, port) = channel();
- let address = match self.query_layout(HitTestQuery(root.to_trusted_node_address(), *point, chan), port) {
+ let address = match self.layout_rpc.hit_test(root.to_trusted_node_address(), *point) {
Ok(HitTestResponse(node_address)) => {
Some(node_address)
}
@@ -404,8 +406,7 @@ impl Page {
}
let root = root.unwrap();
let root: &JSRef<Node> = NodeCast::from_ref(&*root);
- let (chan, port) = channel();
- let address = match self.query_layout(MouseOverQuery(root.to_trusted_node_address(), *point, chan), port) {
+ let address = match self.layout_rpc.mouse_over(root.to_trusted_node_address(), *point) {
Ok(MouseOverResponse(node_address)) => {
Some(node_address)
}