From 0d0b268138674598e4c9c6e979b9245cfbc795d6 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 15 Jun 2016 15:04:04 +0100 Subject: [PATCH] Move LayoutNode and related traits to script_layout_interface. --- components/layout/construct.rs | 4 +- components/layout/flow.rs | 2 +- components/layout/fragment.rs | 2 +- components/layout/generated_content.rs | 2 +- components/layout/inline.rs | 2 +- components/layout/layout_thread.rs | 3 +- components/layout/query.rs | 3 +- components/layout/table_cell.rs | 2 +- components/layout/traversal.rs | 4 +- components/layout/wrapper.rs | 351 +---------------- components/script_layout_interface/Cargo.toml | 6 + components/script_layout_interface/lib.rs | 8 + .../script_layout_interface/wrapper_traits.rs | 366 ++++++++++++++++++ components/servo/Cargo.lock | 6 + ports/cef/Cargo.lock | 6 + 15 files changed, 408 insertions(+), 359 deletions(-) create mode 100644 components/script_layout_interface/wrapper_traits.rs diff --git a/components/layout/construct.rs b/components/layout/construct.rs index c600b0ce8e6..27c6f629ca6 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -35,6 +35,7 @@ use multicol::{MulticolFlow, MulticolColumnFlow}; use parallel; use script::layout_interface::is_image_data; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, RECONSTRUCT_FLOW, RestyleDamage}; +use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, PseudoElementType, ThreadSafeLayoutElement}; use script_layout_interface::{LayoutNodeType, LayoutElementType}; use std::borrow::ToOwned; use std::collections::LinkedList; @@ -59,8 +60,7 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement}; -use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::{TextContent, ThreadSafeLayoutNodeHelpers}; /// The results of flow construction for a DOM node. #[derive(Clone)] diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 79aa1daaaa5..3dc7fac29dc 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -42,6 +42,7 @@ use multicol::MulticolFlow; use parallel::FlowParallelInfo; use rustc_serialize::{Encodable, Encoder}; use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; +use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutNode}; use std::iter::Zip; use std::slice::IterMut; use std::sync::Arc; @@ -60,7 +61,6 @@ use table_row::TableRowFlow; use table_rowgroup::TableRowGroupFlow; use table_wrapper::TableWrapperFlow; use util::print_tree::PrintTree; -use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; /// Virtual methods that make up a float context. /// diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 42fab6a7b8c..28d88e48da3 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -31,6 +31,7 @@ use range::*; use rustc_serialize::{Encodable, Encoder}; use script_layout_interface::HTMLCanvasData; use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, RestyleDamage}; +use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use std::borrow::ToOwned; use std::cmp::{max, min}; use std::collections::LinkedList; @@ -49,7 +50,6 @@ use text; use text::TextRunScanner; use url::Url; use util; -use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position /// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index b6264859faa..33a1d21f0d1 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -14,6 +14,7 @@ use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, Immutab use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use gfx::display_list::OpaqueNode; use script_layout_interface::restyle_damage::{RESOLVE_GENERATED_CONTENT, RestyleDamage}; +use script_layout_interface::wrapper_traits::PseudoElementType; use smallvec::SmallVec; use std::collections::{HashMap, LinkedList}; use std::sync::Arc; @@ -22,7 +23,6 @@ use style::computed_values::{display, list_style_type}; use style::dom::TRestyleDamage; use style::properties::{ComputedValues, ServoComputedValues}; use text::TextRunScanner; -use wrapper::PseudoElementType; // Decimal styles per CSS-COUNTER-STYLES § 6.1: static DECIMAL: [char; 10] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]; diff --git a/components/layout/inline.rs b/components/layout/inline.rs index e0e390557db..2b366acedac 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -26,6 +26,7 @@ use model::IntrinsicISizesContribution; use range::{Range, RangeIndex}; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW}; use script_layout_interface::restyle_damage::{REPAINT, RESOLVE_GENERATED_CONTENT}; +use script_layout_interface::wrapper_traits::PseudoElementType; use std::cmp::max; use std::collections::VecDeque; use std::sync::Arc; @@ -39,7 +40,6 @@ use text; use unicode_bidi; use util; use util::print_tree::PrintTree; -use wrapper::PseudoElementType; // From gfxFontConstants.h in Firefox static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20; diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index d72653dc634..0493bf9b32e 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -50,6 +50,7 @@ use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResp use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow}; use script::reporter::CSSErrorReporter; use script_layout_interface::restyle_damage::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW}; +use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg}; use script_traits::{StackingContextScrollState, UntrustedNodeAddress}; @@ -85,7 +86,7 @@ use util::thread_state; use util::workqueue::WorkQueue; use webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder}; use webrender_traits; -use wrapper::{LayoutNode, LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; +use wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData, ServoLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8; diff --git a/components/layout/query.rs b/components/layout/query.rs index 728cf75e7a9..89b03457175 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -19,6 +19,7 @@ use opaque_node::OpaqueNodeMethods; use script::layout_interface::{ContentBoxResponse, NodeOverflowResponse, ContentBoxesResponse, NodeGeometryResponse}; use script::layout_interface::{HitTestResponse, LayoutRPC, OffsetParentResponse, NodeLayerIdResponse}; use script::layout_interface::{ResolvedStyleResponse, MarginStyleResponse}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; use sequential; @@ -34,7 +35,7 @@ use style::properties::style_structs; use style::selector_impl::PseudoElement; use style::values::AuExtensionMethods; use style_traits::cursor::Cursor; -use wrapper::{LayoutNode, ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::ThreadSafeLayoutNodeHelpers; pub struct LayoutRPCImpl(pub Arc>); diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 1038328b7af..4f043e351c4 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -19,6 +19,7 @@ use gfx_traits::StackingContextId; use layout_debug; use model::MaybeAuto; use script_layout_interface::restyle_damage::REFLOW; +use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode; use std::fmt; use std::sync::Arc; use style::computed_values::{border_collapse, border_top_style, vertical_align}; @@ -27,7 +28,6 @@ use style::properties::{ComputedValues, ServoComputedValues}; use table::InternalTable; use table_row::{CollapsedBorder, CollapsedBorderProvenance}; use util::print_tree::PrintTree; -use wrapper::ThreadSafeLayoutNode; /// A table formatting context. #[derive(RustcEncodable)] diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 27734312e1f..f7f963fdb41 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -11,6 +11,7 @@ use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal}; use flow::{PreorderFlowTraversal, self}; use gfx::display_list::OpaqueNode; use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use std::mem; use style::context::StyleContext; use style::matching::MatchMethods; @@ -18,8 +19,7 @@ use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, LayoutNodeLayoutData, ServoLayoutNode}; -use wrapper::{ThreadSafeLayoutNode, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeLayoutData, ServoLayoutNode, ThreadSafeLayoutNodeHelpers}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index f96020e287e..4c4a77f12e9 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -34,7 +34,6 @@ use core::nonzero::NonZero; use data::{LayoutDataFlags, PrivateLayoutData}; use gfx::display_list::OpaqueNode; use gfx::text::glyph::ByteIndex; -use gfx_traits::{LayerId, LayerType}; use msg::constellation_msg::PipelineId; use opaque_node::OpaqueNodeMethods; use range::Range; @@ -45,6 +44,8 @@ use script::layout_interface::{LayoutDocumentHelpers, LayoutElementHelpers, Layo use script::layout_interface::{LayoutNodeHelpers, Node, NodeTypeId}; use script::layout_interface::{RawLayoutElementHelpers, Text, TrustedNodeAddress}; use script_layout_interface::restyle_damage::RestyleDamage; +use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, LayoutNode, PseudoElementType}; +use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, ThreadSafeLayoutElement}; use script_layout_interface::{HTMLCanvasData, LayoutNodeType}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData}; use selectors::matching::{DeclarationBlock, ElementFlags}; @@ -53,7 +54,6 @@ use smallvec::VecLike; use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; use std::mem::{transmute, transmute_copy}; -use std::sync::Arc; use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace}; use style::attr::AttrValue; use style::computed_values::content::ContentItem; @@ -63,29 +63,13 @@ use style::element_state::*; use style::properties::{ComputedValues, ServoComputedValues}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::restyle_hints::ElementSnapshot; -use style::selector_impl::{NonTSPseudoClass, PseudoElement, PseudoElementCascadeType, ServoSelectorImpl}; +use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; use style::servo::{PrivateStyleData, SharedStyleContext}; use url::Url; use util::str::is_whitespace; pub type NonOpaqueStyleAndLayoutData = *mut RefCell; -/// 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 `LayoutJS`. - -pub trait LayoutNode: TNode { - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; - fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; - - /// Returns the type ID of this node. - fn type_id(&self) -> LayoutNodeType; - - fn get_style_data(&self) -> Option<&RefCell>; - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); - fn get_style_and_layout_data(&self) -> Option; -} - pub trait LayoutNodeLayoutData { /// Similar to borrow_data*, but returns the full PrivateLayoutData rather /// than only the PrivateStyleData. @@ -650,313 +634,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { } } -#[derive(Copy, PartialEq, Clone)] -pub enum PseudoElementType { - Normal, - Before(T), - After(T), - DetailsSummary(T), - DetailsContent(T), -} - -impl PseudoElementType { - 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 strip(&self) -> PseudoElementType<()> { - match *self { - PseudoElementType::Normal => PseudoElementType::Normal, - PseudoElementType::Before(_) => PseudoElementType::Before(()), - PseudoElementType::After(_) => PseudoElementType::After(()), - PseudoElementType::DetailsSummary(_) => PseudoElementType::DetailsSummary(()), - PseudoElementType::DetailsContent(_) => PseudoElementType::DetailsContent(()), - } - } - - 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, - } - } -} - -/// 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: Clone + Copy + Sized + PartialEq { - type ConcreteThreadSafeLayoutElement: - ThreadSafeLayoutElement - + ::selectors::Element; - type ChildrenIterator: Iterator + Sized; - - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType>) -> Self; - - /// 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; - - /// Returns the type ID of this node, without discarding pseudo-elements as - /// `type_id` does. - fn type_id_without_excluding_pseudo_elements(&self) -> LayoutNodeType; - - #[inline] - fn is_element_or_elements_pseudo(&self) -> bool { - match self.type_id_without_excluding_pseudo_elements() { - LayoutNodeType::Element(..) => true, - _ => false, - } - } - - fn debug_id(self) -> usize; - - /// Returns an iterator over this node's children. - fn children(&self) -> Self::ChildrenIterator; - - #[inline] - fn is_element(&self) -> bool { if let Some(LayoutNodeType::Element(_)) = self.type_id() { true } else { false } } - - /// If this is an element, accesses the element data. Fails if this is not an element node. - #[inline] - fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement; - - #[inline] - fn get_pseudo_element_type(&self) -> PseudoElementType>; - - #[inline] - fn get_before_pseudo(&self) -> Option { - if self.get_style_data() - .unwrap() - .borrow() - .style_data - .per_pseudo - .contains_key(&PseudoElement::Before) { - Some(self.with_pseudo(PseudoElementType::Before(None))) - } else { - None - } - } - - #[inline] - fn get_after_pseudo(&self) -> Option { - if self.get_style_data() - .unwrap() - .borrow() - .style_data - .per_pseudo - .contains_key(&PseudoElement::After) { - Some(self.with_pseudo(PseudoElementType::After(None))) - } else { - None - } - } - - #[inline] - fn get_details_summary_pseudo(&self) -> Option { - if self.is_element() && - self.as_element().get_local_name() == atom!("details") && - self.as_element().get_namespace() == ns!(html) { - Some(self.with_pseudo(PseudoElementType::DetailsSummary(None))) - } else { - None - } - } - - #[inline] - fn get_details_content_pseudo(&self) -> Option { - if self.is_element() && - self.as_element().get_local_name() == atom!("details") && - self.as_element().get_namespace() == ns!(html) { - let display = if self.as_element().get_attr(&ns!(), &atom!("open")).is_some() { - None // Specified by the stylesheet - } else { - Some(display::T::none) - }; - Some(self.with_pseudo(PseudoElementType::DetailsContent(display))) - } else { - None - } - } - - fn get_style_and_layout_data(&self) -> Option; - - /// 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) -> Ref> { - match self.get_pseudo_element_type() { - PseudoElementType::Normal => { - Ref::map(self.get_style_data().unwrap().borrow(), |data| { - data.style_data.style.as_ref().unwrap() - }) - }, - 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 => {}, - PseudoElementCascadeType::Precomputed => { - if !self.get_style_data() - .unwrap() - .borrow() - .style_data - .per_pseudo.contains_key(&style_pseudo) { - let mut data = self.get_style_data().unwrap().borrow_mut(); - let new_style = - context.stylist - .precomputed_values_for_pseudo(&style_pseudo, - data.style_data.style.as_ref()); - data.style_data.per_pseudo - .insert(style_pseudo.clone(), new_style.unwrap()); - } - } - PseudoElementCascadeType::Lazy => { - debug_assert!(self.is_element_or_elements_pseudo()); - if !self.get_style_data() - .unwrap() - .borrow() - .style_data - .per_pseudo.contains_key(&style_pseudo) { - let mut data = self.get_style_data().unwrap().borrow_mut(); - let new_style = - context.stylist - .lazily_compute_pseudo_element_style( - &self.as_element(), - &style_pseudo, - data.style_data.style.as_ref().unwrap()); - data.style_data.per_pseudo - .insert(style_pseudo.clone(), new_style.unwrap()); - } - } - } - - Ref::map(self.get_style_data().unwrap().borrow(), |data| { - data.style_data.per_pseudo.get(&style_pseudo).unwrap() - }) - } - } - } - - /// 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) -> Ref> { - Ref::map(self.get_style_data().unwrap().borrow(), |data| { - match self.get_pseudo_element_type() { - PseudoElementType::Normal - => data.style_data.style.as_ref().unwrap(), - other - => data.style_data.per_pseudo.get(&other.style_pseudo_element()).unwrap(), - } - }) - } - - #[inline] - fn selected_style(&self, _context: &SharedStyleContext) -> Ref> { - Ref::map(self.get_style_data().unwrap().borrow(), |data| { - data.style_data.per_pseudo - .get(&PseudoElement::Selection) - .unwrap_or(data.style_data.style.as_ref().unwrap()) - }) - } - - /// Removes the style from this node. - /// - /// Unlike the version on TNode, this handles pseudo-elements. - fn unstyle(self) { - let mut data = self.get_style_data().unwrap().borrow_mut(); - - match self.get_pseudo_element_type() { - PseudoElementType::Normal => { - data.style_data.style = None; - } - other => { - data.style_data.per_pseudo.remove(&other.style_pseudo_element()); - } - }; - } - - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; - - fn restyle_damage(self) -> RestyleDamage; - - fn set_restyle_damage(self, damage: RestyleDamage); - - /// 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 { - match self.type_id() { - Some(LayoutNodeType::Element(..)) | Some(LayoutNodeType::Text) => true, - _ => false - } - } - - fn can_be_fragmented(&self) -> bool; - - fn node_text_content(&self) -> String; - - /// If the insertion point is within this node, returns it. Otherwise, returns `None`. - fn selection(&self) -> Option>; - - /// If this is an image element, returns its URL. If this is not an image element, fails. - /// - /// FIXME(pcwalton): Don't copy URLs. - fn image_url(&self) -> Option; - - fn canvas_data(&self) -> Option; - - /// If this node is an iframe element, returns its pipeline ID. If this node is - /// not an iframe element, fails. - fn iframe_pipeline_id(&self) -> PipelineId; - - fn get_colspan(&self) -> u32; - - fn layer_id(&self) -> LayerId { - let layer_type = match self.get_pseudo_element_type() { - PseudoElementType::Normal => LayerType::FragmentBody, - PseudoElementType::Before(_) => LayerType::BeforePseudoContent, - PseudoElementType::After(_) => LayerType::AfterPseudoContent, - PseudoElementType::DetailsSummary(_) => LayerType::FragmentBody, - PseudoElementType::DetailsContent(_) => LayerType::FragmentBody, - }; - LayerId::new_of_type(layer_type, self.opaque().id() as usize) - } - - fn layer_id_for_overflow_scroll(&self) -> LayerId { - LayerId::new_of_type(LayerType::OverflowScroll, self.opaque().id() as usize) - } - - fn get_style_data(&self) -> Option<&RefCell>; -} - pub trait ThreadSafeLayoutNodeHelpers { fn flow_debug_id(self) -> usize; @@ -990,28 +667,6 @@ pub trait ThreadSafeLayoutNodeHelpers { fn text_content(&self) -> TextContent; } -// This trait is only public so that it can be implemented by the gecko wrapper. -// It can be used to violate thread-safety, so don't use it elsewhere in layout! -pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { - unsafe fn dangerous_first_child(&self) -> Option; - unsafe fn dangerous_next_sibling(&self) -> Option; -} - -pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + - ::selectors::Element + - PresentationalHintsSynthetizer { - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; - - #[inline] - fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; - - #[inline] - fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a>; - - #[inline] - fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a>; -} - #[derive(Copy, Clone)] pub struct ServoThreadSafeLayoutNode<'ln> { /// The wrapped node. diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 32ff5c4dd2a..5765f4a5e90 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -11,8 +11,14 @@ path = "lib.rs" [dependencies] bitflags = "0.7" canvas_traits = {path = "../canvas_traits"} +gfx_traits = {path = "../gfx_traits"} heapsize = "0.3.0" heapsize_plugin = "0.1.2" ipc-channel = {git = "https://github.com/servo/ipc-channel"} +msg = {path = "../msg"} plugins = {path = "../plugins"} +range = {path = "../range"} +selectors = {version = "0.6", features = ["heap_size"]} +string_cache = {version = "0.2.20", features = ["heap_size"]} style = {path = "../style"} +url = {version = "1.0.0", features = ["heap_size"]} diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index e7fa1e3ae6c..8917aad6a76 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -19,11 +19,19 @@ extern crate bitflags; extern crate canvas_traits; extern crate core; +extern crate gfx_traits; extern crate heapsize; extern crate ipc_channel; +extern crate msg; +extern crate range; +extern crate selectors; +#[macro_use(atom, ns)] +extern crate string_cache; extern crate style; +extern crate url; pub mod restyle_damage; +pub mod wrapper_traits; use canvas_traits::CanvasMsg; use core::nonzero::NonZero; diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs new file mode 100644 index 00000000000..145f9dd067b --- /dev/null +++ b/components/script_layout_interface/wrapper_traits.rs @@ -0,0 +1,366 @@ +/* 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/. */ + +use HTMLCanvasData; +use LayoutNodeType; +use OpaqueStyleAndLayoutData; +use PartialStyleAndLayoutData; +use gfx_traits::{ByteIndex, LayerId, LayerType}; +use msg::constellation_msg::PipelineId; +use range::Range; +use restyle_damage::RestyleDamage; +use std::cell::{Ref, RefCell}; +use std::sync::Arc; +use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace}; +use style::computed_values::display; +use style::dom::OpaqueNode; +use style::dom::{PresentationalHintsSynthetizer, TNode}; +use style::properties::ServoComputedValues; +use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl}; +use style::servo::SharedStyleContext; +use url::Url; + +#[derive(Copy, PartialEq, Clone)] +pub enum PseudoElementType { + Normal, + Before(T), + After(T), + DetailsSummary(T), + DetailsContent(T), +} + +impl PseudoElementType { + 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 strip(&self) -> PseudoElementType<()> { + match *self { + PseudoElementType::Normal => PseudoElementType::Normal, + PseudoElementType::Before(_) => PseudoElementType::Before(()), + PseudoElementType::After(_) => PseudoElementType::After(()), + PseudoElementType::DetailsSummary(_) => PseudoElementType::DetailsSummary(()), + PseudoElementType::DetailsContent(_) => PseudoElementType::DetailsContent(()), + } + } + + 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, + } + } +} + +/// 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 `LayoutJS`. +pub trait LayoutNode: TNode { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; + fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; + + /// Returns the type ID of this node. + fn type_id(&self) -> LayoutNodeType; + + fn get_style_data(&self) -> Option<&RefCell>; + + fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); + fn get_style_and_layout_data(&self) -> Option; +} + +/// 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: Clone + Copy + Sized + PartialEq { + type ConcreteThreadSafeLayoutElement: + ThreadSafeLayoutElement + + ::selectors::Element; + type ChildrenIterator: Iterator + Sized; + + /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` + /// with a different pseudo-element type. + fn with_pseudo(&self, pseudo: PseudoElementType>) -> Self; + + /// 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; + + /// Returns the type ID of this node, without discarding pseudo-elements as + /// `type_id` does. + fn type_id_without_excluding_pseudo_elements(&self) -> LayoutNodeType; + + #[inline] + fn is_element_or_elements_pseudo(&self) -> bool { + match self.type_id_without_excluding_pseudo_elements() { + LayoutNodeType::Element(..) => true, + _ => false, + } + } + + fn debug_id(self) -> usize; + + /// Returns an iterator over this node's children. + fn children(&self) -> Self::ChildrenIterator; + + #[inline] + fn is_element(&self) -> bool { if let Some(LayoutNodeType::Element(_)) = self.type_id() { true } else { false } } + + /// If this is an element, accesses the element data. Fails if this is not an element node. + #[inline] + fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement; + + #[inline] + fn get_pseudo_element_type(&self) -> PseudoElementType>; + + #[inline] + fn get_before_pseudo(&self) -> Option { + if self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo + .contains_key(&PseudoElement::Before) { + Some(self.with_pseudo(PseudoElementType::Before(None))) + } else { + None + } + } + + #[inline] + fn get_after_pseudo(&self) -> Option { + if self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo + .contains_key(&PseudoElement::After) { + Some(self.with_pseudo(PseudoElementType::After(None))) + } else { + None + } + } + + #[inline] + fn get_details_summary_pseudo(&self) -> Option { + if self.is_element() && + self.as_element().get_local_name() == atom!("details") && + self.as_element().get_namespace() == ns!(html) { + Some(self.with_pseudo(PseudoElementType::DetailsSummary(None))) + } else { + None + } + } + + #[inline] + fn get_details_content_pseudo(&self) -> Option { + if self.is_element() && + self.as_element().get_local_name() == atom!("details") && + self.as_element().get_namespace() == ns!(html) { + let display = if self.as_element().get_attr(&ns!(), &atom!("open")).is_some() { + None // Specified by the stylesheet + } else { + Some(display::T::none) + }; + Some(self.with_pseudo(PseudoElementType::DetailsContent(display))) + } else { + None + } + } + + fn get_style_and_layout_data(&self) -> Option; + + /// 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) -> Ref> { + match self.get_pseudo_element_type() { + PseudoElementType::Normal => { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { + data.style_data.style.as_ref().unwrap() + }) + }, + 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 => {}, + PseudoElementCascadeType::Precomputed => { + if !self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo.contains_key(&style_pseudo) { + let mut data = self.get_style_data().unwrap().borrow_mut(); + let new_style = + context.stylist + .precomputed_values_for_pseudo(&style_pseudo, + data.style_data.style.as_ref()); + data.style_data.per_pseudo + .insert(style_pseudo.clone(), new_style.unwrap()); + } + } + PseudoElementCascadeType::Lazy => { + debug_assert!(self.is_element_or_elements_pseudo()); + if !self.get_style_data() + .unwrap() + .borrow() + .style_data + .per_pseudo.contains_key(&style_pseudo) { + let mut data = self.get_style_data().unwrap().borrow_mut(); + let new_style = + context.stylist + .lazily_compute_pseudo_element_style( + &self.as_element(), + &style_pseudo, + data.style_data.style.as_ref().unwrap()); + data.style_data.per_pseudo + .insert(style_pseudo.clone(), new_style.unwrap()); + } + } + } + + Ref::map(self.get_style_data().unwrap().borrow(), |data| { + data.style_data.per_pseudo.get(&style_pseudo).unwrap() + }) + } + } + } + + /// 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) -> Ref> { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { + match self.get_pseudo_element_type() { + PseudoElementType::Normal + => data.style_data.style.as_ref().unwrap(), + other + => data.style_data.per_pseudo.get(&other.style_pseudo_element()).unwrap(), + } + }) + } + + #[inline] + fn selected_style(&self, _context: &SharedStyleContext) -> Ref> { + Ref::map(self.get_style_data().unwrap().borrow(), |data| { + data.style_data.per_pseudo + .get(&PseudoElement::Selection) + .unwrap_or(data.style_data.style.as_ref().unwrap()) + }) + } + + /// Removes the style from this node. + /// + /// Unlike the version on TNode, this handles pseudo-elements. + fn unstyle(self) { + let mut data = self.get_style_data().unwrap().borrow_mut(); + + match self.get_pseudo_element_type() { + PseudoElementType::Normal => { + data.style_data.style = None; + } + other => { + data.style_data.per_pseudo.remove(&other.style_pseudo_element()); + } + }; + } + + fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; + + fn restyle_damage(self) -> RestyleDamage; + + fn set_restyle_damage(self, damage: RestyleDamage); + + /// 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 { + match self.type_id() { + Some(LayoutNodeType::Element(..)) | Some(LayoutNodeType::Text) => true, + _ => false + } + } + + fn can_be_fragmented(&self) -> bool; + + fn node_text_content(&self) -> String; + + /// If the insertion point is within this node, returns it. Otherwise, returns `None`. + fn selection(&self) -> Option>; + + /// If this is an image element, returns its URL. If this is not an image element, fails. + /// + /// FIXME(pcwalton): Don't copy URLs. + fn image_url(&self) -> Option; + + fn canvas_data(&self) -> Option; + + /// If this node is an iframe element, returns its pipeline ID. If this node is + /// not an iframe element, fails. + fn iframe_pipeline_id(&self) -> PipelineId; + + fn get_colspan(&self) -> u32; + + fn layer_id(&self) -> LayerId { + let layer_type = match self.get_pseudo_element_type() { + PseudoElementType::Normal => LayerType::FragmentBody, + PseudoElementType::Before(_) => LayerType::BeforePseudoContent, + PseudoElementType::After(_) => LayerType::AfterPseudoContent, + PseudoElementType::DetailsSummary(_) => LayerType::FragmentBody, + PseudoElementType::DetailsContent(_) => LayerType::FragmentBody, + }; + LayerId::new_of_type(layer_type, self.opaque().id() as usize) + } + + fn layer_id_for_overflow_scroll(&self) -> LayerId { + LayerId::new_of_type(LayerType::OverflowScroll, self.opaque().id() as usize) + } + + fn get_style_data(&self) -> Option<&RefCell>; +} + +// This trait is only public so that it can be implemented by the gecko wrapper. +// It can be used to violate thread-safety, so don't use it elsewhere in layout! +#[allow(unsafe_code)] +pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { + unsafe fn dangerous_first_child(&self) -> Option; + unsafe fn dangerous_next_sibling(&self) -> Option; +} + +pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + + ::selectors::Element + + PresentationalHintsSynthetizer { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; + + #[inline] + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; + + #[inline] + fn get_local_name<'a>(&'a self) -> BorrowedAtom<'a>; + + #[inline] + fn get_namespace<'a>(&'a self) -> BorrowedNamespace<'a>; +} diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 12e003e0177..251356da56c 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1932,11 +1932,17 @@ version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", + "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.3 (git+https://github.com/servo/ipc-channel)", + "msg 0.0.1", "plugins 0.0.1", + "range 0.0.1", + "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", + "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 60c7a11a4a6..1d8d416e22c 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1790,11 +1790,17 @@ version = "0.0.1" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", + "gfx_traits 0.0.1", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_plugin 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.2.3 (git+https://github.com/servo/ipc-channel)", + "msg 0.0.1", "plugins 0.0.1", + "range 0.0.1", + "selectors 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", + "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]]