diff options
Diffstat (limited to 'components/script_layout_interface')
-rw-r--r-- | components/script_layout_interface/Cargo.toml | 39 | ||||
-rw-r--r-- | components/script_layout_interface/lib.rs | 164 | ||||
-rw-r--r-- | components/script_layout_interface/message.rs | 260 | ||||
-rw-r--r-- | components/script_layout_interface/rpc.rs | 75 | ||||
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 497 |
5 files changed, 0 insertions, 1035 deletions
diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml deleted file mode 100644 index 6a123c766e9..00000000000 --- a/components/script_layout_interface/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "script_layout_interface" -version = "0.0.1" -authors = ["The Servo Project Developers"] -license = "MPL-2.0" -edition = "2018" -publish = false - -[lib] -name = "script_layout_interface" -path = "lib.rs" - -[dependencies] -app_units = { workspace = true } -atomic_refcell = { workspace = true } -canvas_traits = { path = "../canvas_traits" } -crossbeam-channel = { workspace = true } -euclid = { workspace = true } -fxhash = { workspace = true } -gfx_traits = { path = "../gfx_traits" } -html5ever = { workspace = true } -ipc-channel = { workspace = true } -libc = { workspace = true } -malloc_size_of = { path = "../malloc_size_of" } -malloc_size_of_derive = { workspace = true } -metrics = { path = "../metrics" } -msg = { path = "../msg" } -net_traits = { path = "../net_traits" } -parking_lot = { workspace = true } -profile_traits = { path = "../profile_traits" } -range = { path = "../range" } -script_traits = { path = "../script_traits" } -selectors = { path = "../selectors", features = ["shmem"] } -servo_arc = { path = "../servo_arc" } -servo_atoms = { path = "../atoms" } -servo_url = { path = "../url" } -style = { path = "../style", features = ["servo"] } -style_traits = { path = "../style_traits", features = ["servo"] } -webrender_api = { git = "https://github.com/servo/webrender" } diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs deleted file mode 100644 index 0db42229678..00000000000 --- a/components/script_layout_interface/lib.rs +++ /dev/null @@ -1,164 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -//! This module contains traits in script used generically in the rest of Servo. -//! The traits are here instead of in script so that these modules won't have -//! to depend on script. - -#![deny(unsafe_code)] - -pub mod message; -pub mod rpc; -pub mod wrapper_traits; - -use std::any::Any; -use std::sync::atomic::AtomicIsize; - -use atomic_refcell::AtomicRefCell; -use canvas_traits::canvas::{CanvasId, CanvasMsg}; -use ipc_channel::ipc::IpcSender; -use libc::c_void; -use malloc_size_of_derive::MallocSizeOf; -use net_traits::image_cache::PendingImageId; -use script_traits::UntrustedNodeAddress; -use servo_url::{ImmutableOrigin, ServoUrl}; -use style::data::ElementData; -use webrender_api::ImageKey; - -#[derive(MallocSizeOf)] -pub struct StyleData { - /// Data that the style system associates with a node. When the - /// style system is being used standalone, this is all that hangs - /// off the node. This must be first to permit the various - /// transmutations between ElementData and PersistentLayoutData. - #[ignore_malloc_size_of = "This probably should not be ignored"] - pub element_data: AtomicRefCell<ElementData>, - - /// Information needed during parallel traversals. - pub parallel: DomParallelInfo, -} - -impl StyleData { - pub fn new() -> Self { - Self { - element_data: AtomicRefCell::new(ElementData::default()), - parallel: DomParallelInfo::new(), - } - } -} - -pub type StyleAndOpaqueLayoutData = StyleAndGenericData<dyn Any + Send + Sync>; - -#[derive(MallocSizeOf)] -pub struct StyleAndGenericData<T> -where - T: ?Sized, -{ - /// The style data. - pub style_data: StyleData, - /// The opaque layout data. - #[ignore_malloc_size_of = "Trait objects are hard"] - pub generic_data: T, -} - -impl StyleAndOpaqueLayoutData { - #[inline] - pub fn new<T>(style_data: StyleData, layout_data: T) -> Box<Self> - where - T: Any + Send + Sync, - { - Box::new(StyleAndGenericData { - style_data, - generic_data: layout_data, - }) - } -} - -/// Information that we need stored in each DOM node. -#[derive(MallocSizeOf)] -pub struct DomParallelInfo { - /// The number of children remaining to process during bottom-up traversal. - pub children_to_process: AtomicIsize, -} - -impl DomParallelInfo { - pub fn new() -> DomParallelInfo { - DomParallelInfo { - children_to_process: AtomicIsize::new(0), - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum LayoutNodeType { - Element(LayoutElementType), - Text, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum LayoutElementType { - Element, - HTMLBodyElement, - HTMLBRElement, - HTMLCanvasElement, - HTMLHtmlElement, - HTMLIFrameElement, - HTMLImageElement, - HTMLInputElement, - HTMLMediaElement, - HTMLObjectElement, - HTMLParagraphElement, - HTMLTableCellElement, - HTMLTableColElement, - HTMLTableElement, - HTMLTableRowElement, - HTMLTableSectionElement, - HTMLTextAreaElement, - SVGSVGElement, -} - -pub enum HTMLCanvasDataSource { - WebGL(ImageKey), - Image(Option<IpcSender<CanvasMsg>>), - WebGPU(ImageKey), -} - -pub struct HTMLCanvasData { - pub source: HTMLCanvasDataSource, - pub width: u32, - pub height: u32, - pub canvas_id: CanvasId, -} - -pub struct SVGSVGData { - pub width: u32, - pub height: u32, -} - -/// The address of a node known to be valid. These are sent from script to layout. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct TrustedNodeAddress(pub *const c_void); - -#[allow(unsafe_code)] -unsafe impl Send for TrustedNodeAddress {} - -/// Whether the pending image needs to be fetched or is waiting on an existing fetch. -pub enum PendingImageState { - Unrequested(ServoUrl), - PendingResponse, -} - -/// The data associated with an image that is not yet present in the image cache. -/// Used by the script thread to hold on to DOM elements that need to be repainted -/// when an image fetch is complete. -pub struct PendingImage { - pub state: PendingImageState, - pub node: UntrustedNodeAddress, - pub id: PendingImageId, - pub origin: ImmutableOrigin, -} - -pub struct HTMLMediaData { - pub current_frame: Option<(ImageKey, i32, i32)>, -} diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs deleted file mode 100644 index 01c5d58e659..00000000000 --- a/components/script_layout_interface/message.rs +++ /dev/null @@ -1,260 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -use std::sync::atomic::AtomicBool; -use std::sync::Arc; - -use app_units::Au; -use crossbeam_channel::{Receiver, Sender}; -use euclid::default::{Point2D, Rect}; -use gfx_traits::Epoch; -use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use malloc_size_of_derive::MallocSizeOf; -use metrics::PaintTimeMetrics; -use msg::constellation_msg::{BackgroundHangMonitorRegister, BrowsingContextId, PipelineId}; -use net_traits::image_cache::ImageCache; -use profile_traits::mem::ReportsChan; -use script_traits::{ - ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg, Painter, ScrollState, - WindowSizeData, -}; -use servo_arc::Arc as ServoArc; -use servo_atoms::Atom; -use servo_url::{ImmutableOrigin, ServoUrl}; -use style::animation::DocumentAnimationSet; -use style::context::QuirksMode; -use style::dom::OpaqueNode; -use style::invalidation::element::restyle_hints::RestyleHint; -use style::properties::PropertyId; -use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot}; -use style::stylesheets::Stylesheet; - -use crate::rpc::LayoutRPC; -use crate::{PendingImage, TrustedNodeAddress}; - -/// Asynchronous messages that script can send to layout. -pub enum Msg { - /// Adds the given stylesheet to the document. The second stylesheet is the - /// insertion point (if it exists, the sheet needs to be inserted before - /// it). - AddStylesheet(ServoArc<Stylesheet>, Option<ServoArc<Stylesheet>>), - - /// Removes a stylesheet from the document. - RemoveStylesheet(ServoArc<Stylesheet>), - - /// Change the quirks mode. - SetQuirksMode(QuirksMode), - - /// Requests a reflow. - Reflow(ScriptReflow), - - /// Get an RPC interface. - GetRPC(Sender<Box<dyn LayoutRPC + Send>>), - - /// Requests that the layout thread measure its memory usage. The resulting reports are sent back - /// via the supplied channel. - CollectReports(ReportsChan), - - /// Requests that the layout thread 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 thread immediately shut down. There must be no more nodes left after - /// this, or layout will crash. - ExitNow, - - /// Get the last epoch counter for this layout thread. - GetCurrentEpoch(IpcSender<Epoch>), - - /// Asks the layout thread whether any Web fonts have yet to load (if true, loads are pending; - /// false otherwise). - GetWebFontLoadState(IpcSender<bool>), - - /// Creates a new layout thread. - /// - /// This basically exists to keep the script-layout dependency one-way. - CreateLayoutThread(LayoutThreadInit), - - /// Set the final Url. - SetFinalUrl(ServoUrl), - - /// Tells layout about the new scrolling offsets of each scrollable stacking context. - SetScrollStates(Vec<ScrollState>), - - /// Tells layout that script has added some paint worklet modules. - RegisterPaint(Atom, Vec<Atom>, Box<dyn Painter>), - - /// Send to layout the precise time when the navigation started. - SetNavigationStart(u64), -} - -#[derive(Debug, PartialEq)] -pub enum NodesFromPointQueryType { - All, - Topmost, -} - -#[derive(Debug, PartialEq)] -pub enum QueryMsg { - ContentBoxQuery(OpaqueNode), - ContentBoxesQuery(OpaqueNode), - ClientRectQuery(OpaqueNode), - ScrollingAreaQuery(Option<OpaqueNode>), - OffsetParentQuery(OpaqueNode), - TextIndexQuery(OpaqueNode, Point2D<f32>), - NodesFromPointQuery(Point2D<f32>, NodesFromPointQueryType), - - // FIXME(nox): The following queries use the TrustedNodeAddress to - // access actual DOM nodes, but those values can be constructed from - // garbage values such as `0xdeadbeef as *const _`, this is unsound. - NodeScrollIdQuery(TrustedNodeAddress), - ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, PropertyId), - StyleQuery, - ElementInnerTextQuery(TrustedNodeAddress), - ResolvedFontStyleQuery(TrustedNodeAddress, PropertyId, String), - InnerWindowDimensionsQuery(BrowsingContextId), -} - -/// Any query to perform with this reflow. -#[derive(Debug, PartialEq)] -pub enum ReflowGoal { - Full, - TickAnimations, - LayoutQuery(QueryMsg, u64), - - /// Tells layout about a single new scrolling offset from the script. The rest will - /// remain untouched and layout won't forward this back to script. - UpdateScrollNode(ScrollState), -} - -impl ReflowGoal { - /// Returns true if the given ReflowQuery needs a full, up-to-date display list to - /// be present or false if it only needs stacking-relative positions. - pub fn needs_display_list(&self) -> bool { - match *self { - ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true, - ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg { - QueryMsg::NodesFromPointQuery(..) | - QueryMsg::TextIndexQuery(..) | - QueryMsg::InnerWindowDimensionsQuery(_) | - QueryMsg::ElementInnerTextQuery(_) => true, - QueryMsg::ContentBoxQuery(_) | - QueryMsg::ContentBoxesQuery(_) | - QueryMsg::ClientRectQuery(_) | - QueryMsg::ScrollingAreaQuery(_) | - QueryMsg::NodeScrollIdQuery(_) | - QueryMsg::ResolvedStyleQuery(..) | - QueryMsg::ResolvedFontStyleQuery(..) | - QueryMsg::OffsetParentQuery(_) | - QueryMsg::StyleQuery => false, - }, - } - } - - /// Returns true if the given ReflowQuery needs its display list send to WebRender or - /// false if a layout_thread display list is sufficient. - pub fn needs_display(&self) -> bool { - match *self { - ReflowGoal::Full | ReflowGoal::TickAnimations | ReflowGoal::UpdateScrollNode(_) => true, - ReflowGoal::LayoutQuery(ref querymsg, _) => match *querymsg { - QueryMsg::NodesFromPointQuery(..) | - QueryMsg::TextIndexQuery(..) | - QueryMsg::ElementInnerTextQuery(_) => true, - QueryMsg::ContentBoxQuery(_) | - QueryMsg::ContentBoxesQuery(_) | - QueryMsg::ClientRectQuery(_) | - QueryMsg::ScrollingAreaQuery(_) | - QueryMsg::NodeScrollIdQuery(_) | - QueryMsg::ResolvedStyleQuery(..) | - QueryMsg::ResolvedFontStyleQuery(..) | - QueryMsg::OffsetParentQuery(_) | - QueryMsg::InnerWindowDimensionsQuery(_) | - QueryMsg::StyleQuery => false, - }, - } - } -} - -/// Information needed for a reflow. -pub struct Reflow { - /// A clipping rectangle for the page, an enlarged rectangle containing the viewport. - pub page_clip_rect: Rect<Au>, -} - -/// Information derived from a layout pass that needs to be returned to the script thread. -#[derive(Default)] -pub struct ReflowComplete { - /// The list of images that were encountered that are in progress. - pub pending_images: Vec<PendingImage>, -} - -/// Information needed for a script-initiated reflow. -pub struct ScriptReflow { - /// General reflow data. - pub reflow_info: Reflow, - /// The document node. - pub document: TrustedNodeAddress, - /// The dirty root from which to restyle. - pub dirty_root: Option<TrustedNodeAddress>, - /// Whether the document's stylesheets have changed since the last script reflow. - pub stylesheets_changed: bool, - /// The current window size. - pub window_size: WindowSizeData, - /// The channel that we send a notification to. - pub script_join_chan: Sender<ReflowComplete>, - /// The goal of this reflow. - pub reflow_goal: ReflowGoal, - /// The number of objects in the dom #10110 - pub dom_count: u32, - /// The current window origin - pub origin: ImmutableOrigin, - /// Restyle snapshot map. - pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>, - /// The current animation timeline value. - pub animation_timeline_value: f64, - /// The set of animations for this document. - pub animations: DocumentAnimationSet, -} - -pub struct LayoutThreadInit { - pub id: PipelineId, - pub url: ServoUrl, - pub is_parent: bool, - pub layout_pair: (Sender<Msg>, Receiver<Msg>), - pub pipeline_port: IpcReceiver<LayoutControlMsg>, - pub background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, - pub constellation_chan: IpcSender<ConstellationMsg>, - pub script_chan: IpcSender<ConstellationControlMsg>, - pub image_cache: Arc<dyn ImageCache>, - pub paint_time_metrics: PaintTimeMetrics, - pub layout_is_busy: Arc<AtomicBool>, - pub window_size: WindowSizeData, -} - -/// A pending restyle. -#[derive(Debug, MallocSizeOf)] -pub struct PendingRestyle { - /// If this element had a state or attribute change since the last restyle, track - /// the original condition of the element. - pub snapshot: Option<Snapshot>, - - /// Any explicit restyles hints that have been accumulated for this element. - pub hint: RestyleHint, - - /// Any explicit restyles damage that have been accumulated for this element. - pub damage: RestyleDamage, -} - -impl PendingRestyle { - /// Creates a new empty pending restyle. - #[inline] - pub fn new() -> Self { - PendingRestyle { - snapshot: None, - hint: RestyleHint::empty(), - damage: RestyleDamage::empty(), - } - } -} diff --git a/components/script_layout_interface/rpc.rs b/components/script_layout_interface/rpc.rs deleted file mode 100644 index 3778d8f975a..00000000000 --- a/components/script_layout_interface/rpc.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -use app_units::Au; -use euclid::default::Rect; -use euclid::Size2D; -use script_traits::UntrustedNodeAddress; -use servo_arc::Arc; -use style::properties::style_structs::Font; -use style_traits::CSSPixel; -use webrender_api::ExternalScrollId; - -/// 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 LayoutThreadData, -/// 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 scroll geometry of this node. Used by APIs such as `scrollTop`. - fn scrolling_area(&self) -> NodeGeometryResponse; - /// Requests the scroll id of this node. Used by APIs such as `scrollTop` - fn node_scroll_id(&self) -> NodeScrollIdResponse; - /// Query layout for the resolved value of a given CSS property - fn resolved_style(&self) -> ResolvedStyleResponse; - /// Query layout to get the resolved font style for canvas. - fn resolved_font_style(&self) -> Option<Arc<Font>>; - fn offset_parent(&self) -> OffsetParentResponse; - fn text_index(&self) -> TextIndexResponse; - /// Requests the list of nodes from the given point. - fn nodes_from_point_response(&self) -> Vec<UntrustedNodeAddress>; - /// Query layout to get the inner text for a given element. - fn element_inner_text(&self) -> String; - /// Get the dimensions of an iframe's inner window. - fn inner_window_dimensions(&self) -> Option<Size2D<f32, CSSPixel>>; -} - -pub struct ContentBoxResponse(pub Option<Rect<Au>>); - -pub struct ContentBoxesResponse(pub Vec<Rect<Au>>); - -pub struct NodeGeometryResponse { - pub client_rect: Rect<i32>, -} - -pub struct NodeScrollIdResponse(pub ExternalScrollId); - -pub struct ResolvedStyleResponse(pub String); - -#[derive(Clone)] -pub struct OffsetParentResponse { - pub node_address: Option<UntrustedNodeAddress>, - pub rect: Rect<Au>, -} - -impl OffsetParentResponse { - pub fn empty() -> OffsetParentResponse { - OffsetParentResponse { - node_address: None, - rect: Rect::zero(), - } - } -} - -#[derive(Clone)] -pub struct TextIndexResponse(pub Option<usize>); diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs deleted file mode 100644 index 1cc20c5f6ab..00000000000 --- a/components/script_layout_interface/wrapper_traits.rs +++ /dev/null @@ -1,497 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -#![allow(unsafe_code)] - -use std::borrow::Cow; -use std::fmt::Debug; -use std::sync::Arc as StdArc; - -use atomic_refcell::AtomicRef; -use gfx_traits::{combine_id_with_fragment_type, ByteIndex, FragmentType}; -use html5ever::{local_name, namespace_url, ns, LocalName, Namespace}; -use msg::constellation_msg::{BrowsingContextId, PipelineId}; -use net_traits::image::base::{Image, ImageMetadata}; -use range::Range; -use servo_arc::Arc; -use servo_url::ServoUrl; -use style::attr::AttrValue; -use style::context::SharedStyleContext; -use style::data::ElementData; -use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TNode}; -use style::properties::ComputedValues; -use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl}; -use style::stylist::RuleInclusion; -use webrender_api::ExternalScrollId; - -use crate::{HTMLCanvasData, HTMLMediaData, LayoutNodeType, SVGSVGData, StyleAndOpaqueLayoutData}; - -pub trait LayoutDataTrait: Default + Send + Sync + 'static {} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PseudoElementType { - Normal, - Before, - After, - DetailsSummary, - DetailsContent, -} - -impl PseudoElementType { - pub fn fragment_type(&self) -> FragmentType { - match *self { - PseudoElementType::Normal => FragmentType::FragmentBody, - PseudoElementType::Before => FragmentType::BeforePseudoContent, - PseudoElementType::After => FragmentType::AfterPseudoContent, - PseudoElementType::DetailsSummary => FragmentType::FragmentBody, - PseudoElementType::DetailsContent => FragmentType::FragmentBody, - } - } - - pub fn is_before(&self) -> bool { - match *self { - PseudoElementType::Before => true, - _ => false, - } - } - - pub fn is_replaced_content(&self) -> bool { - match *self { - PseudoElementType::Before | PseudoElementType::After => true, - _ => false, - } - } - - pub fn style_pseudo_element(&self) -> PseudoElement { - match *self { - PseudoElementType::Normal => { - unreachable!("style_pseudo_element called with PseudoElementType::Normal") - }, - PseudoElementType::Before => PseudoElement::Before, - PseudoElementType::After => PseudoElement::After, - PseudoElementType::DetailsSummary => PseudoElement::DetailsSummary, - PseudoElementType::DetailsContent => PseudoElement::DetailsContent, - } - } -} - -/// Trait to abstract access to layout data across various data structures. -pub trait GetStyleAndOpaqueLayoutData<'dom> { - fn get_style_and_opaque_layout_data(self) -> Option<&'dom StyleAndOpaqueLayoutData>; -} - -/// A wrapper so that layout can access only the methods that it should have access to. Layout must -/// only ever see these and must never see instances of `LayoutDom`. -/// FIXME(mrobinson): `Send + Sync` is required here for Layout 2020, but eventually it -/// should stop sending LayoutNodes to other threads and rely on ThreadSafeLayoutNode -/// or some other mechanism to ensure thread safety. -pub trait LayoutNode<'dom>: - Copy + Debug + GetStyleAndOpaqueLayoutData<'dom> + TNode + Send + Sync -{ - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'dom>; - fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; - - /// Returns the type ID of this node. - fn type_id(&self) -> LayoutNodeType; - - unsafe fn initialize_data(&self); - unsafe fn init_style_and_opaque_layout_data(&self, data: Box<StyleAndOpaqueLayoutData>); - unsafe fn take_style_and_opaque_layout_data(&self) -> Box<StyleAndOpaqueLayoutData>; - - fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> { - LayoutIterator(ReverseChildrenIterator { - current: self.last_child(), - }) - } - - fn traverse_preorder(self) -> TreeIterator<Self> { - TreeIterator::new(self) - } - - /// Returns whether the node is connected. - fn is_connected(&self) -> bool; -} - -pub struct ReverseChildrenIterator<ConcreteNode> { - current: Option<ConcreteNode>, -} - -impl<'dom, ConcreteNode> Iterator for ReverseChildrenIterator<ConcreteNode> -where - ConcreteNode: LayoutNode<'dom>, -{ - type Item = ConcreteNode; - fn next(&mut self) -> Option<ConcreteNode> { - let node = self.current; - self.current = node.and_then(|node| node.prev_sibling()); - node - } -} - -pub struct TreeIterator<ConcreteNode> { - stack: Vec<ConcreteNode>, -} - -impl<'dom, ConcreteNode> TreeIterator<ConcreteNode> -where - ConcreteNode: LayoutNode<'dom>, -{ - fn new(root: ConcreteNode) -> TreeIterator<ConcreteNode> { - let mut stack = vec![]; - stack.push(root); - TreeIterator { stack: stack } - } - - pub fn next_skipping_children(&mut self) -> Option<ConcreteNode> { - self.stack.pop() - } -} - -impl<'dom, ConcreteNode> Iterator for TreeIterator<ConcreteNode> -where - ConcreteNode: LayoutNode<'dom>, -{ - type Item = ConcreteNode; - fn next(&mut self) -> Option<ConcreteNode> { - let ret = self.stack.pop(); - ret.map(|node| self.stack.extend(node.rev_children())); - ret - } -} - -/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout -/// node does not allow any parents or siblings of nodes to be accessed, to avoid races. -pub trait ThreadSafeLayoutNode<'dom>: - Clone + Copy + Debug + GetStyleAndOpaqueLayoutData<'dom> + NodeInfo + PartialEq + Sized -{ - type ConcreteNode: LayoutNode<'dom, ConcreteThreadSafeLayoutNode = Self>; - type ConcreteElement: TElement; - - type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<'dom, ConcreteThreadSafeLayoutNode = Self> - + ::selectors::Element<Impl = SelectorImpl>; - type ChildrenIterator: Iterator<Item = Self> + Sized; - - /// Converts self into an `OpaqueNode`. - fn opaque(&self) -> OpaqueNode; - - /// Returns the type ID of this node. - /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. - fn type_id(&self) -> Option<LayoutNodeType>; - - /// Returns the style for a text node. This is computed on the fly from the - /// parent style to avoid traversing text nodes in the style system. - /// - /// Note that this does require accessing the parent, which this interface - /// technically forbids. But accessing the parent is only unsafe insofar as - /// it can be used to reach siblings and cousins. A simple immutable borrow - /// of the parent data is fine, since the bottom-up traversal will not process - /// the parent until all the children have been processed. - fn parent_style(&self) -> Arc<ComputedValues>; - - fn get_before_pseudo(&self) -> Option<Self> { - self.as_element() - .and_then(|el| el.get_before_pseudo()) - .map(|el| el.as_node()) - } - - fn get_after_pseudo(&self) -> Option<Self> { - self.as_element() - .and_then(|el| el.get_after_pseudo()) - .map(|el| el.as_node()) - } - - fn get_details_summary_pseudo(&self) -> Option<Self> { - self.as_element() - .and_then(|el| el.get_details_summary_pseudo()) - .map(|el| el.as_node()) - } - - fn get_details_content_pseudo(&self) -> Option<Self> { - self.as_element() - .and_then(|el| el.get_details_content_pseudo()) - .map(|el| el.as_node()) - } - - fn debug_id(self) -> usize; - - /// Returns an iterator over this node's children. - fn children(&self) -> LayoutIterator<Self::ChildrenIterator>; - - /// Returns a ThreadSafeLayoutElement if this is an element, None otherwise. - fn as_element(&self) -> Option<Self::ConcreteThreadSafeLayoutElement>; - - #[inline] - fn get_pseudo_element_type(&self) -> PseudoElementType { - self.as_element() - .map_or(PseudoElementType::Normal, |el| el.get_pseudo_element_type()) - } - - fn get_style_and_opaque_layout_data(self) -> Option<&'dom StyleAndOpaqueLayoutData>; - - fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues> { - if let Some(el) = self.as_element() { - el.style(context) - } else { - // Text nodes are not styled during traversal,instead we simply - // return parent style here and do cascading during layout. - debug_assert!(self.is_text_node()); - self.parent_style() - } - } - - fn selected_style(&self) -> Arc<ComputedValues> { - if let Some(el) = self.as_element() { - el.selected_style() - } else { - debug_assert!(self.is_text_node()); - // TODO(stshine): What should the selected style be for text? - self.parent_style() - } - } - - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; - - /// Returns true if this node contributes content. This is used in the implementation of - /// `empty_cells` per CSS 2.1 § 17.6.1.1. - fn is_content(&self) -> bool { - self.type_id().is_some() - } - - /// Returns access to the underlying LayoutNode. This is breaks the abstraction - /// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used - /// carefully. - /// - /// We need this because the implementation of some methods need to access the layout - /// data flags, and we have this annoying trait separation between script and layout :-( - unsafe fn unsafe_get(self) -> Self::ConcreteNode; - - fn node_text_content(self) -> Cow<'dom, str>; - - /// If the insertion point is within this node, returns it. Otherwise, returns `None`. - fn selection(&self) -> Option<Range<ByteIndex>>; - - /// If this is an image element, returns its URL. If this is not an image element, fails. - fn image_url(&self) -> Option<ServoUrl>; - - /// If this is an image element, returns its current-pixel-density. If this is not an image element, fails. - fn image_density(&self) -> Option<f64>; - - /// If this is an image element, returns its image data. Otherwise, returns `None`. - fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)>; - - fn canvas_data(&self) -> Option<HTMLCanvasData>; - - fn svg_data(&self) -> Option<SVGSVGData>; - - fn media_data(&self) -> Option<HTMLMediaData>; - - /// If this node is an iframe element, returns its browsing context ID. If this node is - /// not an iframe element, fails. Returns None if there is no nested browsing context. - fn iframe_browsing_context_id(&self) -> Option<BrowsingContextId>; - - /// If this node is an iframe element, returns its pipeline ID. If this node is - /// not an iframe element, fails. Returns None if there is no nested browsing context. - fn iframe_pipeline_id(&self) -> Option<PipelineId>; - - fn get_colspan(&self) -> u32; - - fn get_rowspan(&self) -> u32; - - fn fragment_type(&self) -> FragmentType { - self.get_pseudo_element_type().fragment_type() - } - - fn generate_scroll_id(&self, pipeline_id: PipelineId) -> ExternalScrollId { - let id = combine_id_with_fragment_type(self.opaque().id(), self.fragment_type()); - ExternalScrollId(id as u64, pipeline_id.to_webrender()) - } -} - -pub trait ThreadSafeLayoutElement<'dom>: - Clone - + Copy - + Sized - + Debug - + ::selectors::Element<Impl = SelectorImpl> - + GetStyleAndOpaqueLayoutData<'dom> -{ - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode< - 'dom, - ConcreteThreadSafeLayoutElement = Self, - >; - - /// This type alias is just a work-around to avoid writing - /// - /// <Self::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteElement - /// - type ConcreteElement: TElement; - - fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode; - - /// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType) -> Self; - - /// Returns the type ID of this node. - /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. - fn type_id(&self) -> Option<LayoutNodeType>; - - /// Returns access to the underlying TElement. This is breaks the abstraction - /// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used - /// carefully. - /// - /// We need this so that the functions defined on this trait can call - /// lazily_compute_pseudo_element_style, which operates on TElement. - unsafe fn unsafe_get(self) -> Self::ConcreteElement; - - fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str>; - - fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue>; - - fn style_data(&self) -> AtomicRef<ElementData>; - - fn get_pseudo_element_type(&self) -> PseudoElementType; - - #[inline] - fn get_before_pseudo(&self) -> Option<Self> { - if self - .style_data() - .styles - .pseudos - .get(&PseudoElement::Before) - .is_some() - { - Some(self.with_pseudo(PseudoElementType::Before)) - } else { - None - } - } - - #[inline] - fn get_after_pseudo(&self) -> Option<Self> { - if self - .style_data() - .styles - .pseudos - .get(&PseudoElement::After) - .is_some() - { - Some(self.with_pseudo(PseudoElementType::After)) - } else { - None - } - } - - #[inline] - fn get_details_summary_pseudo(&self) -> Option<Self> { - if self.has_local_name(&local_name!("details")) && self.has_namespace(&ns!(html)) { - Some(self.with_pseudo(PseudoElementType::DetailsSummary)) - } else { - None - } - } - - #[inline] - fn get_details_content_pseudo(&self) -> Option<Self> { - if self.has_local_name(&local_name!("details")) && - self.has_namespace(&ns!(html)) && - self.get_attr(&ns!(), &local_name!("open")).is_some() - { - Some(self.with_pseudo(PseudoElementType::DetailsContent)) - } else { - None - } - } - - /// Returns the style results for the given node. If CSS selector matching - /// has not yet been performed, fails. - /// - /// Unlike the version on TNode, this handles pseudo-elements. - #[inline] - fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues> { - let data = self.style_data(); - match self.get_pseudo_element_type() { - PseudoElementType::Normal => data.styles.primary().clone(), - other => { - // Precompute non-eagerly-cascaded pseudo-element styles if not - // cached before. - let style_pseudo = other.style_pseudo_element(); - match style_pseudo.cascade_type() { - // Already computed during the cascade. - PseudoElementCascadeType::Eager => self - .style_data() - .styles - .pseudos - .get(&style_pseudo) - .unwrap() - .clone(), - PseudoElementCascadeType::Precomputed => context - .stylist - .precomputed_values_for_pseudo::<Self::ConcreteElement>( - &context.guards, - &style_pseudo, - Some(data.styles.primary()), - ), - PseudoElementCascadeType::Lazy => { - context - .stylist - .lazily_compute_pseudo_element_style( - &context.guards, - unsafe { self.unsafe_get() }, - &style_pseudo, - RuleInclusion::All, - data.styles.primary(), - /* is_probe = */ false, - /* matching_func = */ None, - ) - .unwrap() - }, - } - }, - } - } - - #[inline] - fn selected_style(&self) -> Arc<ComputedValues> { - let data = self.style_data(); - data.styles - .pseudos - .get(&PseudoElement::Selection) - .unwrap_or(data.styles.primary()) - .clone() - } - - /// Returns the already resolved style of the node. - /// - /// This differs from `style(ctx)` in that if the pseudo-element has not yet - /// been computed it would panic. - /// - /// This should be used just for querying layout, or when we know the - /// element style is precomputed, not from general layout itself. - #[inline] - fn resolved_style(&self) -> Arc<ComputedValues> { - let data = self.style_data(); - match self.get_pseudo_element_type() { - PseudoElementType::Normal => data.styles.primary().clone(), - other => data - .styles - .pseudos - .get(&other.style_pseudo_element()) - .unwrap() - .clone(), - } - } - - fn is_shadow_host(&self) -> bool; - - /// Returns whether this node is a body element of an html element root - /// in an HTML element document. - /// - /// Note that this does require accessing the parent, which this interface - /// technically forbids. But accessing the parent is only unsafe insofar as - /// it can be used to reach siblings and cousins. A simple immutable borrow - /// of the parent data is fine, since the bottom-up traversal will not process - /// the parent until all the children have been processed. - fn is_body_element_of_html_element_root(&self) -> bool; -} |