diff options
author | Josh Matthews <josh@joshmatthews.net> | 2014-09-04 22:14:18 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2014-09-04 22:14:18 -0400 |
commit | 94f7f46dd89ed225e22f5a5a35eacaa85d641de5 (patch) | |
tree | 00c834a7084ea88eb5fdb0968abb43c1a9b14e63 /src/components/script | |
parent | b940828a8aac8f39b6e156760c8a6fc40f352f95 (diff) | |
parent | dafd0b652d8b5452e485a8430c8e120029fcdbbd (diff) | |
download | servo-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.rs | 9 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 25 | ||||
-rw-r--r-- | src/components/script/page.rs | 35 |
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) } |