aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/animation.rs49
-rw-r--r--components/layout/construct.rs331
-rw-r--r--components/script_layout_interface/lib.rs1
-rw-r--r--components/script_layout_interface/wrapper_traits.rs13
-rw-r--r--components/style/animation.rs97
-rw-r--r--components/style/matching.rs10
-rw-r--r--components/style/properties/properties.mako.rs14
-rw-r--r--components/style/style_resolver.rs1
-rw-r--r--components/style/stylist.rs93
-rw-r--r--ports/geckolib/glue.rs23
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(),