diff options
-rw-r--r-- | components/layout/animation.rs | 49 | ||||
-rw-r--r-- | components/layout/construct.rs | 331 | ||||
-rw-r--r-- | components/script_layout_interface/lib.rs | 1 | ||||
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 13 | ||||
-rw-r--r-- | components/style/animation.rs | 97 | ||||
-rw-r--r-- | components/style/matching.rs | 10 | ||||
-rw-r--r-- | components/style/properties/properties.mako.rs | 14 | ||||
-rw-r--r-- | components/style/style_resolver.rs | 1 | ||||
-rw-r--r-- | components/style/stylist.rs | 93 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 23 |
10 files changed, 425 insertions, 207 deletions
diff --git a/components/layout/animation.rs b/components/layout/animation.rs index a3c364a7851..27497811489 100644 --- a/components/layout/animation.rs +++ b/components/layout/animation.rs @@ -15,6 +15,7 @@ use script_traits::{AnimationState, ConstellationControlMsg, LayoutMsg as Conste use script_traits::UntrustedNodeAddress; use std::sync::mpsc::Receiver; use style::animation::{Animation, update_style_for_animation}; +use style::dom::TElement; use style::font_metrics::ServoMetricsProvider; use style::selector_parser::RestyleDamage; use style::timer::Timer; @@ -22,14 +23,19 @@ use style::timer::Timer; /// Processes any new animations that were discovered after style recalculation. /// Also expire any old animations that have completed, inserting them into /// `expired_animations`. -pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>, - script_chan: &IpcSender<ConstellationControlMsg>, - running_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>, - expired_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>, - mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>, - new_animations_receiver: &Receiver<Animation>, - pipeline_id: PipelineId, - timer: &Timer) { +pub fn update_animation_state<E>( + constellation_chan: &IpcSender<ConstellationMsg>, + script_chan: &IpcSender<ConstellationControlMsg>, + running_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>, + expired_animations: &mut FnvHashMap<OpaqueNode, Vec<Animation>>, + mut newly_transitioning_nodes: Option<&mut Vec<UntrustedNodeAddress>>, + new_animations_receiver: &Receiver<Animation>, + pipeline_id: PipelineId, + timer: &Timer, +) +where + E: TElement, +{ let mut new_running_animations = vec![]; while let Ok(animation) = new_animations_receiver.try_recv() { let mut should_push = true; @@ -144,22 +150,25 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>, /// Recalculates style for a set of animations. This does *not* run with the DOM /// lock held. -// NB: This is specific for SelectorImpl, since the layout context and the -// flows are SelectorImpl specific too. If that goes away at some point, -// this should be made generic. -pub fn recalc_style_for_animations(context: &LayoutContext, - flow: &mut Flow, - animations: &FnvHashMap<OpaqueNode, - Vec<Animation>>) { +pub fn recalc_style_for_animations<E>( + context: &LayoutContext, + flow: &mut Flow, + animations: &FnvHashMap<OpaqueNode, Vec<Animation>>, +) +where + E: TElement, +{ let mut damage = RestyleDamage::empty(); flow.mutate_fragments(&mut |fragment| { if let Some(ref animations) = animations.get(&fragment.node) { for animation in animations.iter() { let old_style = fragment.style.clone(); - update_style_for_animation(&context.style_context, - animation, - &mut fragment.style, - &ServoMetricsProvider); + update_style_for_animation::<E>( + &context.style_context, + animation, + &mut fragment.style, + &ServoMetricsProvider, + ); let difference = RestyleDamage::compute_style_difference( &old_style, @@ -173,6 +182,6 @@ pub fn recalc_style_for_animations(context: &LayoutContext, let base = flow.mut_base(); base.restyle_damage.insert(damage); for kid in base.children.iter_mut() { - recalc_style_for_animations(context, kid, animations) + recalc_style_for_animations::<E>(context, kid, animations) } } diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 807bac242cc..bbbd9287e13 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -51,6 +51,7 @@ use style::computed_values::float::T as Float; use style::computed_values::list_style_position::T as ListStylePosition; use style::computed_values::position::T as Position; use style::context::SharedStyleContext; +use style::dom::TElement; use style::logical_geometry::Direction; use style::properties::ComputedValues; use style::properties::longhands::list_style_image; @@ -170,11 +171,12 @@ pub struct InlineBlockSplit { impl InlineBlockSplit { /// Flushes the given accumulator to the new split and makes a new accumulator to hold any /// subsequent fragments. - fn new<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>(fragment_accumulator: &mut InlineFragmentsAccumulator, - node: &ConcreteThreadSafeLayoutNode, - style_context: &SharedStyleContext, - flow: FlowRef) - -> InlineBlockSplit { + fn new<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>( + fragment_accumulator: &mut InlineFragmentsAccumulator, + node: &ConcreteThreadSafeLayoutNode, + style_context: &SharedStyleContext, + flow: FlowRef, + ) -> InlineBlockSplit { fragment_accumulator.enclosing_node.as_mut().expect( "enclosing_node is None; Are {ib} splits being generated outside of an inline node?" ).flags.remove(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT); @@ -183,7 +185,9 @@ impl InlineBlockSplit { predecessors: mem::replace( fragment_accumulator, InlineFragmentsAccumulator::from_inline_node( - node, style_context)).to_intermediate_inline_fragments(style_context), + node, + style_context, + )).to_intermediate_inline_fragments::<ConcreteThreadSafeLayoutNode>(style_context), flow: flow, }; @@ -280,8 +284,13 @@ impl InlineFragmentsAccumulator { self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants); } - fn to_intermediate_inline_fragments(self, context: &SharedStyleContext) - -> IntermediateInlineFragments { + fn to_intermediate_inline_fragments<N>( + self, + context: &SharedStyleContext, + ) -> IntermediateInlineFragments + where + N: ThreadSafeLayoutNode, + { let InlineFragmentsAccumulator { mut fragments, enclosing_node, @@ -308,9 +317,21 @@ impl InlineFragmentsAccumulator { if let Some((start, end)) = bidi_control_chars { fragments.fragments.push_front( - control_chars_to_fragment(&enclosing_node, context, start, restyle_damage)); + control_chars_to_fragment::<N::ConcreteElement>( + &enclosing_node, + context, + start, + restyle_damage, + ) + ); fragments.fragments.push_back( - control_chars_to_fragment(&enclosing_node, context, end, restyle_damage)); + control_chars_to_fragment::<N::ConcreteElement>( + &enclosing_node, + context, + end, + restyle_damage, + ) + ); } } fragments @@ -402,13 +423,18 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> /// `#[inline(always)]` because this is performance critical and LLVM will not inline it /// otherwise. #[inline(always)] - fn flush_inline_fragments_to_flow(&mut self, - fragment_accumulator: InlineFragmentsAccumulator, - flow: &mut FlowRef, - absolute_descendants: &mut AbsoluteDescendants, - legalizer: &mut Legalizer, - node: &ConcreteThreadSafeLayoutNode) { - let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(self.style_context()); + fn flush_inline_fragments_to_flow( + &mut self, + fragment_accumulator: InlineFragmentsAccumulator, + flow: &mut FlowRef, + absolute_descendants: &mut AbsoluteDescendants, + legalizer: &mut Legalizer, + node: &ConcreteThreadSafeLayoutNode, + ) { + let mut fragments = + fragment_accumulator.to_intermediate_inline_fragments::<ConcreteThreadSafeLayoutNode>( + self.style_context(), + ); if fragments.is_empty() { return }; @@ -479,7 +505,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> } inline_flow_ref.finish(); - legalizer.add_child(self.style_context(), flow, inline_flow_ref) + legalizer.add_child::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + self.style_context(), + flow, + inline_flow_ref, + ) } fn build_block_flow_using_construction_result_of_child( @@ -512,7 +542,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> legalizer, node); } - legalizer.add_child(self.style_context(), flow, kid_flow) + legalizer.add_child::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + self.style_context(), + flow, + kid_flow, + ) } abs_descendants.push_descendants(kid_abs_descendants); } @@ -546,7 +580,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> node); // Push the flow generated by the {ib} split onto our list of flows. - legalizer.add_child(self.style_context(), flow, kid_flow) + legalizer.add_child::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + self.style_context(), + flow, + kid_flow, + ) } // Add the fragments to the list we're maintaining. @@ -666,11 +704,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let context = self.style_context(); let mut style = node.style(context); - style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoText, &style); + style = context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoText, + &style, + ); if node_is_input_or_text_area { - style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoInputText, &style) + style = context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoInputText, + &style, + ) } self.create_fragments_for_node_text_content(&mut fragments, node, &style) @@ -878,7 +922,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let construction_item = ConstructionItem::InlineFragments( InlineFragmentsConstructionResult { splits: opt_inline_block_splits, - fragments: fragment_accumulator.to_intermediate_inline_fragments(self.style_context()), + fragments: fragment_accumulator.to_intermediate_inline_fragments::<ConcreteThreadSafeLayoutNode>( + self.style_context(), + ), }); ConstructionResult::ConstructionItem(construction_item) } else { @@ -902,9 +948,13 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> return ConstructionResult::ConstructionItem(ConstructionItem::Whitespace( node.opaque(), node.get_pseudo_element_type(), - context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoText, &style), - node.restyle_damage())) + context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoText, + &style, + ), + node.restyle_damage(), + )) } // If this is generated content, then we need to initialize the accumulator with the @@ -913,8 +963,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let mut fragments = IntermediateInlineFragments::new(); match (node.get_pseudo_element_type(), node.type_id()) { (_, Some(LayoutNodeType::Text)) => { - let text_style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoText, &style); + let text_style = context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoText, + &style, + ); self.create_fragments_for_node_text_content(&mut fragments, node, &text_style) } (PseudoElementType::Normal, _) => { @@ -949,8 +1002,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let context = self.style_context(); let style = node.style(context); - let style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoInlineBlockWrapper, &style); + let style = context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoInlineBlockWrapper, + &style, + ); let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new( block_flow)); let fragment = Fragment::from_opaque_node_and_style(node.opaque(), @@ -967,7 +1023,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), - fragments: fragment_accumulator.to_intermediate_inline_fragments(context), + fragments: fragment_accumulator + .to_intermediate_inline_fragments::<ConcreteThreadSafeLayoutNode>(context), }); ConstructionResult::ConstructionItem(construction_item) } @@ -987,8 +1044,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> InlineAbsoluteHypotheticalFragmentInfo::new(block_flow)); let style_context = self.style_context(); let style = node.style(style_context); - let style = style_context.stylist.style_for_anonymous( - &style_context.guards, &PseudoElement::ServoInlineAbsolute, &style); + let style = style_context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &style_context.guards, + &PseudoElement::ServoInlineAbsolute, + &style, + ); let fragment = Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, style, @@ -1003,7 +1063,8 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { splits: LinkedList::new(), - fragments: fragment_accumulator.to_intermediate_inline_fragments(style_context), + fragments: fragment_accumulator + .to_intermediate_inline_fragments::<ConcreteThreadSafeLayoutNode>(style_context), }); ConstructionResult::ConstructionItem(construction_item) } @@ -1097,8 +1158,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> { let context = self.style_context(); table_style = node.style(context); - wrapper_style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoTableWrapper, &table_style); + wrapper_style = context.stylist.style_for_anonymous::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + &context.guards, + &PseudoElement::ServoTableWrapper, + &table_style, + ); } let wrapper_fragment = Fragment::from_opaque_node_and_style(node.opaque(), @@ -1128,7 +1192,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> CaptionSide::Top); if let ConstructionResult::Flow(table_flow, table_abs_descendants) = construction_result { - legalizer.add_child(self.style_context(), &mut wrapper_flow, table_flow); + legalizer.add_child::<ConcreteThreadSafeLayoutNode::ConcreteElement>( + self.style_context(), + &mut wrapper_flow, + table_flow, + ); abs_descendants.push_descendants(table_abs_descendants); } @@ -1821,16 +1889,24 @@ fn bidi_control_chars(style: &ServoArc<ComputedValues>) -> Option<(&'static str, } } -fn control_chars_to_fragment(node: &InlineFragmentNodeInfo, - context: &SharedStyleContext, - text: &str, - restyle_damage: RestyleDamage) - -> Fragment { +fn control_chars_to_fragment<E>( + node: &InlineFragmentNodeInfo, + context: &SharedStyleContext, + text: &str, + restyle_damage: RestyleDamage, +) -> Fragment +where + E: TElement, +{ let info = SpecificFragmentInfo::UnscannedText( Box::new(UnscannedTextFragmentInfo::new(String::from(text), None)) ); - let text_style = context.stylist.style_for_anonymous( - &context.guards, &PseudoElement::ServoText, &node.style); + let text_style = context.stylist.style_for_anonymous::<E>( + &context.guards, + &PseudoElement::ServoText, + &node.style, + ); + Fragment::from_opaque_node_and_style(node.address, node.pseudo, text_style, @@ -1887,16 +1963,24 @@ impl Legalizer { /// Makes the `child` flow a new child of `parent`. Anonymous flows are automatically inserted /// to keep the tree legal. - fn add_child(&mut self, context: &SharedStyleContext, parent: &mut FlowRef, mut child: FlowRef) { + fn add_child<E>( + &mut self, + context: &SharedStyleContext, + parent: &mut FlowRef, + mut child: FlowRef, + ) + where + E: TElement, + { while !self.stack.is_empty() { - if self.try_to_add_child(context, parent, &mut child) { + if self.try_to_add_child::<E>(context, parent, &mut child) { return } self.flush_top_of_stack(parent) } - while !self.try_to_add_child(context, parent, &mut child) { - self.push_next_anonymous_flow(context, parent) + while !self.try_to_add_child::<E>(context, parent, &mut child) { + self.push_next_anonymous_flow::<E>(context, parent) } } @@ -1913,8 +1997,15 @@ impl Legalizer { /// This method attempts to create anonymous blocks in between `parent` and `child` if and only /// if those blocks will only ever have `child` as their sole child. At present, this is only /// true for anonymous block children of flex flows. - fn try_to_add_child(&mut self, context: &SharedStyleContext, parent: &mut FlowRef, child: &mut FlowRef) - -> bool { + fn try_to_add_child<E>( + &mut self, + context: &SharedStyleContext, + parent: &mut FlowRef, + child: &mut FlowRef, + ) -> bool + where + E: TElement, + { let parent = self.stack.last_mut().unwrap_or(parent); let (parent_class, child_class) = (parent.class(), child.class()); match (parent_class, child_class) { @@ -1944,12 +2035,14 @@ impl Legalizer { (FlowClass::Flex, FlowClass::Inline) => { FlowRef::deref_mut(child).mut_base().flags.insert(FlowFlags::MARGINS_CANNOT_COLLAPSE); - let mut block_wrapper = - Legalizer::create_anonymous_flow(context, - parent, - &[PseudoElement::ServoAnonymousBlock], - SpecificFragmentInfo::Generic, - BlockFlow::from_fragment); + let mut block_wrapper = Legalizer::create_anonymous_flow::<E, _>( + context, + parent, + &[PseudoElement::ServoAnonymousBlock], + SpecificFragmentInfo::Generic, + BlockFlow::from_fragment, + ); + { let flag = if parent.as_flex().main_mode() == Direction::Inline { FragmentFlags::IS_INLINE_FLEX_ITEM @@ -1997,54 +2090,76 @@ impl Legalizer { /// Adds the anonymous flow that would be necessary to make an illegal child of `parent` legal /// to the stack. - fn push_next_anonymous_flow(&mut self, context: &SharedStyleContext, parent: &FlowRef) { + fn push_next_anonymous_flow<E>( + &mut self, + context: &SharedStyleContext, + parent: &FlowRef, + ) + where + E: TElement, + { let parent_class = self.stack.last().unwrap_or(parent).class(); match parent_class { FlowClass::TableRow => { - self.push_new_anonymous_flow(context, - parent, - &[PseudoElement::ServoAnonymousTableCell], - SpecificFragmentInfo::TableCell, - TableCellFlow::from_fragment) + self.push_new_anonymous_flow::<E, _>( + context, + parent, + &[PseudoElement::ServoAnonymousTableCell], + SpecificFragmentInfo::TableCell, + TableCellFlow::from_fragment, + ) } FlowClass::Table | FlowClass::TableRowGroup => { - self.push_new_anonymous_flow(context, - parent, - &[PseudoElement::ServoAnonymousTableRow], - SpecificFragmentInfo::TableRow, - TableRowFlow::from_fragment) + self.push_new_anonymous_flow::<E, _>( + context, + parent, + &[PseudoElement::ServoAnonymousTableRow], + SpecificFragmentInfo::TableRow, + TableRowFlow::from_fragment, + ) } FlowClass::TableWrapper => { - self.push_new_anonymous_flow(context, - parent, - &[PseudoElement::ServoAnonymousTable], - SpecificFragmentInfo::Table, - TableFlow::from_fragment) + self.push_new_anonymous_flow::<E, _>( + context, + parent, + &[PseudoElement::ServoAnonymousTable], + SpecificFragmentInfo::Table, + TableFlow::from_fragment, + ) } _ => { - self.push_new_anonymous_flow(context, - parent, - &[PseudoElement::ServoTableWrapper, - PseudoElement::ServoAnonymousTableWrapper], - SpecificFragmentInfo::TableWrapper, - TableWrapperFlow::from_fragment) + self.push_new_anonymous_flow::<E, _>( + context, + parent, + &[PseudoElement::ServoTableWrapper, + PseudoElement::ServoAnonymousTableWrapper], + SpecificFragmentInfo::TableWrapper, + TableWrapperFlow::from_fragment, + ) } } } /// Creates an anonymous flow and pushes it onto the stack. - fn push_new_anonymous_flow<F>(&mut self, - context: &SharedStyleContext, - reference: &FlowRef, - pseudos: &[PseudoElement], - specific_fragment_info: SpecificFragmentInfo, - constructor: extern "Rust" fn(Fragment) -> F) - where F: Flow { - let new_flow = Legalizer::create_anonymous_flow(context, - reference, - pseudos, - specific_fragment_info, - constructor); + fn push_new_anonymous_flow<E, F>( + &mut self, + context: &SharedStyleContext, + reference: &FlowRef, + pseudos: &[PseudoElement], + specific_fragment_info: SpecificFragmentInfo, + constructor: extern "Rust" fn(Fragment) -> F, + ) + where + E: TElement, + F: Flow, + { + let new_flow = Self::create_anonymous_flow::<E, _>( + context, + reference, + pseudos, + specific_fragment_info, + constructor, + ); self.stack.push(new_flow) } @@ -2053,21 +2168,31 @@ impl Legalizer { /// /// This method invokes the supplied constructor function on the given specific fragment info /// in order to actually generate the flow. - fn create_anonymous_flow<F>(context: &SharedStyleContext, - reference: &FlowRef, - pseudos: &[PseudoElement], - specific_fragment_info: SpecificFragmentInfo, - constructor: extern "Rust" fn(Fragment) -> F) - -> FlowRef - where F: Flow { + fn create_anonymous_flow<E, F>( + context: &SharedStyleContext, + reference: &FlowRef, + pseudos: &[PseudoElement], + specific_fragment_info: SpecificFragmentInfo, + constructor: extern "Rust" fn(Fragment) -> F, + ) -> FlowRef + where + E: TElement, + F: Flow, + { let reference_block = reference.as_block(); let mut new_style = reference_block.fragment.style.clone(); for pseudo in pseudos { - new_style = context.stylist.style_for_anonymous(&context.guards, pseudo, &new_style) + new_style = context.stylist.style_for_anonymous::<E>( + &context.guards, + pseudo, + &new_style, + ); } - let fragment = reference_block.fragment - .create_similar_anonymous_fragment(new_style, - specific_fragment_info); + let fragment = + reference_block.fragment.create_similar_anonymous_fragment( + new_style, + specific_fragment_info, + ); FlowRef::new(Arc::new(constructor(fragment))) } } diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 0538aabafd0..45c82ee1089 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -7,6 +7,7 @@ //! to depend on script. #![deny(unsafe_code)] +#![feature(associated_type_defaults)] extern crate app_units; extern crate atomic_refcell; diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index dc1f5db4c54..17a9172cd71 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -19,7 +19,7 @@ use std::fmt::Debug; use style::attr::AttrValue; use style::context::SharedStyleContext; use style::data::ElementData; -use style::dom::{LayoutIterator, NodeInfo, TNode}; +use style::dom::{LayoutIterator, NodeInfo, TElement, TNode}; use style::dom::OpaqueNode; use style::font_metrics::ServoMetricsProvider; use style::properties::{CascadeFlags, ComputedValues}; @@ -148,6 +148,8 @@ impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode> /// node does not allow any parents or siblings of nodes to be accessed, to avoid races. pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo + PartialEq + Sized { type ConcreteNode: LayoutNode<ConcreteThreadSafeLayoutNode = Self>; + type ConcreteElement: TElement = <Self::ConcreteNode as TNode>::ConcreteElement; + type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self> + ::selectors::Element<Impl=SelectorImpl>; @@ -291,6 +293,10 @@ pub trait ThreadSafeLayoutElement { type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; + /// This type alias is just a hack to avoid writing the monstrosity after it + /// twice. + type ConcreteElement: TElement = <Self::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteElement; + fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode; /// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement` @@ -307,8 +313,7 @@ pub trait ThreadSafeLayoutElement /// /// 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::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteNode as TNode>::ConcreteElement; + unsafe fn unsafe_get(self) -> Self::ConcreteElement; #[inline] fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str>; @@ -382,7 +387,7 @@ pub trait ThreadSafeLayoutElement .unwrap().clone() }, PseudoElementCascadeType::Precomputed => { - context.stylist.precomputed_values_for_pseudo( + context.stylist.precomputed_values_for_pseudo::<Self::ConcreteElement>( &context.guards, &style_pseudo, Some(data.styles.primary()), diff --git a/components/style/animation.rs b/components/style/animation.rs index ada5ccad40f..ab482862358 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -8,7 +8,7 @@ use Atom; use bezier::Bezier; use context::SharedStyleContext; -use dom::OpaqueNode; +use dom::{OpaqueNode, TElement}; use font_metrics::FontMetricsProvider; use properties::{self, CascadeFlags, ComputedValues, LonghandId}; use properties::animated_properties::{AnimatedProperty, TransitionProperty}; @@ -458,12 +458,16 @@ pub fn start_transitions_if_applicable( had_animations } -fn compute_style_for_animation_step(context: &SharedStyleContext, - step: &KeyframesStep, - previous_style: &ComputedValues, - style_from_cascade: &Arc<ComputedValues>, - font_metrics_provider: &FontMetricsProvider) - -> Arc<ComputedValues> { +fn compute_style_for_animation_step<E>( + context: &SharedStyleContext, + step: &KeyframesStep, + previous_style: &ComputedValues, + style_from_cascade: &Arc<ComputedValues>, + font_metrics_provider: &FontMetricsProvider, +) -> Arc<ComputedValues> +where + E: TElement, +{ match step.value { KeyframesStepValue::ComputedValues => style_from_cascade.clone(), KeyframesStepValue::Declarations { block: ref declarations } => { @@ -482,20 +486,23 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, // This currently ignores visited styles, which seems acceptable, // as existing browsers don't appear to animate visited styles. let computed = - properties::apply_declarations(context.stylist.device(), - /* pseudo = */ None, - previous_style.rules(), - &context.guards, - iter, - Some(previous_style), - Some(previous_style), - Some(previous_style), - /* visited_style = */ None, - font_metrics_provider, - CascadeFlags::empty(), - context.quirks_mode(), - /* rule_cache = */ None, - &mut Default::default()); + properties::apply_declarations::<E, _, _>( + context.stylist.device(), + /* pseudo = */ None, + previous_style.rules(), + &context.guards, + iter, + Some(previous_style), + Some(previous_style), + Some(previous_style), + /* visited_style = */ None, + font_metrics_provider, + CascadeFlags::empty(), + context.quirks_mode(), + /* rule_cache = */ None, + &mut Default::default(), + /* element = */ None, + ); computed } } @@ -503,11 +510,12 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, /// Triggers animations for a given node looking at the animation property /// values. -pub fn maybe_start_animations(context: &SharedStyleContext, - new_animations_sender: &Sender<Animation>, - node: OpaqueNode, - new_style: &Arc<ComputedValues>) - -> bool { +pub fn maybe_start_animations( + context: &SharedStyleContext, + new_animations_sender: &Sender<Animation>, + node: OpaqueNode, + new_style: &Arc<ComputedValues>, +) -> bool { let mut had_animations = false; let box_style = new_style.get_box(); @@ -599,10 +607,15 @@ pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>, } /// Updates a single animation and associated style based on the current time. /// If `damage` is provided, inserts the appropriate restyle damage. -pub fn update_style_for_animation(context: &SharedStyleContext, - animation: &Animation, - style: &mut Arc<ComputedValues>, - font_metrics_provider: &FontMetricsProvider) { +pub fn update_style_for_animation<E>( + context: &SharedStyleContext, + animation: &Animation, + style: &mut Arc<ComputedValues>, + font_metrics_provider: &FontMetricsProvider, +) +where + E: TElement, +{ debug!("update_style_for_animation: entering"); debug_assert!(!animation.is_expired()); @@ -724,11 +737,13 @@ pub fn update_style_for_animation(context: &SharedStyleContext, let relative_progress = (now - last_keyframe_ended_at) / relative_duration; // TODO: How could we optimise it? Is it such a big deal? - let from_style = compute_style_for_animation_step(context, - last_keyframe, - &**style, - &state.cascade_style, - font_metrics_provider); + let from_style = compute_style_for_animation_step::<E>( + context, + last_keyframe, + &**style, + &state.cascade_style, + font_metrics_provider, + ); // NB: The spec says that the timing function can be overwritten // from the keyframe style. @@ -739,11 +754,13 @@ pub fn update_style_for_animation(context: &SharedStyleContext, timing_function = from_style.get_box().animation_timing_function_at(0); } - let target_style = compute_style_for_animation_step(context, - target_keyframe, - &from_style, - &state.cascade_style, - font_metrics_provider); + let target_style = compute_style_for_animation_step::<E>( + context, + target_keyframe, + &from_style, + &state.cascade_style, + font_metrics_provider, + ); let mut new_style = (*style).clone(); diff --git a/components/style/matching.rs b/components/style/matching.rs index 37694bc0538..5145e26ec36 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -460,10 +460,12 @@ trait PrivateMatchMethods: TElement { // See #12171 and the associated PR for an example where this // happened while debugging other release panic. if !running_animation.is_expired() { - animation::update_style_for_animation(context, - running_animation, - style, - font_metrics); + animation::update_style_for_animation::<Self>( + context, + running_animation, + style, + font_metrics, + ); if let Animation::Transition(_, _, ref frame, _) = *running_animation { possibly_expired_animations.push(frame.property_animation.clone()) } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index a30fa6c0e0a..8e551312044 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -12,6 +12,7 @@ #[cfg(feature = "servo")] use app_units::Au; +use dom::TElement; use custom_properties::CustomPropertiesBuilder; use servo_arc::{Arc, UniqueArc}; use smallbitvec::SmallBitVec; @@ -3188,7 +3189,7 @@ bitflags! { /// Returns the computed values. /// * `flags`: Various flags. /// -pub fn cascade( +pub fn cascade<E>( device: &Device, pseudo: Option<<&PseudoElement>, rule_node: &StrongRuleNode, @@ -3202,7 +3203,11 @@ pub fn cascade( quirks_mode: QuirksMode, rule_cache: Option<<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, -) -> Arc<ComputedValues> { + element: Option<E>, +) -> Arc<ComputedValues> +where + E: TElement, +{ debug_assert_eq!(parent_style.is_some(), parent_style_ignoring_first_line.is_some()); let empty = SmallBitVec::new(); @@ -3261,12 +3266,13 @@ pub fn cascade( quirks_mode, rule_cache, rule_cache_conditions, + element, ) } /// NOTE: This function expects the declaration with more priority to appear /// first. -pub fn apply_declarations<'a, F, I>( +pub fn apply_declarations<'a, E, F, I>( device: &Device, pseudo: Option<<&PseudoElement>, rules: &StrongRuleNode, @@ -3281,8 +3287,10 @@ pub fn apply_declarations<'a, F, I>( quirks_mode: QuirksMode, rule_cache: Option<<&RuleCache>, rule_cache_conditions: &mut RuleCacheConditions, + _element: Option<E>, ) -> Arc<ComputedValues> where + E: TElement, F: Fn() -> I, I: Iterator<Item = (&'a PropertyDeclaration, CascadeLevel)>, { diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs index ea3e8a6b9e3..2a30aa1659b 100644 --- a/components/style/style_resolver.rs +++ b/components/style/style_resolver.rs @@ -592,6 +592,7 @@ where self.context.shared.quirks_mode(), Some(&self.context.thread_local.rule_cache), &mut conditions, + Some(self.element), ); self.context diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 88689d92890..d43f7ed6740 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -642,14 +642,20 @@ impl Stylist { /// parent; otherwise, non-inherited properties are reset to their initial /// values. The flow constructor uses this flag when constructing anonymous /// flows. - pub fn precomputed_values_for_pseudo( + /// + /// TODO(emilio): The type parameter could go away with a void type + /// implementing TElement. + pub fn precomputed_values_for_pseudo<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, parent: Option<&ComputedValues>, cascade_flags: CascadeFlags, - font_metrics: &FontMetricsProvider - ) -> Arc<ComputedValues> { + font_metrics: &FontMetricsProvider, + ) -> Arc<ComputedValues> + where + E: TElement, + { debug_assert!(pseudo.is_precomputed()); let rule_node = self.rule_node_for_precomputed_pseudo( @@ -658,7 +664,7 @@ impl Stylist { None, ); - self.precomputed_values_for_pseudo_with_rule_node( + self.precomputed_values_for_pseudo_with_rule_node::<E>( guards, pseudo, parent, @@ -670,7 +676,10 @@ impl Stylist { /// Computes the style for a given "precomputed" pseudo-element with /// given rule node. - pub fn precomputed_values_for_pseudo_with_rule_node( + /// + /// TODO(emilio): The type parameter could go away with a void type + /// implementing TElement. + pub fn precomputed_values_for_pseudo_with_rule_node<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, @@ -678,8 +687,11 @@ impl Stylist { cascade_flags: CascadeFlags, font_metrics: &FontMetricsProvider, rule_node: StrongRuleNode - ) -> Arc<ComputedValues> { - self.compute_pseudo_element_style_with_inputs( + ) -> Arc<ComputedValues> + where + E: TElement, + { + self.compute_pseudo_element_style_with_inputs::<E>( &CascadeInputs { rules: Some(rule_node), visited_rules: None, @@ -689,6 +701,7 @@ impl Stylist { parent, font_metrics, cascade_flags, + None, ).unwrap() } @@ -730,13 +743,19 @@ impl Stylist { } /// Returns the style for an anonymous box of the given type. + /// + /// TODO(emilio): The type parameter could go away with a void type + /// implementing TElement. #[cfg(feature = "servo")] - pub fn style_for_anonymous( + pub fn style_for_anonymous<E>( &self, guards: &StylesheetGuards, pseudo: &PseudoElement, - parent_style: &ComputedValues - ) -> Arc<ComputedValues> { + parent_style: &ComputedValues, + ) -> Arc<ComputedValues> + where + E: TElement, + { use font_metrics::ServoMetricsProvider; // For most (but not all) pseudo-elements, we inherit all values from the parent. @@ -771,12 +790,12 @@ impl Stylist { if inherit_all { cascade_flags.insert(CascadeFlags::INHERIT_ALL); } - self.precomputed_values_for_pseudo( + self.precomputed_values_for_pseudo::<E>( guards, &pseudo, Some(parent_style), cascade_flags, - &ServoMetricsProvider + &ServoMetricsProvider, ) } @@ -818,6 +837,7 @@ impl Stylist { Some(parent_style), font_metrics, CascadeFlags::empty(), + Some(element), ) } @@ -825,7 +845,7 @@ impl Stylist { /// This can be used for truly lazy pseudo-elements or to avoid redoing /// selector matching for eager pseudo-elements when we need to recompute /// their style with a new parent style. - pub fn compute_pseudo_element_style_with_inputs( + pub fn compute_pseudo_element_style_with_inputs<E>( &self, inputs: &CascadeInputs, pseudo: &PseudoElement, @@ -833,7 +853,11 @@ impl Stylist { parent_style: Option<&ComputedValues>, font_metrics: &FontMetricsProvider, cascade_flags: CascadeFlags, - ) -> Option<Arc<ComputedValues>> { + element: Option<E>, + ) -> Option<Arc<ComputedValues>> + where + E: TElement, + { // We may have only visited rules in cases when we are actually // resolving, not probing, pseudo-element style. if inputs.rules.is_none() && inputs.visited_rules.is_none() { @@ -861,6 +885,7 @@ impl Stylist { parent_style, font_metrics, cascade_flags, + element, )) } @@ -879,7 +904,7 @@ impl Stylist { /// /// is_link should be true if we're computing style for a link; that affects /// how :visited handling is done. - pub fn compute_style_with_inputs( + pub fn compute_style_with_inputs<E>( &self, inputs: &CascadeInputs, pseudo: Option<&PseudoElement>, @@ -888,8 +913,12 @@ impl Stylist { parent_style_ignoring_first_line: Option<&ComputedValues>, layout_parent_style: Option<&ComputedValues>, font_metrics: &FontMetricsProvider, - cascade_flags: CascadeFlags - ) -> Arc<ComputedValues> { + cascade_flags: CascadeFlags, + element: Option<E>, + ) -> Arc<ComputedValues> + where + E: TElement, + { // We need to compute visited values if we have visited rules or if our // parent has visited values. let mut visited_values = None; @@ -928,7 +957,7 @@ impl Stylist { }); } - visited_values = Some(properties::cascade( + visited_values = Some(properties::cascade::<E>( &self.device, pseudo, rule_node, @@ -942,6 +971,7 @@ impl Stylist { self.quirks_mode, /* rule_cache = */ None, &mut Default::default(), + element, )); } @@ -953,7 +983,7 @@ impl Stylist { // difficult to assert that display: contents nodes never arrive here // (tl;dr: It doesn't apply for replaced elements and such, but the // computed value is still "contents"). - properties::cascade( + properties::cascade::<E>( &self.device, pseudo, rules, @@ -967,6 +997,7 @@ impl Stylist { self.quirks_mode, /* rule_cache = */ None, &mut Default::default(), + None, ) } @@ -1515,14 +1546,28 @@ impl Stylist { } /// Computes styles for a given declaration with parent_style. - pub fn compute_for_declarations( + /// + /// FIXME(emilio): the lack of pseudo / cascade flags look quite dubious, + /// hopefully this is only used for some canvas font stuff. + /// + /// TODO(emilio): The type parameter can go away when + /// https://github.com/rust-lang/rust/issues/35121 is fixed. + pub fn compute_for_declarations<E>( &self, guards: &StylesheetGuards, parent_style: &ComputedValues, declarations: Arc<Locked<PropertyDeclarationBlock>>, - ) -> Arc<ComputedValues> { + ) -> Arc<ComputedValues> + where + E: TElement, + { use font_metrics::get_metrics_provider_for_product; + // FIXME(emilio): Why do we even need the rule node? We should probably + // just avoid allocating it and calling `apply_declarations` directly, + // maybe... + // + // Also the `vec!` is super-wasteful. let v = vec![ApplicableDeclarationBlock::from_declarations( declarations.clone(), CascadeLevel::StyleAttributeNormal @@ -1537,7 +1582,7 @@ impl Stylist { let metrics = get_metrics_provider_for_product(); // FIXME(emilio): the pseudo bit looks quite dubious! - properties::cascade( + properties::cascade::<E>( &self.device, /* pseudo = */ None, &rule_node, @@ -1551,20 +1596,24 @@ impl Stylist { self.quirks_mode, /* rule_cache = */ None, &mut Default::default(), + None, ) } /// Accessor for a shared reference to the device. + #[inline] pub fn device(&self) -> &Device { &self.device } /// Accessor for a mutable reference to the device. + #[inline] pub fn device_mut(&mut self) -> &mut Device { &mut self.device } /// Accessor for a shared reference to the rule tree. + #[inline] pub fn rule_tree(&self) -> &RuleTree { &self.rule_tree } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 06c76f3e7f0..fdaa9ab09a4 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -2040,7 +2040,7 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ); let cascade_flags = CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP; - data.stylist.precomputed_values_for_pseudo_with_rule_node( + data.stylist.precomputed_values_for_pseudo_with_rule_node::<GeckoElement>( &guards, &pseudo, parent_style_or_null.map(|x| &*x), @@ -2231,15 +2231,15 @@ fn get_pseudo_style( let guards = StylesheetGuards::same(guard); let metrics = get_metrics_provider_for_product(); let inputs = CascadeInputs::new_from_style(pseudo_styles); - doc_data.stylist - .compute_pseudo_element_style_with_inputs( - &inputs, - pseudo, - &guards, - Some(inherited_styles), - &metrics, - CascadeFlags::empty(), - ) + doc_data.stylist.compute_pseudo_element_style_with_inputs( + &inputs, + pseudo, + &guards, + Some(inherited_styles), + &metrics, + CascadeFlags::empty(), + Some(element), + ) }) }, _ => { @@ -3655,6 +3655,7 @@ pub extern "C" fn Servo_ReparentStyle( Some(layout_parent_style), &metrics, cascade_flags, + element, ).into() } @@ -4297,7 +4298,7 @@ pub extern "C" fn Servo_StyleSet_ResolveForDeclarations( let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations); - doc_data.stylist.compute_for_declarations( + doc_data.stylist.compute_for_declarations::<GeckoElement>( &guards, parent_style, declarations.clone_arc(), |