aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2018-01-22 21:49:18 +0100
committerEmilio Cobos Álvarez <emilio@crisal.io>2018-01-23 00:57:54 +0100
commit5ac12b5df4406dbde1ceeb6be36be5c3162401a2 (patch)
tree173742ffb60360fc56f39a5b05b53890e84853ee
parent6f543d3de1658e3cacf7fc2caed7b9bda69e1d23 (diff)
downloadservo-5ac12b5df4406dbde1ceeb6be36be5c3162401a2.tar.gz
servo-5ac12b5df4406dbde1ceeb6be36be5c3162401a2.zip
style: Make the TElement type arrive to the `cascade` function.
Not super-proud of this one, but it's the easiest way I could think of. The changeset looks bigger than what it is, because while at it I've rewrapped a fair amount of functions around to use proper block indentation. Alternatives are parameterizing Stylist by <E>, which is not fun, or moving the concrete element from layout_thread to layout, but that implies layout depending on script, which isn't fun either. Other alternative is implementing an empty enum and making anon boxes work on it. It has the advantage of removing the annoying type parameter, but the disadvantage of instantiating `cascade` twice, which isn't great, and having to maintain all the boilerplate of a `TElement` implementation that just does nothing.
-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(),