/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! The high-level interface from script to layout. Using this abstract //! interface helps reduce coupling between these two components, and enables //! the DOM to be placed in a separate crate from layout. use dom::node::LayoutData; use euclid::point::Point2D; use euclid::rect::Rect; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use libc::uintptr_t; use msg::compositor_msg::Epoch; use msg::compositor_msg::LayerId; use msg::constellation_msg::{ConstellationChan, Failure, PipelineExitType, PipelineId}; use msg::constellation_msg::{WindowSizeData}; use net_traits::PendingAsyncLoad; use net_traits::image_cache_task::ImageCacheTask; use profile_traits::mem::ReportsChan; use script_traits::{ConstellationControlMsg, LayoutControlMsg}; use script_traits::{OpaqueScriptLayoutChannel, StylesheetLoadResponder, UntrustedNodeAddress}; use selectors::parser::PseudoElement; use std::any::Any; use std::sync::mpsc::{channel, Receiver, Sender}; use string_cache::Atom; use style::animation::PropertyAnimation; use style::media_queries::MediaQueryList; use style::stylesheets::Stylesheet; use url::Url; use util::geometry::Au; pub use dom::node::TrustedNodeAddress; /// Asynchronous messages that script can send to layout. pub enum Msg { /// Adds the given stylesheet to the document. AddStylesheet(Stylesheet, MediaQueryList), /// Adds the given stylesheet to the document. LoadStylesheet(Url, MediaQueryList, PendingAsyncLoad, Box), /// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded. SetQuirksMode, /// Requests a reflow. Reflow(Box), /// Get an RPC interface. GetRPC(Sender>), /// Requests that the layout task render the next frame of all animations. TickAnimations, /// Updates the layout visible rects, affecting the area that display lists will be constructed /// for. SetVisibleRects(Vec<(LayerId, Rect)>), /// Destroys layout data associated with a DOM node. /// /// TODO(pcwalton): Maybe think about batching to avoid message traffic. ReapLayoutData(LayoutData), /// Requests that the layout task measure its memory usage. The resulting reports are sent back /// via the supplied channel. CollectReports(ReportsChan), /// Requests that the layout task enter a quiescent state in which no more messages are /// accepted except `ExitMsg`. A response message will be sent on the supplied channel when /// this happens. PrepareToExit(Sender<()>), /// Requests that the layout task immediately shut down. There must be no more nodes left after /// this, or layout will crash. ExitNow(PipelineExitType), /// Get the last epoch counter for this layout task. GetCurrentEpoch(IpcSender), /// Creates a new layout task. /// /// This basically exists to keep the script-layout dependency one-way. CreateLayoutTask(NewLayoutTaskInfo), } /// Synchronous messages that script can send to layout. /// /// 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. fn content_box(&self) -> ContentBoxResponse; /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. fn content_boxes(&self) -> ContentBoxesResponse; /// Requests the geometry of this node. Used by APIs such as `clientTop`. fn node_geometry(&self) -> NodeGeometryResponse; /// Requests the node containing the point of interest fn hit_test(&self, node: TrustedNodeAddress, point: Point2D) -> Result; fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D) -> Result; /// Query layout for the resolved value of a given CSS property fn resolved_style(&self) -> ResolvedStyleResponse; fn offset_parent(&self) -> OffsetParentResponse; } pub struct ContentBoxResponse(pub Rect); pub struct ContentBoxesResponse(pub Vec>); pub struct NodeGeometryResponse { pub client_rect: Rect, } pub struct HitTestResponse(pub UntrustedNodeAddress); pub struct MouseOverResponse(pub Vec); pub struct ResolvedStyleResponse(pub Option); #[derive(Clone)] pub struct OffsetParentResponse { pub node_address: Option, pub rect: Rect, } impl OffsetParentResponse { pub fn empty() -> OffsetParentResponse { OffsetParentResponse { node_address: None, rect: Rect::zero(), } } } /// Why we're doing reflow. #[derive(PartialEq, Copy, Clone, Debug)] pub enum ReflowGoal { /// We're reflowing in order to send a display list to the screen. ForDisplay, /// We're reflowing in order to satisfy a script query. No display list will be created. ForScriptQuery, } /// Any query to perform with this reflow. #[derive(PartialEq)] pub enum ReflowQueryType { NoQuery, ContentBoxQuery(TrustedNodeAddress), ContentBoxesQuery(TrustedNodeAddress), NodeGeometryQuery(TrustedNodeAddress), ResolvedStyleQuery(TrustedNodeAddress, Option, Atom), OffsetParentQuery(TrustedNodeAddress), } /// Information needed for a reflow. pub struct Reflow { /// The goal of reflow: either to render to the screen or to flush layout info for script. pub goal: ReflowGoal, /// A clipping rectangle for the page, an enlarged rectangle containing the viewport. pub page_clip_rect: Rect, } /// Information needed for a script-initiated reflow. pub struct ScriptReflow { /// General reflow data. pub reflow_info: Reflow, /// The document node. pub document_root: TrustedNodeAddress, /// The channel through which messages can be sent back to the script task. pub script_chan: Sender, /// The current window size. pub window_size: WindowSizeData, /// The channel that we send a notification to. pub script_join_chan: Sender<()>, /// Unique identifier pub id: u32, /// The type of query if any to perform during this reflow. pub query_type: ReflowQueryType, } /// Encapsulates a channel to the layout task. #[derive(Clone)] pub struct LayoutChan(pub Sender); impl LayoutChan { pub fn new() -> (Receiver, LayoutChan) { let (chan, port) = channel(); (port, LayoutChan(chan)) } } /// A trait to manage opaque references to script<->layout channels without needing /// to expose the message type to crates that don't need to know about them. pub trait ScriptLayoutChan { fn new(sender: Sender, receiver: Receiver) -> Self; fn sender(&self) -> Sender; fn receiver(self) -> Receiver; } impl ScriptLayoutChan for OpaqueScriptLayoutChannel { fn new(sender: Sender, receiver: Receiver) -> OpaqueScriptLayoutChannel { let inner = (box sender as Box, box receiver as Box); OpaqueScriptLayoutChannel(inner) } fn sender(&self) -> Sender { let &OpaqueScriptLayoutChannel((ref sender, _)) = self; (*sender.downcast_ref::>().unwrap()).clone() } fn receiver(self) -> Receiver { let OpaqueScriptLayoutChannel((_, receiver)) = self; *receiver.downcast::>().unwrap() } } /// Type of an opaque node. pub type OpaqueNode = uintptr_t; /// State relating to an animation. #[derive(Clone)] pub struct Animation { /// An opaque reference to the DOM node participating in the animation. pub node: OpaqueNode, /// A description of the property animation that is occurring. pub property_animation: PropertyAnimation, /// The start time of the animation, as returned by `time::precise_time_s()`. pub start_time: f64, /// The end time of the animation, as returned by `time::precise_time_s()`. pub end_time: f64, } impl Animation { /// Returns the duration of this animation in seconds. #[inline] pub fn duration(&self) -> f64 { self.end_time - self.start_time } } pub struct NewLayoutTaskInfo { pub id: PipelineId, pub url: Url, pub is_parent: bool, pub layout_pair: OpaqueScriptLayoutChannel, pub pipeline_port: IpcReceiver, pub constellation_chan: ConstellationChan, pub failure: Failure, pub script_chan: Sender, pub image_cache_task: ImageCacheTask, pub paint_chan: Box, pub layout_shutdown_chan: Sender<()>, }