aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/animation.rs49
-rw-r--r--components/layout/construct.rs331
-rw-r--r--components/layout_thread/dom_wrapper.rs4
-rw-r--r--components/layout_thread/lib.rs25
-rw-r--r--components/script_layout_interface/lib.rs1
-rw-r--r--components/script_layout_interface/wrapper_traits.rs18
-rw-r--r--components/style/animation.rs97
-rw-r--r--components/style/context.rs11
-rw-r--r--components/style/dom.rs2
-rw-r--r--components/style/gecko/pseudo_element.rs13
-rw-r--r--components/style/gecko/wrapper.rs14
-rw-r--r--components/style/matching.rs10
-rw-r--r--components/style/properties/properties.mako.rs47
-rw-r--r--components/style/servo/selector_parser.rs46
-rw-r--r--components/style/style_adjuster.rs92
-rw-r--r--components/style/style_resolver.rs144
-rw-r--r--components/style/stylist.rs225
-rw-r--r--ports/geckolib/glue.rs50
18 files changed, 666 insertions, 513 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/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs
index 6eef1106c3d..0110704edad 100644
--- a/components/layout_thread/dom_wrapper.rs
+++ b/components/layout_thread/dom_wrapper.rs
@@ -455,7 +455,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
}
}
- fn skip_root_and_item_based_display_fixup(&self) -> bool {
+ fn skip_item_display_fixup(&self) -> bool {
false
}
@@ -860,6 +860,7 @@ impl<'ln> NodeInfo for ServoThreadSafeLayoutNode<'ln> {
impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
type ConcreteNode = ServoLayoutNode<'ln>;
type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>;
+ type ConcreteElement = ServoLayoutElement<'ln>;
type ChildrenIterator = ThreadSafeLayoutNodeChildrenIterator<Self>;
fn opaque(&self) -> OpaqueNode {
@@ -1084,6 +1085,7 @@ pub struct ServoThreadSafeLayoutElement<'le> {
impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'le>;
+ type ConcreteElement = ServoLayoutElement<'le>;
fn as_node(&self) -> ServoThreadSafeLayoutNode<'le> {
ServoThreadSafeLayoutNode {
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 3fb7d0c8c73..fcd790fe6ec 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -1491,8 +1491,11 @@ impl LayoutThread {
self.profiler_metadata(),
self.time_profiler_chan.clone(),
|| {
- animation::recalc_style_for_animations(
- &layout_context, FlowRef::deref_mut(&mut root_flow), &animations)
+ animation::recalc_style_for_animations::<ServoLayoutElement>(
+ &layout_context,
+ FlowRef::deref_mut(&mut root_flow),
+ &animations,
+ )
});
}
self.perform_post_style_recalc_layout_passes(&mut root_flow,
@@ -1522,14 +1525,16 @@ impl LayoutThread {
.as_mut()
.map(|nodes| &mut **nodes);
// Kick off animations if any were triggered, expire completed ones.
- animation::update_animation_state(&self.constellation_chan,
- &self.script_chan,
- &mut *self.running_animations.write(),
- &mut *self.expired_animations.write(),
- newly_transitioning_nodes,
- &self.new_animations_receiver,
- self.id,
- &self.timer);
+ animation::update_animation_state::<ServoLayoutElement>(
+ &self.constellation_chan,
+ &self.script_chan,
+ &mut *self.running_animations.write(),
+ &mut *self.expired_animations.write(),
+ newly_transitioning_nodes,
+ &self.new_animations_receiver,
+ self.id,
+ &self.timer,
+ );
}
profile(time::ProfilerCategory::LayoutRestyleDamagePropagation,
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..0b04d4256a6 100644
--- a/components/script_layout_interface/wrapper_traits.rs
+++ b/components/script_layout_interface/wrapper_traits.rs
@@ -19,10 +19,10 @@ 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};
+use style::properties::ComputedValues;
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
use style::stylist::RuleInclusion;
use webrender_api::ClipId;
@@ -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;
+
type ConcreteThreadSafeLayoutElement:
ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
+ ::selectors::Element<Impl=SelectorImpl>;
@@ -291,6 +293,12 @@ pub trait ThreadSafeLayoutElement
{
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
+ /// This type alias is just a work-around to avoid writing
+ ///
+ /// <Self::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteElement
+ ///
+ type ConcreteElement: TElement;
+
fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode;
/// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement`
@@ -307,8 +315,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,11 +389,10 @@ 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()),
- CascadeFlags::empty(),
&ServoMetricsProvider,
)
}
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/context.rs b/components/style/context.rs
index 6c9ba7b47f6..3768289da0e 100644
--- a/components/style/context.rs
+++ b/components/style/context.rs
@@ -203,7 +203,7 @@ impl<'a> SharedStyleContext<'a> {
/// within the `CurrentElementInfo`. At the end of the cascade, they are folded
/// down into the main `ComputedValues` to reduce memory usage per element while
/// still remaining accessible.
-#[derive(Clone, Default)]
+#[derive(Clone, Debug, Default)]
pub struct CascadeInputs {
/// The rule node representing the ordered list of rules matched for this
/// node.
@@ -226,15 +226,6 @@ impl CascadeInputs {
}
}
-// We manually implement Debug for CascadeInputs so that we can avoid the
-// verbose stringification of ComputedValues for normal logging.
-impl fmt::Debug for CascadeInputs {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "CascadeInputs {{ rules: {:?}, visited_rules: {:?}, .. }}",
- self.rules, self.visited_rules)
- }
-}
-
/// A list of cascade inputs for eagerly-cascaded pseudo-elements.
/// The list is stored inline.
#[derive(Debug)]
diff --git a/components/style/dom.rs b/components/style/dom.rs
index bfa0b6078ac..88cd7a82829 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -680,7 +680,7 @@ pub trait TElement
/// Whether we should skip any root- or item-based display property
/// blockification on this element. (This function exists so that Gecko
/// native anonymous content can opt out of this style fixup.)
- fn skip_root_and_item_based_display_fixup(&self) -> bool;
+ fn skip_item_display_fixup(&self) -> bool;
/// Sets selector flags, which indicate what kinds of selectors may have
/// matched on this element and therefore what kind of work may need to
diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs
index 852498ab9ec..ab38bdff798 100644
--- a/components/style/gecko/pseudo_element.rs
+++ b/components/style/gecko/pseudo_element.rs
@@ -10,7 +10,7 @@
use cssparser::{ToCss, serialize_identifier};
use gecko_bindings::structs::{self, CSSPseudoElementType};
-use properties::{ComputedValues, PropertyFlags};
+use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
@@ -51,6 +51,15 @@ impl PseudoElement {
PseudoElementCascadeType::Lazy
}
+ /// The CascadeFlags needed to cascade this pseudo-element.
+ ///
+ /// This is only needed to support the broken INHERIT_ALL pseudo mode for
+ /// Servo.
+ #[inline]
+ pub fn cascade_flags(&self) -> CascadeFlags {
+ CascadeFlags::empty()
+ }
+
/// Whether the pseudo-element should inherit from the default computed
/// values instead of from the parent element.
///
@@ -128,7 +137,7 @@ impl PseudoElement {
/// Whether this pseudo-element skips flex/grid container display-based
/// fixup.
#[inline]
- pub fn skip_item_based_display_fixup(&self) -> bool {
+ pub fn skip_item_display_fixup(&self) -> bool {
(self.flags() & structs::CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM) == 0
}
diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs
index de4855c4ed4..92aedc3b5d7 100644
--- a/components/style/gecko/wrapper.rs
+++ b/components/style/gecko/wrapper.rs
@@ -1285,15 +1285,11 @@ impl<'le> TElement for GeckoElement<'le> {
}
#[inline]
- fn skip_root_and_item_based_display_fixup(&self) -> bool {
- if !self.is_native_anonymous() {
- return false;
- }
-
- if let Some(p) = self.implemented_pseudo_element() {
- return p.skip_item_based_display_fixup();
- }
-
+ fn skip_item_display_fixup(&self) -> bool {
+ debug_assert!(
+ self.implemented_pseudo_element().is_none(),
+ "Just don't call me if I'm a pseudo, you should know the answer already"
+ );
self.is_root_of_native_anonymous_subtree()
}
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..e87f6758b3c 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;
@@ -3147,30 +3148,8 @@ bitflags! {
/// present, non-inherited styles are reset to their initial values.
const INHERIT_ALL = 1;
- /// Whether to skip any display style fixup for root element, flex/grid
- /// item, and ruby descendants.
- const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 1 << 1;
-
/// Whether to only cascade properties that are visited dependent.
- const VISITED_DEPENDENT_ONLY = 1 << 2;
-
- /// Whether the given element we're styling is the document element,
- /// that is, matches :root.
- ///
- /// Not set for native anonymous content since some NAC form their own
- /// root, but share the device.
- ///
- /// This affects some style adjustments, like blockification, and means
- /// that it may affect global state, like the Device's root font-size.
- const IS_ROOT_ELEMENT = 1 << 3;
-
- /// Whether we're computing the style of a link, either visited or
- /// unvisited.
- const IS_LINK = 1 << 4;
-
- /// Whether we're computing the style of a link element that happens to
- /// be visited.
- const IS_VISITED_LINK = 1 << 5;
+ const VISITED_DEPENDENT_ONLY = 1 << 1;
}
}
@@ -3188,7 +3167,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 +3181,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 +3244,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 +3265,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)>,
{
@@ -3318,7 +3304,7 @@ where
};
let mut context = computed::Context {
- is_root_element: flags.contains(CascadeFlags::IS_ROOT_ELEMENT),
+ is_root_element: pseudo.is_none() && element.map_or(false, |e| e.is_root()),
// We'd really like to own the rules here to avoid refcount traffic, but
// animation's usage of `apply_declarations` make this tricky. See bug
// 1375525.
@@ -3602,8 +3588,11 @@ where
builder.clear_modified_reset();
- StyleAdjuster::new(&mut builder)
- .adjust(layout_parent_style, flags);
+ StyleAdjuster::new(&mut builder).adjust(
+ layout_parent_style,
+ element,
+ flags,
+ );
if builder.modified_reset() || !apply_reset {
// If we adjusted any reset structs, we can't cache this ComputedValues.
diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs
index bc6cc31cf7d..04c164e290d 100644
--- a/components/style/servo/selector_parser.rs
+++ b/components/style/servo/selector_parser.rs
@@ -14,8 +14,7 @@ use element_state::{DocumentState, ElementState};
use fnv::FnvHashMap;
use invalidation::element::document_state::InvalidationMatchingData;
use invalidation::element::element_wrapper::ElementSnapshot;
-use properties::ComputedValues;
-use properties::PropertyFlags;
+use properties::{CascadeFlags, ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser};
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
@@ -174,10 +173,10 @@ impl PseudoElement {
self.is_precomputed()
}
- /// Whether this pseudo-element skips flex/grid container
- /// display-based fixup.
+ /// Whether this pseudo-element skips flex/grid container display-based
+ /// fixup.
#[inline]
- pub fn skip_item_based_display_fixup(&self) -> bool {
+ pub fn skip_item_display_fixup(&self) -> bool {
!self.is_before_or_after()
}
@@ -213,6 +212,43 @@ impl PseudoElement {
}
}
+ /// For most (but not all) anon-boxes, we inherit all values from the
+ /// parent, this is the hook in the style system to allow this.
+ ///
+ /// FIXME(emilio): It's likely that this is broken in a variety of
+ /// situations, and what it really wants is just inherit some reset
+ /// properties... Also, I guess it just could do all: inherit on the
+ /// stylesheet, though chances are that'd be kinda slow if we don't cache
+ /// them...
+ pub fn cascade_flags(&self) -> CascadeFlags {
+ match *self {
+ PseudoElement::After |
+ PseudoElement::Before |
+ PseudoElement::Selection |
+ PseudoElement::DetailsContent |
+ PseudoElement::DetailsSummary => CascadeFlags::empty(),
+ // Anonymous table flows shouldn't inherit their parents properties in order
+ // to avoid doubling up styles such as transformations.
+ PseudoElement::ServoAnonymousTableCell |
+ PseudoElement::ServoAnonymousTableRow |
+ PseudoElement::ServoText |
+ PseudoElement::ServoInputText => CascadeFlags::empty(),
+
+ // For tables, we do want style to inherit, because TableWrapper is
+ // responsible for handling clipping and scrolling, while Table is
+ // responsible for creating stacking contexts.
+ //
+ // StackingContextCollectionFlags makes sure this is processed
+ // properly.
+ PseudoElement::ServoAnonymousTable |
+ PseudoElement::ServoAnonymousTableWrapper |
+ PseudoElement::ServoTableWrapper |
+ PseudoElement::ServoAnonymousBlock |
+ PseudoElement::ServoInlineBlockWrapper |
+ PseudoElement::ServoInlineAbsolute => CascadeFlags::INHERIT_ALL,
+ }
+ }
+
/// Covert non-canonical pseudo-element to canonical one, and keep a
/// canonical one as it is.
pub fn canonical(&self) -> PseudoElement {
diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs
index 052d80dbe22..7f805bb3f5c 100644
--- a/components/style/style_adjuster.rs
+++ b/components/style/style_adjuster.rs
@@ -6,6 +6,7 @@
//! a computed style needs in order for it to adhere to the CSS spec.
use app_units::Au;
+use dom::TElement;
use properties::{self, CascadeFlags, ComputedValues, StyleBuilder};
use properties::longhands::display::computed_value::T as Display;
use properties::longhands::float::computed_value::T as Float;
@@ -50,13 +51,30 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
+ /// Whether we should skip any item-based display property blockification on
+ /// this element.
+ fn skip_item_display_fixup<E>(&self, element: Option<E>) -> bool
+ where
+ E: TElement,
+ {
+ if let Some(pseudo) = self.style.pseudo {
+ return pseudo.skip_item_display_fixup();
+ }
+
+ element.map_or(false, |e| e.skip_item_display_fixup())
+ }
+
+
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
- fn blockify_if_necessary(
+ fn blockify_if_necessary<E>(
&mut self,
layout_parent_style: &ComputedValues,
- flags: CascadeFlags,
- ) {
+ element: Option<E>,
+ )
+ where
+ E: TElement,
+ {
let mut blockify = false;
macro_rules! blockify_if {
($if_what:expr) => {
@@ -66,8 +84,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
- if !flags.contains(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) {
- blockify_if!(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
+ let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
+ blockify_if!(is_root);
+ if !self.skip_item_display_fixup(element) {
blockify_if!(layout_parent_style.get_box().clone_display().is_item_container());
}
@@ -81,8 +100,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
let display = self.style.get_box().clone_display();
- let blockified_display =
- display.equivalent_block_display(flags.contains(CascadeFlags::IS_ROOT_ELEMENT));
+ let blockified_display = display.equivalent_block_display(is_root);
if display != blockified_display {
self.style.mutate_box().set_adjusted_display(
blockified_display,
@@ -477,12 +495,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// * suppress border and padding for ruby level containers,
/// * correct unicode-bidi.
#[cfg(feature = "gecko")]
- fn adjust_for_ruby(
+ fn adjust_for_ruby<E>(
&mut self,
layout_parent_style: &ComputedValues,
- flags: CascadeFlags,
- ) {
- use properties::CascadeFlags;
+ element: Option<E>,
+ )
+ where
+ E: TElement,
+ {
use properties::computed_value_flags::ComputedValueFlags;
use properties::longhands::unicode_bidi::computed_value::T as UnicodeBidi;
@@ -491,7 +511,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
if self.should_suppress_linebreak(layout_parent_style) {
self.style.flags.insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
// Inlinify the display type if allowed.
- if !flags.contains(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) {
+ if !self.skip_item_display_fixup(element) {
let inline_display = self_display.inlinify();
if self_display != inline_display {
self.style.mutate_box().set_adjusted_display(inline_display, false);
@@ -531,16 +551,22 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
///
/// FIXME(emilio): This isn't technically a style adjustment thingie, could
/// it move somewhere else?
- fn adjust_for_visited(&mut self, flags: CascadeFlags) {
- use properties::CascadeFlags;
+ fn adjust_for_visited<E>(&mut self, element: Option<E>)
+ where
+ E: TElement,
+ {
use properties::computed_value_flags::ComputedValueFlags;
if !self.style.has_visited_style() {
return;
}
- let relevant_link_visited = if flags.contains(CascadeFlags::IS_LINK) {
- flags.contains(CascadeFlags::IS_VISITED_LINK)
+ let is_link_element =
+ self.style.pseudo.is_none() &&
+ element.map_or(false, |e| e.is_link());
+
+ let relevant_link_visited = if is_link_element {
+ element.unwrap().is_visited_link()
} else {
self.style.inherited_flags().contains(ComputedValueFlags::IS_RELEVANT_LINK_VISITED)
};
@@ -586,11 +612,35 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// When comparing to Gecko, this is similar to the work done by
/// `nsStyleContext::ApplyStyleFixups`, plus some parts of
/// `nsStyleSet::GetContext`.
- pub fn adjust(
+ pub fn adjust<E>(
&mut self,
layout_parent_style: &ComputedValues,
+ element: Option<E>,
flags: CascadeFlags,
- ) {
+ )
+ where
+ E: TElement,
+ {
+ if cfg!(debug_assertions) {
+ if element.and_then(|e| e.implemented_pseudo_element()).is_some() {
+ // It'd be nice to assert `self.style.pseudo == Some(&pseudo)`,
+ // but we do resolve ::-moz-list pseudos on ::before / ::after
+ // content, sigh.
+ debug_assert!(
+ self.style.pseudo.is_some(),
+ "Someone really messed up"
+ );
+ }
+ }
+ // FIXME(emilio): The apply_declarations callsite in Servo's
+ // animation, and the font stuff for Gecko
+ // (Stylist::compute_for_declarations) should pass an element to
+ // cascade(), then we can make this assertion hold everywhere.
+ // debug_assert!(
+ // element.is_some() || self.style.pseudo.is_some(),
+ // "Should always have an element around for non-pseudo styles"
+ // );
+
// Don't adjust visited styles, visited-dependent properties aren't
// affected by these adjustments and it'd be just wasted work anyway.
//
@@ -600,14 +650,14 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
return;
}
- self.adjust_for_visited(flags);
+ self.adjust_for_visited(element);
#[cfg(feature = "gecko")]
{
self.adjust_for_prohibited_display_contents();
self.adjust_for_fieldset_content(layout_parent_style);
}
self.adjust_for_top_layer();
- self.blockify_if_necessary(layout_parent_style, flags);
+ self.blockify_if_necessary(layout_parent_style, element);
self.adjust_for_position();
self.adjust_for_overflow();
#[cfg(feature = "gecko")]
@@ -627,7 +677,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
self.adjust_for_text_decoration_lines(layout_parent_style);
#[cfg(feature = "gecko")]
{
- self.adjust_for_ruby(layout_parent_style, flags);
+ self.adjust_for_ruby(layout_parent_style, element);
}
#[cfg(feature = "servo")]
{
diff --git a/components/style/style_resolver.rs b/components/style/style_resolver.rs
index ea3e8a6b9e3..b07dfb487b9 100644
--- a/components/style/style_resolver.rs
+++ b/components/style/style_resolver.rs
@@ -9,9 +9,8 @@ use context::{CascadeInputs, ElementCascadeInputs, StyleContext};
use data::{ElementStyles, EagerPseudoStyles};
use dom::TElement;
use log::LogLevel::Trace;
-use matching::{CascadeVisitedMode, MatchMethods};
-use properties::{AnimationRules, CascadeFlags, ComputedValues};
-use properties::cascade;
+use matching::MatchMethods;
+use properties::{AnimationRules, ComputedValues};
use properties::longhands::display::computed_value::T as Display;
use rule_tree::StrongRuleNode;
use selector_parser::{PseudoElement, SelectorImpl};
@@ -161,7 +160,8 @@ where
parent_style.map_or(false, |s| s.visited_style().is_some());
let visited_rules =
- if inside_link || self.element.is_link() {
+ if self.context.shared.visited_styles_enabled &&
+ (inside_link || self.element.is_link()) {
let visited_matching_results =
self.match_primary(VisitedHandlingMode::RelevantLinkVisited);
Some(visited_matching_results.rule_node)
@@ -291,29 +291,37 @@ where
layout_parent_style: Option<&ComputedValues>,
pseudo: Option<&PseudoElement>,
) -> ResolvedStyle {
- let mut style_if_visited = None;
- if parent_style.map_or(false, |s| s.visited_style().is_some()) ||
- inputs.visited_rules.is_some() {
- style_if_visited = Some(self.cascade_style(
- inputs.visited_rules.as_ref().or(inputs.rules.as_ref()),
- /* style_if_visited = */ None,
- parent_style,
- layout_parent_style,
- CascadeVisitedMode::Visited,
- pseudo,
- ));
- }
+ debug_assert!(
+ self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
+ "Pseudo-elements can't have other pseudos!"
+ );
+ debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
- ResolvedStyle(
- self.cascade_style(
- inputs.rules.as_ref(),
- style_if_visited,
- parent_style,
- layout_parent_style,
- CascadeVisitedMode::Unvisited,
- pseudo,
- )
- )
+ let implemented_pseudo = self.element.implemented_pseudo_element();
+ let pseudo = pseudo.or(implemented_pseudo.as_ref());
+
+ let mut conditions = Default::default();
+ let values = self.context.shared.stylist.cascade_style_and_visited(
+ Some(self.element),
+ pseudo,
+ inputs,
+ &self.context.shared.guards,
+ parent_style,
+ parent_style,
+ layout_parent_style,
+ &self.context.thread_local.font_metrics_provider,
+ Some(&self.context.thread_local.rule_cache),
+ &mut conditions,
+ );
+
+ self.context.thread_local.rule_cache.insert_if_possible(
+ &self.context.shared.guards,
+ &values,
+ pseudo,
+ &conditions
+ );
+
+ ResolvedStyle(values)
}
/// Cascade the element and pseudo-element styles with the default parents.
@@ -469,7 +477,7 @@ where
) -> Option<StrongRuleNode> {
debug!("Match pseudo {:?} for {:?}, visited: {:?}",
self.element, pseudo_element, visited_handling);
- debug_assert!(pseudo_element.is_eager() || pseudo_element.is_lazy());
+ debug_assert!(pseudo_element.is_eager());
debug_assert!(self.element.implemented_pseudo_element().is_none(),
"Element pseudos can't have any other pseudo.");
@@ -524,86 +532,4 @@ where
Some(rule_node)
}
-
- fn cascade_style(
- &mut self,
- rules: Option<&StrongRuleNode>,
- style_if_visited: Option<Arc<ComputedValues>>,
- mut parent_style: Option<&ComputedValues>,
- layout_parent_style: Option<&ComputedValues>,
- cascade_visited: CascadeVisitedMode,
- pseudo: Option<&PseudoElement>,
- ) -> Arc<ComputedValues> {
- debug_assert!(
- self.element.implemented_pseudo_element().is_none() || pseudo.is_none(),
- "Pseudo-elements can't have other pseudos!"
- );
- debug_assert!(pseudo.map_or(true, |p| p.is_eager()));
-
- let mut cascade_flags = CascadeFlags::empty();
-
- if self.element.skip_root_and_item_based_display_fixup() ||
- pseudo.map_or(false, |p| p.skip_item_based_display_fixup()) {
- cascade_flags.insert(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
- }
-
- if pseudo.is_none() && self.element.is_link() {
- cascade_flags.insert(CascadeFlags::IS_LINK);
- if self.element.is_visited_link() &&
- self.context.shared.visited_styles_enabled {
- cascade_flags.insert(CascadeFlags::IS_VISITED_LINK);
- }
- }
-
- if cascade_visited.visited_dependent_only() {
- // If this element is a link, we want its visited style to inherit
- // from the regular style of its parent, because only the
- // visitedness of the relevant link should influence style.
- if pseudo.is_some() || !self.element.is_link() {
- parent_style = parent_style.map(|s| {
- s.visited_style().unwrap_or(s)
- });
- }
- cascade_flags.insert(CascadeFlags::VISITED_DEPENDENT_ONLY);
- }
- if !self.element.is_native_anonymous() &&
- pseudo.is_none() &&
- self.element.is_root()
- {
- cascade_flags.insert(CascadeFlags::IS_ROOT_ELEMENT);
- }
-
- let implemented_pseudo = self.element.implemented_pseudo_element();
- let pseudo = pseudo.or(implemented_pseudo.as_ref());
-
- let mut conditions = Default::default();
- let values =
- cascade(
- self.context.shared.stylist.device(),
- pseudo,
- rules.unwrap_or(self.context.shared.stylist.rule_tree().root()),
- &self.context.shared.guards,
- parent_style,
- parent_style,
- layout_parent_style,
- style_if_visited,
- &self.context.thread_local.font_metrics_provider,
- cascade_flags,
- self.context.shared.quirks_mode(),
- Some(&self.context.thread_local.rule_cache),
- &mut conditions,
- );
-
- self.context
- .thread_local
- .rule_cache
- .insert_if_possible(
- &self.context.shared.guards,
- &values,
- pseudo,
- &conditions
- );
-
- values
- }
}
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index 88689d92890..6ed2b36ac89 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -22,6 +22,7 @@ use malloc_size_of::MallocUnconditionalShallowSizeOf;
use media_queries::Device;
use properties::{self, CascadeFlags, ComputedValues};
use properties::{AnimationRules, PropertyDeclarationBlock};
+use rule_cache::{RuleCache, RuleCacheConditions};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
@@ -642,14 +643,19 @@ 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,11 +664,10 @@ impl Stylist {
None,
);
- self.precomputed_values_for_pseudo_with_rule_node(
+ self.precomputed_values_for_pseudo_with_rule_node::<E>(
guards,
pseudo,
parent,
- cascade_flags,
font_metrics,
rule_node
)
@@ -670,26 +675,31 @@ 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,
parent: Option<&ComputedValues>,
- cascade_flags: CascadeFlags,
font_metrics: &FontMetricsProvider,
- rule_node: StrongRuleNode
- ) -> Arc<ComputedValues> {
- self.compute_pseudo_element_style_with_inputs(
- &CascadeInputs {
- rules: Some(rule_node),
+ rules: StrongRuleNode
+ ) -> Arc<ComputedValues>
+ where
+ E: TElement,
+ {
+ self.compute_pseudo_element_style_with_inputs::<E>(
+ CascadeInputs {
+ rules: Some(rules),
visited_rules: None,
},
pseudo,
guards,
parent,
font_metrics,
- cascade_flags,
- ).unwrap()
+ None,
+ )
}
/// Returns the rule node for given precomputed pseudo-element.
@@ -730,53 +740,25 @@ 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.
- let inherit_all = match *pseudo {
- // Anonymous table flows shouldn't inherit their parents properties in order
- // to avoid doubling up styles such as transformations.
- PseudoElement::ServoAnonymousTableCell |
- PseudoElement::ServoAnonymousTableRow |
- PseudoElement::ServoText |
- PseudoElement::ServoInputText => false,
- PseudoElement::ServoAnonymousBlock |
-
- // For tables, we do want style to inherit, because TableWrapper is responsible
- // for handling clipping and scrolling, while Table is responsible for creating
- // stacking contexts. StackingContextCollectionFlags makes sure this is processed
- // properly.
- PseudoElement::ServoAnonymousTable |
- PseudoElement::ServoAnonymousTableWrapper |
-
- PseudoElement::ServoTableWrapper |
- PseudoElement::ServoInlineBlockWrapper |
- PseudoElement::ServoInlineAbsolute => true,
- PseudoElement::Before |
- PseudoElement::After |
- PseudoElement::Selection |
- PseudoElement::DetailsSummary |
- PseudoElement::DetailsContent => {
- unreachable!("That pseudo doesn't represent an anonymous box!")
- }
- };
- let mut cascade_flags = CascadeFlags::empty();
- 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,
)
}
@@ -809,37 +791,34 @@ impl Stylist {
is_probe,
rule_inclusion,
matching_fn
- );
+ )?;
- self.compute_pseudo_element_style_with_inputs(
- &cascade_inputs,
+ Some(self.compute_pseudo_element_style_with_inputs(
+ cascade_inputs,
pseudo,
guards,
Some(parent_style),
font_metrics,
- CascadeFlags::empty(),
- )
+ Some(element),
+ ))
}
/// Computes a pseudo-element style lazily using the given CascadeInputs.
/// 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,
+ inputs: CascadeInputs,
pseudo: &PseudoElement,
guards: &StylesheetGuards,
parent_style: Option<&ComputedValues>,
font_metrics: &FontMetricsProvider,
- cascade_flags: CascadeFlags,
- ) -> Option<Arc<ComputedValues>> {
- // 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() {
- return None
- }
-
+ element: Option<E>,
+ ) -> Arc<ComputedValues>
+ where
+ E: TElement,
+ {
// FIXME(emilio): The lack of layout_parent_style here could be
// worrying, but we're probably dropping the display fixup for
// pseudos other than before and after, so it's probably ok.
@@ -852,16 +831,18 @@ impl Stylist {
// <fieldset style="display: contents">. That is, the computed value of
// display for the fieldset is "contents", even though it's not the used
// value, so we don't need to adjust in a different way anyway.
- Some(self.compute_style_with_inputs(
- inputs,
+ self.cascade_style_and_visited(
+ element,
Some(pseudo),
+ inputs,
guards,
parent_style,
parent_style,
parent_style,
font_metrics,
- cascade_flags,
- ))
+ /* rule_cache = */ None,
+ &mut RuleCacheConditions::default(),
+ )
}
/// Computes a style using the given CascadeInputs. This can be used to
@@ -879,34 +860,43 @@ 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 cascade_style_and_visited<E>(
&self,
- inputs: &CascadeInputs,
+ element: Option<E>,
pseudo: Option<&PseudoElement>,
+ inputs: CascadeInputs,
guards: &StylesheetGuards,
parent_style: Option<&ComputedValues>,
parent_style_ignoring_first_line: Option<&ComputedValues>,
layout_parent_style: Option<&ComputedValues>,
font_metrics: &FontMetricsProvider,
- cascade_flags: CascadeFlags
- ) -> Arc<ComputedValues> {
+ rule_cache: Option<&RuleCache>,
+ rule_cache_conditions: &mut RuleCacheConditions,
+ ) -> Arc<ComputedValues>
+ where
+ E: TElement,
+ {
+ debug_assert!(pseudo.is_some() || element.is_some(), "Huh?");
+
+ let cascade_flags =
+ pseudo.map_or(CascadeFlags::empty(), |p| p.cascade_flags());
+
// We need to compute visited values if we have visited rules or if our
// parent has visited values.
let mut visited_values = None;
if inputs.visited_rules.is_some() ||
parent_style.and_then(|s| s.visited_style()).is_some()
{
- // At this point inputs may have visited rules, or rules, or both,
- // or neither (e.g. if it's a text style it may have neither). So
- // we have to be a bit careful here.
+ // At this point inputs may have visited rules, or rules.
let rule_node = match inputs.visited_rules.as_ref() {
Some(rules) => rules,
- None => inputs.rules.as_ref().unwrap_or(self.rule_tree().root()),
+ None => inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
};
+
let inherited_style;
let inherited_style_ignoring_first_line;
let layout_parent_style_for_visited;
- if cascade_flags.contains(CascadeFlags::IS_LINK) {
+ if pseudo.is_none() && element.unwrap().is_link() {
// We just want to use our parent style as our parent.
inherited_style = parent_style;
inherited_style_ignoring_first_line = parent_style_ignoring_first_line;
@@ -928,7 +918,7 @@ impl Stylist {
});
}
- visited_values = Some(properties::cascade(
+ visited_values = Some(properties::cascade::<E>(
&self.device,
pseudo,
rule_node,
@@ -940,23 +930,22 @@ impl Stylist {
font_metrics,
cascade_flags | CascadeFlags::VISITED_DEPENDENT_ONLY,
self.quirks_mode,
- /* rule_cache = */ None,
- &mut Default::default(),
+ rule_cache,
+ rule_cache_conditions,
+ element,
));
}
- // We may not have non-visited rules, if we only had visited ones. In
- // that case we want to use the root rulenode for our non-visited rules.
- let rules = inputs.rules.as_ref().unwrap_or(self.rule_tree.root());
-
// Read the comment on `precomputed_values_for_pseudo` to see why it's
// 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(
+ //
+ // FIXME(emilio): We should assert that it holds if pseudo.is_none()!
+ properties::cascade::<E>(
&self.device,
pseudo,
- rules,
+ inputs.rules.as_ref().unwrap_or(self.rule_tree.root()),
guards,
parent_style,
parent_style_ignoring_first_line,
@@ -965,8 +954,9 @@ impl Stylist {
font_metrics,
cascade_flags,
self.quirks_mode,
- /* rule_cache = */ None,
- &mut Default::default(),
+ rule_cache,
+ rule_cache_conditions,
+ element,
)
}
@@ -983,7 +973,7 @@ impl Stylist {
is_probe: bool,
rule_inclusion: RuleInclusion,
matching_fn: Option<&Fn(&PseudoElement) -> bool>,
- ) -> CascadeInputs
+ ) -> Option<CascadeInputs>
where
E: TElement
{
@@ -1020,7 +1010,6 @@ impl Stylist {
}
};
- let mut inputs = CascadeInputs::default();
let mut declarations = ApplicableDeclarationList::new();
let mut matching_context = MatchingContext::new(
MatchingMode::ForStatelessPseudoElement,
@@ -1043,19 +1032,14 @@ impl Stylist {
&mut set_selector_flags
);
- if !declarations.is_empty() {
- let rule_node =
- self.rule_tree.compute_rule_node(&mut declarations, guards);
- debug_assert!(rule_node != *self.rule_tree.root());
- inputs.rules = Some(rule_node);
+ if declarations.is_empty() && is_probe {
+ return None;
}
- if is_probe && inputs.rules.is_none() {
- // When probing, don't compute visited styles if we have no
- // unvisited styles.
- return inputs;
- }
+ let rules =
+ self.rule_tree.compute_rule_node(&mut declarations, guards);
+ let mut visited_rules = None;
if parent_style.visited_style().is_some() {
let mut declarations = ApplicableDeclarationList::new();
let mut matching_context =
@@ -1083,14 +1067,15 @@ impl Stylist {
let rule_node =
self.rule_tree.insert_ordered_rules_with_important(
declarations.drain().map(|a| a.order_and_level()),
- guards);
+ guards,
+ );
if rule_node != *self.rule_tree.root() {
- inputs.visited_rules = Some(rule_node);
+ visited_rules = Some(rule_node);
}
}
}
- inputs
+ Some(CascadeInputs { rules: Some(rules), visited_rules })
}
/// Set a given device, which may change the styles that apply to the
@@ -1515,14 +1500,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 +1536,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 +1550,24 @@ impl Stylist {
self.quirks_mode,
/* rule_cache = */ None,
&mut Default::default(),
+ /* element = */ 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..4a93d43a83a 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -6,7 +6,7 @@ use cssparser::{ParseErrorKind, Parser, ParserInput};
use cssparser::ToCss as ParserToCss;
use env_logger::LogBuilder;
use malloc_size_of::MallocSizeOfOps;
-use selectors::{Element, NthIndexCache};
+use selectors::NthIndexCache;
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec;
@@ -122,7 +122,7 @@ use style::gecko_properties;
use style::invalidation::element::restyle_hints;
use style::media_queries::{Device, MediaList, parse_media_query_list};
use style::parser::{Parse, ParserContext, self};
-use style::properties::{CascadeFlags, ComputedValues, DeclarationSource, Importance};
+use style::properties::{ComputedValues, DeclarationSource, Importance};
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use style::properties::{PropertyDeclarationId, ShorthandId};
use style::properties::{SourcePropertyDeclaration, StyleBuilder};
@@ -2039,12 +2039,10 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
page_decls,
);
- 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),
- cascade_flags,
&metrics,
rule_node
).into()
@@ -2220,7 +2218,7 @@ fn get_pseudo_style(
PseudoElementCascadeType::Eager => {
match *pseudo {
PseudoElement::FirstLetter => {
- styles.pseudos.get(&pseudo).and_then(|pseudo_styles| {
+ styles.pseudos.get(&pseudo).map(|pseudo_styles| {
// inherited_styles can be None when doing lazy resolution
// (e.g. for computed style) or when probing. In that case
// we just inherit from our element, which is what Gecko
@@ -2231,15 +2229,14 @@ 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,
+ Some(element),
+ )
})
},
_ => {
@@ -3633,28 +3630,17 @@ pub extern "C" fn Servo_ReparentStyle(
let pseudo = style_to_reparent.pseudo();
let element = element.map(GeckoElement);
- let mut cascade_flags = CascadeFlags::empty();
- if style_to_reparent.is_anon_box() {
- cascade_flags.insert(CascadeFlags::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
- }
- if let Some(element) = element {
- if element.is_link() {
- cascade_flags.insert(CascadeFlags::IS_LINK);
- if element.is_visited_link() && doc_data.visited_styles_enabled() {
- cascade_flags.insert(CascadeFlags::IS_VISITED_LINK);
- }
- };
- }
-
- doc_data.stylist.compute_style_with_inputs(
- &inputs,
+ doc_data.stylist.cascade_style_and_visited(
+ element,
pseudo.as_ref(),
+ inputs,
&StylesheetGuards::same(&guard),
Some(parent_style),
Some(parent_style_ignoring_first_line),
Some(layout_parent_style),
&metrics,
- cascade_flags,
+ /* rule_cache = */ None,
+ &mut RuleCacheConditions::default(),
).into()
}
@@ -4297,7 +4283,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(),