diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/construct.rs | 24 | ||||
-rw-r--r-- | components/layout/fragment.rs | 4 | ||||
-rw-r--r-- | components/layout/query.rs | 32 | ||||
-rw-r--r-- | components/layout/traversal.rs | 2 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 58 | ||||
-rw-r--r-- | components/script/layout_wrapper.rs | 141 | ||||
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 246 |
7 files changed, 260 insertions, 247 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 7c7eff8bc0c..03d7e767f69 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -62,7 +62,7 @@ use text::TextRunScanner; use traversal::PostorderNodeMutTraversal; use url::Url; use util::opts; -use wrapper::{TextContent, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeLayoutData, TextContent, ThreadSafeLayoutNodeHelpers}; /// The results of flow construction for a DOM node. #[derive(Clone)] @@ -221,7 +221,7 @@ impl InlineFragmentsAccumulator { address: node.opaque(), pseudo: node.get_pseudo_element_type().strip(), style: node.style(style_context), - selected_style: node.selected_style(style_context), + selected_style: node.selected_style(), flags: InlineFragmentNodeFlags::empty(), }), bidi_control_chars: None, @@ -514,11 +514,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> box UnscannedTextFragmentInfo::new(" ".to_owned(), None)); properties::modify_style_for_replaced_content(&mut whitespace_style); properties::modify_style_for_text(&mut whitespace_style); - let style_context = self.style_context(); let fragment = Fragment::from_opaque_node_and_style(whitespace_node, whitespace_pseudo, whitespace_style, - node.selected_style(style_context), + node.selected_style(), whitespace_damage, fragment_info); inline_fragment_accumulator.fragments.fragments.push_back(fragment); @@ -650,7 +649,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> _ => properties::modify_style_for_text(&mut style) } - let selected_style = node.selected_style(self.style_context()); + let selected_style = node.selected_style(); match text_content { TextContent::Text(string) => { @@ -811,7 +810,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> Fragment::from_opaque_node_and_style(whitespace_node, whitespace_pseudo, whitespace_style, - node.selected_style(self.style_context()), + node.selected_style(), whitespace_damage, fragment_info); fragment_accumulator.fragments.fragments.push_back(fragment) @@ -834,7 +833,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(node.opaque(), node.get_pseudo_element_type().strip(), modified_style, - node.selected_style(self.style_context()), + node.selected_style(), node.restyle_damage(), info); fragment_accumulator.fragments.fragments.push_back(fragment) @@ -921,7 +920,6 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> _ => unreachable!() }; - let style_context = self.style_context(); let mut modified_style = node.style(self.style_context()); properties::modify_style_for_outer_inline_block_fragment(&mut modified_style); let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new( @@ -929,7 +927,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(node.opaque(), node.get_pseudo_element_type().strip(), modified_style, - node.selected_style(style_context), + node.selected_style(), node.restyle_damage(), fragment_info); @@ -964,7 +962,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let fragment = Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, style, - node.selected_style(style_context), + node.selected_style(), node.restyle_damage(), fragment_info); @@ -1076,7 +1074,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, wrapper_style, - node.selected_style(self.style_context()), + node.selected_style(), node.restyle_damage(), SpecificFragmentInfo::TableWrapper); let wrapper_float_kind = FloatKind::from_property(float_value); @@ -1661,7 +1659,7 @@ trait ObjectElement { impl<N> ObjectElement for N where N: ThreadSafeLayoutNode { fn has_object_data(&self) -> bool { - let elem = self.as_element(); + let elem = self.as_element().unwrap(); let type_and_data = (elem.get_attr(&ns!(), &atom!("type")), elem.get_attr(&ns!(), &atom!("data"))); match type_and_data { (None, Some(uri)) => is_image_data(uri), @@ -1670,7 +1668,7 @@ impl<N> ObjectElement for N where N: ThreadSafeLayoutNode { } fn object_data(&self) -> Option<Url> { - let elem = self.as_element(); + let elem = self.as_element().unwrap(); let type_and_data = (elem.get_attr(&ns!(), &atom!("type")), elem.get_attr(&ns!(), &atom!("data"))); match type_and_data { (None, Some(uri)) if is_image_data(uri) => Url::parse(uri).ok(), diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index e79360d08f4..ab9563c90bc 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -885,7 +885,7 @@ pub struct TableColumnFragmentInfo { impl TableColumnFragmentInfo { /// Create the information specific to an table column fragment. pub fn new<N: ThreadSafeLayoutNode>(node: &N) -> TableColumnFragmentInfo { - let element = node.as_element(); + let element = node.as_element().unwrap(); let span = element.get_attr(&ns!(), &atom!("span")) .and_then(|string| string.parse().ok()) .unwrap_or(0); @@ -908,7 +908,7 @@ impl Fragment { Fragment { node: node.opaque(), style: style, - selected_style: node.selected_style(style_context), + selected_style: node.selected_style(), restyle_damage: restyle_damage, border_box: LogicalRect::zero(writing_mode), border_padding: LogicalMargin::zero(writing_mode), diff --git a/components/layout/query.rs b/components/layout/query.rs index b491f08632d..8b394ac8fec 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -19,7 +19,7 @@ use script_layout_interface::rpc::{HitTestResponse, LayoutRPC}; use script_layout_interface::rpc::{MarginStyleResponse, NodeGeometryResponse}; use script_layout_interface::rpc::{NodeOverflowResponse, OffsetParentResponse}; use script_layout_interface::rpc::ResolvedStyleResponse; -use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; use sequential; @@ -36,7 +36,7 @@ use style::selector_impl::PseudoElement; use style::selector_matching::Stylist; use style::values::LocalToCss; use style_traits::cursor::Cursor; -use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeHelpers, LayoutNodeLayoutData}; /// Mutable data belonging to the LayoutThread. /// @@ -640,27 +640,27 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N, ensure_node_data_initialized(&requested_node); ensure_element_styled(requested_node.as_element().unwrap(), style_context); - let layout_node = requested_node.to_threadsafe(); - let layout_node = match *pseudo { - Some(PseudoElement::Before) => layout_node.get_before_pseudo(), - Some(PseudoElement::After) => layout_node.get_after_pseudo(), + let layout_el = requested_node.to_threadsafe().as_element().unwrap(); + let layout_el = match *pseudo { + Some(PseudoElement::Before) => layout_el.get_before_pseudo(), + Some(PseudoElement::After) => layout_el.get_after_pseudo(), Some(PseudoElement::DetailsSummary) | Some(PseudoElement::DetailsContent) | Some(PseudoElement::Selection) => None, - _ => Some(layout_node) + _ => Some(layout_el) }; - let layout_node = match layout_node { + let layout_el = match layout_el { None => { // The pseudo doesn't exist, return nothing. Chrome seems to query // the element itself in this case, Firefox uses the resolved value. // https://www.w3.org/Bugs/Public/show_bug.cgi?id=29006 return None; } - Some(layout_node) => layout_node + Some(layout_el) => layout_el }; - let style = &*layout_node.resolved_style(); + let style = &*layout_el.resolved_style(); let positioned = match style.get_box().position { position::computed_value::T::relative | @@ -678,11 +678,11 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N, let applies = true; fn used_value_for_position_property<N: LayoutNode>( - layout_node: N::ConcreteThreadSafeLayoutNode, + layout_el: <N::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteThreadSafeLayoutElement, layout_root: &mut Flow, requested_node: N, property: &Atom) -> Option<String> { - let maybe_data = layout_node.borrow_layout_data(); + let maybe_data = layout_el.borrow_layout_data(); let position = maybe_data.map_or(Point2D::zero(), |data| { match (*data).flow_construction_result { ConstructionResult::Flow(ref flow_ref, _) => @@ -744,12 +744,12 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N, atom!("left") if applies && positioned && style.get_box().display != display::computed_value::T::none => { - used_value_for_position_property(layout_node, layout_root, requested_node, property) + used_value_for_position_property(layout_el, layout_root, requested_node, property) } atom!("width") | atom!("height") if applies && style.get_box().display != display::computed_value::T::none => { - used_value_for_position_property(layout_node, layout_root, requested_node, property) + used_value_for_position_property(layout_el, layout_root, requested_node, property) } // FIXME: implement used value computation for line-height ref property => { @@ -781,7 +781,7 @@ pub fn process_offset_parent_query<N: LayoutNode>(requested_node: N, layout_root pub fn process_node_overflow_request<N: LayoutNode>(requested_node: N) -> NodeOverflowResponse { let layout_node = requested_node.to_threadsafe(); - let style = &*layout_node.resolved_style(); + let style = &*layout_node.as_element().unwrap().resolved_style(); let style_box = style.get_box(); NodeOverflowResponse(Some((Point2D::new(style_box.overflow_x, style_box.overflow_y.0)))) @@ -790,7 +790,7 @@ pub fn process_node_overflow_request<N: LayoutNode>(requested_node: N) -> NodeOv pub fn process_margin_style_query<N: LayoutNode>(requested_node: N) -> MarginStyleResponse { let layout_node = requested_node.to_threadsafe(); - let style = &*layout_node.resolved_style(); + let style = &*layout_node.as_element().unwrap().resolved_style(); let margin = style.get_margin(); MarginStyleResponse { diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 2ab1e21cebe..2f6c49b8ea8 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -23,7 +23,7 @@ use style::traversal::{recalc_style_at, remove_from_bloom_filter}; use style::traversal::RestyleResult; use style::traversal::take_thread_local_bloom_filter; use util::opts; -use wrapper::{LayoutNodeLayoutData, ThreadSafeLayoutNodeHelpers}; +use wrapper::{LayoutNodeHelpers, LayoutNodeLayoutData}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 99f9a4cc54d..c37499a12af 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -33,7 +33,8 @@ use core::nonzero::NonZero; use data::{LayoutDataFlags, PersistentLayoutData}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; -use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; +use script_layout_interface::wrapper_traits::{GetLayoutData, LayoutNode}; +use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use style::computed_values::content::{self, ContentItem}; @@ -44,11 +45,10 @@ pub trait LayoutNodeLayoutData { /// than only the style::data::NodeData. fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>>; fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>>; - fn initialize_data(self); fn flow_debug_id(self) -> usize; } -impl<T: LayoutNode> LayoutNodeLayoutData for T { +impl<T: GetLayoutData> LayoutNodeLayoutData for T { fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>> { unsafe { self.get_style_and_layout_data().map(|opaque| { @@ -67,6 +67,16 @@ impl<T: LayoutNode> LayoutNodeLayoutData for T { } } + fn flow_debug_id(self) -> usize { + self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) + } +} + +pub trait LayoutNodeHelpers { + fn initialize_data(self); +} + +impl<T: LayoutNode> LayoutNodeHelpers for T { fn initialize_data(self) { if self.borrow_layout_data().is_none() { let ptr: NonOpaqueStyleAndLayoutData = @@ -77,27 +87,9 @@ impl<T: LayoutNode> LayoutNodeLayoutData for T { self.init_style_and_layout_data(opaque); } } - - fn flow_debug_id(self) -> usize { - self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) - } } pub trait ThreadSafeLayoutNodeHelpers { - fn flow_debug_id(self) -> usize; - - /// Borrows the layout data immutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>>; - - /// Borrows the layout data mutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>>; - /// Returns the layout data flags for this node. fn flags(self) -> LayoutDataFlags; @@ -115,28 +107,6 @@ pub trait ThreadSafeLayoutNodeHelpers { } impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T { - fn flow_debug_id(self) -> usize { - self.borrow_layout_data().map_or(0, |d| d.flow_construction_result.debug_id()) - } - - fn borrow_layout_data(&self) -> Option<AtomicRef<PersistentLayoutData>> { - unsafe { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; - (*container).borrow() - }) - } - } - - fn mutate_layout_data(&self) -> Option<AtomicRefMut<PersistentLayoutData>> { - unsafe { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; - (*container).borrow_mut() - }) - } - } - fn flags(self) -> LayoutDataFlags { self.borrow_layout_data().as_ref().unwrap().flags } @@ -151,7 +121,7 @@ impl<T: ThreadSafeLayoutNode> ThreadSafeLayoutNodeHelpers for T { fn text_content(&self) -> TextContent { if self.get_pseudo_element_type().is_replaced_content() { - let style = self.resolved_style(); + let style = self.as_element().unwrap().resolved_style(); return match style.as_ref().get_counters().content { content::T::Content(ref value) if !value.is_empty() => { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 75bdd55aedc..73d06eec76a 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -46,8 +46,8 @@ use range::Range; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; use script_layout_interface::restyle_damage::RestyleDamage; -use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, LayoutNode, PseudoElementType}; -use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; +use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use selectors::matching::ElementFlags; use selectors::parser::{AttrSelector, NamespaceConstraint}; use std::fmt; @@ -306,6 +306,8 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { self.node.set_flag(HAS_DIRTY_DESCENDANTS, false); } + // NB: This duplicates the get_style_data on ThreadSafeLayoutElement, but + // will go away soon. fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> { unsafe { self.get_jsmanaged().get_style_and_layout_data().map(|d| { @@ -321,7 +323,9 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { self.get_jsmanaged().init_style_and_layout_data(data); } } +} +impl<'ln> GetLayoutData for ServoLayoutNode<'ln> { fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { unsafe { self.get_jsmanaged().get_style_and_layout_data() @@ -329,6 +333,24 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { } } +impl<'le> GetLayoutData for ServoLayoutElement<'le> { + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { + self.as_node().get_style_and_layout_data() + } +} + +impl<'ln> GetLayoutData for ServoThreadSafeLayoutNode<'ln> { + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { + self.node.get_style_and_layout_data() + } +} + +impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> { + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { + self.element.as_node().get_style_and_layout_data() + } +} + impl<'ln> ServoLayoutNode<'ln> { pub fn is_dirty(&self) -> bool { unsafe { self.node.get_flag(IS_DIRTY) } @@ -710,8 +732,8 @@ pub struct ServoThreadSafeLayoutNode<'ln> { /// The wrapped node. node: ServoLayoutNode<'ln>, - /// The pseudo-element type, with (optionally), - /// an specified display value to override the stylesheet. + /// The pseudo-element type, with (optionally) + /// a specified display value to override the stylesheet. pseudo: PseudoElementType<Option<display::T>>, } @@ -757,21 +779,19 @@ impl<'ln> ServoThreadSafeLayoutNode<'ln> { } } +// NB: The implementation here is a bit tricky because elements implementing +// pseudos are supposed to return false for is_element(). impl<'ln> NodeInfo for ServoThreadSafeLayoutNode<'ln> { fn is_element(&self) -> bool { self.pseudo == PseudoElementType::Normal && self.node.is_element() } fn is_text_node(&self) -> bool { - // It's unlikely that text nodes will ever be used to implement a - // pseudo-element, but the type system doesn't really enforce that, - // so we check to be safe. - self.pseudo == PseudoElementType::Normal && self.node.is_text_node() + self.node.is_text_node() } fn needs_layout(&self) -> bool { - self.pseudo != PseudoElementType::Normal || - self.node.is_element() || self.node.is_text_node() + self.node.is_text_node() || self.node.is_element() } } @@ -779,24 +799,16 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>; type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator<Self>; - fn with_pseudo(&self, - pseudo: PseudoElementType<Option<display::T>>) -> ServoThreadSafeLayoutNode<'ln> { - ServoThreadSafeLayoutNode { - node: self.node.clone(), - pseudo: pseudo, - } - } - fn opaque(&self) -> OpaqueNode { unsafe { self.get_jsmanaged().opaque() } } fn type_id(&self) -> Option<LayoutNodeType> { - if self.pseudo != PseudoElementType::Normal { - return None + if self.pseudo == PseudoElementType::Normal { + Some(self.node.type_id()) + } else { + None } - - Some(self.node.type_id()) } #[inline] @@ -827,22 +839,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { LayoutIterator(ThreadSafeLayoutNodeChildrenIterator::new(*self)) } - fn as_element(&self) -> ServoThreadSafeLayoutElement<'ln> { - unsafe { - let element = match self.get_jsmanaged().downcast() { - Some(e) => e.unsafe_get(), - None => panic!("not an element") - }; - // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on - // implementations. - ServoThreadSafeLayoutElement { - element: &*element, - } - } - } - - fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>> { - self.pseudo + fn as_element(&self) -> Option<ServoThreadSafeLayoutElement<'ln>> { + self.node.as_element().map(|el| ServoThreadSafeLayoutElement { + element: el, + pseudo: self.pseudo, + }) } fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { @@ -932,10 +933,6 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan() } } - - fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> { - self.node.get_style_data() - } } pub struct ThreadSafeLayoutNodeChildrenIterator<ConcreteNode: ThreadSafeLayoutNode> { @@ -968,6 +965,7 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod where ConcreteNode: DangerousThreadSafeLayoutNode { type Item = ConcreteNode; fn next(&mut self) -> Option<ConcreteNode> { + use ::selectors::Element; match self.parent_node.get_pseudo_element_type() { PseudoElementType::Before(_) | PseudoElementType::After(_) => None, @@ -976,8 +974,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod loop { let next_node = if let Some(ref node) = current_node { if node.is_element() && - node.as_element().get_local_name() == &atom!("summary") && - node.as_element().get_namespace() == &ns!(html) { + node.as_element().unwrap().get_local_name() == &atom!("summary") && + node.as_element().unwrap().get_namespace() == &ns!(html) { self.current_node = None; return Some(node.clone()); } @@ -994,8 +992,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod let node = self.current_node.clone(); let node = node.and_then(|node| { if node.is_element() && - node.as_element().get_local_name() == &atom!("summary") && - node.as_element().get_namespace() == &ns!(html) { + node.as_element().unwrap().get_local_name() == &atom!("summary") && + node.as_element().unwrap().get_namespace() == &ns!(html) { unsafe { node.dangerous_next_sibling() } } else { Some(node) @@ -1042,26 +1040,51 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod /// ever access safe properties and cannot race on elements. #[derive(Copy, Clone, Debug)] pub struct ServoThreadSafeLayoutElement<'le> { - element: &'le Element, + element: ServoLayoutElement<'le>, + + /// The pseudo-element type, with (optionally) + /// a specified display value to override the stylesheet. + pseudo: PseudoElementType<Option<display::T>>, } impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> { type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'le>; - fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> { - unsafe { - self.element.get_attr_val_for_layout(namespace, name) + fn as_node(&self) -> ServoThreadSafeLayoutNode<'le> { + ServoThreadSafeLayoutNode { + node: self.element.as_node(), + pseudo: self.pseudo.clone(), } } - #[inline] - fn get_local_name(&self) -> &Atom { - self.element.local_name() + fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>> { + self.pseudo } - #[inline] - fn get_namespace(&self) -> &Namespace { - self.element.namespace() + fn with_pseudo(&self, + pseudo: PseudoElementType<Option<display::T>>) -> Self { + ServoThreadSafeLayoutElement { + element: self.element.clone(), + pseudo: pseudo, + } + } + + fn type_id(&self) -> Option<LayoutNodeType> { + self.as_node().type_id() + } + + fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> { + self.element.get_attr(namespace, name) + } + + fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>> { + unsafe { + self.element.as_node().get_style_and_layout_data().map(|d| { + let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr; + let psd: &AtomicRefCell<NodeData> = transmute(ppld); + psd + }) + } } } @@ -1088,7 +1111,7 @@ impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> { }, NamespaceConstraint::Any => { unsafe { - self.element.get_attr_vals_for_layout(&attr.name).iter() + (*self.element.element.unsafe_get()).get_attr_vals_for_layout(&attr.name).iter() .any(|attr| test(*attr)) } } @@ -1131,12 +1154,12 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { #[inline] fn get_local_name(&self) -> &Atom { - ThreadSafeLayoutElement::get_local_name(self) + self.element.get_local_name() } #[inline] fn get_namespace(&self) -> &Namespace { - ThreadSafeLayoutElement::get_namespace(self) + self.element.get_namespace() } fn match_non_ts_pseudo_class(&self, _: NonTSPseudoClass) -> bool { diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 200aeaa03af..669a3e331be 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -25,7 +25,7 @@ use style::properties::ServoComputedValues; use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl}; use url::Url; -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, PartialEq, Clone, Debug)] pub enum PseudoElementType<T> { Normal, Before(T), @@ -70,9 +70,14 @@ impl<T> PseudoElementType<T> { } } +/// Trait to abstract access to layout data across various data structures. +pub trait GetLayoutData { + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; +} + /// 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 { +pub trait LayoutNode: GetLayoutData + TNode { type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; @@ -86,7 +91,6 @@ pub trait LayoutNode: TNode { fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); - fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> { LayoutIterator(ReverseChildrenIterator { @@ -144,16 +148,12 @@ impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode> /// 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 + NodeInfo + PartialEq + Sized { +pub trait ThreadSafeLayoutNode: Clone + Copy + GetLayoutData + NodeInfo + PartialEq + Sized { type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self> + ::selectors::Element<Impl=ServoSelectorImpl>; type ChildrenIterator: Iterator<Item = Self> + Sized; - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType<Option<display::T>>) -> Self; - /// Converts self into an `OpaqueNode`. fn opaque(&self) -> OpaqueNode; @@ -183,22 +183,126 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } + 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>; - /// If this is an element, accesses the element data. Fails if this is not an element node. + /// Returns a ThreadSafeLayoutElement if this is an element, None otherwise. + #[inline] + fn as_element(&self) -> Option<Self::ConcreteThreadSafeLayoutElement>; + + #[inline] + fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>> { + self.as_element().map_or(PseudoElementType::Normal, |el| el.get_pseudo_element_type()) + } + + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; + + fn style(&self, context: &SharedStyleContext) -> Arc<ServoComputedValues> { + if let Some(el) = self.as_element() { + el.style(context) + } else { + debug_assert!(self.is_text_node()); + self.style_for_text_node() + } + } + + fn selected_style(&self) -> Arc<ServoComputedValues> { + if let Some(el) = self.as_element() { + el.selected_style() + } else { + debug_assert!(self.is_text_node()); + self.style_for_text_node() + } + } + + fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; + + fn restyle_damage(self) -> RestyleDamage; + + fn clear_restyle_damage(self); + + /// 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() + } + + 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<Range<ByteIndex>>; + + /// 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<Url>; + + fn canvas_data(&self) -> Option<HTMLCanvasData>; + + fn svg_data(&self) -> Option<SVGSVGData>; + + /// 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; +} + +// 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<Self>; + unsafe fn dangerous_next_sibling(&self) -> Option<Self>; +} + +pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + + ::selectors::Element<Impl=ServoSelectorImpl> + + GetLayoutData + + PresentationalHintsSynthetizer { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; + + 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<Option<display::T>>) -> 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>; + #[inline] - fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement; + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; + + fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; #[inline] fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>>; #[inline] fn get_before_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.get_style_data() + if self.get_style_data() .unwrap() .borrow() .current_styles().pseudos @@ -211,8 +315,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_after_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.get_style_data() + if self.get_style_data() .unwrap() .borrow() .current_styles().pseudos @@ -225,9 +328,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_details_summary_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.as_element().get_local_name() == &atom!("details") && - self.as_element().get_namespace() == &ns!(html) { + if self.get_local_name() == &atom!("details") && + self.get_namespace() == &ns!(html) { Some(self.with_pseudo(PseudoElementType::DetailsSummary(None))) } else { None @@ -236,10 +338,9 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_details_content_pseudo(&self) -> Option<Self> { - 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() { + if self.get_local_name() == &atom!("details") && + self.get_namespace() == &ns!(html) { + let display = if self.get_attr(&ns!(), &atom!("open")).is_some() { None // Specified by the stylesheet } else { Some(display::T::none) @@ -250,8 +351,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } - fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; - /// Returns the style results for the given node. If CSS selector matching /// has not yet been performed, fails. /// @@ -259,13 +358,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn style(&self, context: &SharedStyleContext) -> Arc<ServoComputedValues> { match self.get_pseudo_element_type() { - PseudoElementType::Normal => { - match self.type_id().unwrap() { - LayoutNodeType::Text => self.style_for_text_node(), - LayoutNodeType::Element(_) => self.get_style_data().unwrap().borrow() - .current_styles().primary.clone(), - } - }, + PseudoElementType::Normal => self.get_style_data().unwrap().borrow() + .current_styles().primary.clone(), other => { // Precompute non-eagerly-cascaded pseudo-element styles if not // cached before. @@ -289,7 +383,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } PseudoElementCascadeType::Lazy => { - debug_assert!(self.is_element_or_elements_pseudo()); if !self.get_style_data() .unwrap() .borrow() @@ -298,7 +391,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { let new_style = context.stylist .lazily_compute_pseudo_element_style( - &self.as_element(), + self, &style_pseudo, &data.current_styles().primary); data.current_pseudos_mut() @@ -314,6 +407,15 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } + #[inline] + fn selected_style(&self) -> Arc<ServoComputedValues> { + let data = self.get_style_data().unwrap().borrow(); + data.current_styles().pseudos + .get(&PseudoElement::Selection) + .unwrap_or(&data.current_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 @@ -323,11 +425,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { /// element style is precomputed, not from general layout itself. #[inline] fn resolved_style(&self) -> Arc<ServoComputedValues> { - // FIXME(bholley): This should move to Element and lose the text node check. - if self.is_text_node() { - return self.style_for_text_node(); - } - let data = self.get_style_data().unwrap().borrow(); match self.get_pseudo_element_type() { PseudoElementType::Normal @@ -337,79 +434,4 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } - #[inline] - fn selected_style(&self, _context: &SharedStyleContext) -> Arc<ServoComputedValues> { - // FIXME(bholley): This should move to Element and lose the text node check. - if self.is_text_node() { - return self.style_for_text_node(); - } - - let data = self.get_style_data().unwrap().borrow(); - data.current_styles().pseudos - .get(&PseudoElement::Selection) - .unwrap_or(&data.current_styles().primary) - .clone() - } - - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; - - fn restyle_damage(self) -> RestyleDamage; - - fn clear_restyle_damage(self); - - /// 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<Range<ByteIndex>>; - - /// 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<Url>; - - fn canvas_data(&self) -> Option<HTMLCanvasData>; - - fn svg_data(&self) -> Option<SVGSVGData>; - - /// 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 get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; -} - -// 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<Self>; - unsafe fn dangerous_next_sibling(&self) -> Option<Self>; -} - -pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + - ::selectors::Element<Impl=ServoSelectorImpl> + - PresentationalHintsSynthetizer { - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; - - #[inline] - fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; - - #[inline] - fn get_local_name(&self) -> &Atom; - - #[inline] - fn get_namespace(&self) -> &Namespace; } |