style: Adjust display:contents to display:inline for NAC (including ::before/::after).

This commit is contained in:
Cameron McCormack 2017-06-16 09:07:38 +08:00
parent 04935de3ea
commit 36e4d0a511
3 changed files with 56 additions and 24 deletions

View file

@ -17,7 +17,7 @@ use invalidation::element::restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_T
use invalidation::element::restyle_hints::{RESTYLE_SMIL, RESTYLE_STYLE_ATTRIBUTE}; use invalidation::element::restyle_hints::{RESTYLE_SMIL, RESTYLE_STYLE_ATTRIBUTE};
use invalidation::element::restyle_hints::RestyleHint; use invalidation::element::restyle_hints::RestyleHint;
use log::LogLevel::Trace; use log::LogLevel::Trace;
use properties::{ALLOW_SET_ROOT_FONT_SIZE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP}; use properties::{ALLOW_SET_ROOT_FONT_SIZE, PROHIBIT_DISPLAY_CONTENTS, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP};
use properties::{AnimationRules, CascadeFlags, ComputedValues}; use properties::{AnimationRules, CascadeFlags, ComputedValues};
use properties::{VISITED_DEPENDENT_ONLY, cascade}; use properties::{VISITED_DEPENDENT_ONLY, cascade};
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
@ -29,15 +29,23 @@ use sharing::StyleSharingBehavior;
use stylearc::Arc; use stylearc::Arc;
use stylist::RuleInclusion; use stylist::RuleInclusion;
/// The way a style should be inherited. /// Whether we are cascading for an eager pseudo-element or something else.
enum InheritMode { ///
/// Controls where we inherit styles from, and whether display:contents is
/// prohibited.
#[derive(PartialEq, Copy, Clone)]
enum CascadeTarget {
/// Inherit from the parent element, as normal CSS dictates, _or_ from the /// Inherit from the parent element, as normal CSS dictates, _or_ from the
/// closest non-Native Anonymous element in case this is Native Anonymous /// closest non-Native Anonymous element in case this is Native Anonymous
/// Content. /// Content. display:contents is allowed.
Normal, Normal,
/// Inherit from the primary style, this is used while computing eager /// Inherit from the primary style, this is used while computing eager
/// pseudos, like ::before and ::after when we're traversing the parent. /// pseudos, like ::before and ::after when we're traversing the parent.
FromPrimaryStyle, /// Also prohibits display:contents from having an effect.
///
/// TODO(emilio) display:contents really should apply to ::before/::after.
/// https://github.com/w3c/csswg-drafts/issues/1345
EagerPseudo,
} }
/// Represents the result of comparing an element's old and new style. /// Represents the result of comparing an element's old and new style.
@ -251,7 +259,7 @@ trait PrivateMatchMethods: TElement {
font_metrics_provider: &FontMetricsProvider, font_metrics_provider: &FontMetricsProvider,
rule_node: &StrongRuleNode, rule_node: &StrongRuleNode,
primary_style: &ComputedStyle, primary_style: &ComputedStyle,
inherit_mode: InheritMode, cascade_target: CascadeTarget,
cascade_visited: CascadeVisitedMode, cascade_visited: CascadeVisitedMode,
visited_values_to_insert: Option<Arc<ComputedValues>>) visited_values_to_insert: Option<Arc<ComputedValues>>)
-> Arc<ComputedValues> { -> Arc<ComputedValues> {
@ -263,15 +271,17 @@ trait PrivateMatchMethods: TElement {
if cascade_visited.visited_dependent_only() { if cascade_visited.visited_dependent_only() {
cascade_flags.insert(VISITED_DEPENDENT_ONLY); cascade_flags.insert(VISITED_DEPENDENT_ONLY);
} }
if !self.is_native_anonymous() { if self.is_native_anonymous() || cascade_target == CascadeTarget::EagerPseudo {
cascade_flags.insert(PROHIBIT_DISPLAY_CONTENTS);
} else {
cascade_flags.insert(ALLOW_SET_ROOT_FONT_SIZE); cascade_flags.insert(ALLOW_SET_ROOT_FONT_SIZE);
} }
// Grab the inherited values. // Grab the inherited values.
let parent_el; let parent_el;
let parent_data; let parent_data;
let style_to_inherit_from = match inherit_mode { let style_to_inherit_from = match cascade_target {
InheritMode::Normal => { CascadeTarget::Normal => {
parent_el = self.inheritance_parent(); parent_el = self.inheritance_parent();
parent_data = parent_el.as_ref().and_then(|e| e.borrow_data()); parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
let parent_style = parent_data.as_ref().map(|d| { let parent_style = parent_data.as_ref().map(|d| {
@ -287,7 +297,7 @@ trait PrivateMatchMethods: TElement {
}); });
parent_style.map(|s| cascade_visited.values(s)) parent_style.map(|s| cascade_visited.values(s))
} }
InheritMode::FromPrimaryStyle => { CascadeTarget::EagerPseudo => {
parent_el = Some(self.clone()); parent_el = Some(self.clone());
Some(cascade_visited.values(primary_style)) Some(cascade_visited.values(primary_style))
} }
@ -390,17 +400,17 @@ trait PrivateMatchMethods: TElement {
// Grab the rule node. // Grab the rule node.
let style = eager_pseudo_style.unwrap_or(primary_style); let style = eager_pseudo_style.unwrap_or(primary_style);
let rule_node = cascade_visited.rules(style); let rule_node = cascade_visited.rules(style);
let inherit_mode = if eager_pseudo_style.is_some() { let cascade_target = if eager_pseudo_style.is_some() {
InheritMode::FromPrimaryStyle CascadeTarget::EagerPseudo
} else { } else {
InheritMode::Normal CascadeTarget::Normal
}; };
self.cascade_with_rules(context.shared, self.cascade_with_rules(context.shared,
&context.thread_local.font_metrics_provider, &context.thread_local.font_metrics_provider,
rule_node, rule_node,
primary_style, primary_style,
inherit_mode, cascade_target,
cascade_visited, cascade_visited,
visited_values_to_insert) visited_values_to_insert)
} }
@ -536,7 +546,7 @@ trait PrivateMatchMethods: TElement {
&context.thread_local.font_metrics_provider, &context.thread_local.font_metrics_provider,
&without_transition_rules, &without_transition_rules,
primary_style, primary_style,
InheritMode::Normal, CascadeTarget::Normal,
CascadeVisitedMode::Unvisited, CascadeVisitedMode::Unvisited,
None)) None))
} }
@ -1480,7 +1490,7 @@ pub trait MatchMethods : TElement {
font_metrics_provider, font_metrics_provider,
&without_animation_rules, &without_animation_rules,
primary_style, primary_style,
InheritMode::Normal, CascadeTarget::Normal,
CascadeVisitedMode::Unvisited, CascadeVisitedMode::Unvisited,
None) None)
} }

View file

@ -2479,6 +2479,10 @@ bitflags! {
/// ::backdrop and all NAC will resolve rem units against /// ::backdrop and all NAC will resolve rem units against
/// the toplevel root element now. /// the toplevel root element now.
const ALLOW_SET_ROOT_FONT_SIZE = 0x08, const ALLOW_SET_ROOT_FONT_SIZE = 0x08,
/// Whether to convert display:contents into display:inline. This
/// is used by Gecko to prevent display:contents on generated
/// content.
const PROHIBIT_DISPLAY_CONTENTS = 0x10,
} }
} }
@ -2851,8 +2855,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
{ {
StyleAdjuster::new(&mut style, is_root_element) StyleAdjuster::new(&mut style, is_root_element)
.adjust(context.layout_parent_style, .adjust(context.layout_parent_style, flags);
flags.contains(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP));
} }
% if product == "gecko": % if product == "gecko":

View file

@ -6,7 +6,10 @@
//! for it to adhere to the CSS spec. //! for it to adhere to the CSS spec.
use app_units::Au; use app_units::Au;
use properties::{self, ComputedValues, StyleBuilder}; use properties::{self, CascadeFlags, ComputedValues};
use properties::{SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, StyleBuilder};
#[cfg(feature = "gecko")]
use properties::PROHIBIT_DISPLAY_CONTENTS;
use properties::longhands::display::computed_value::T as display; use properties::longhands::display::computed_value::T as display;
use properties::longhands::float::computed_value::T as float; use properties::longhands::float::computed_value::T as float;
use properties::longhands::overflow_x::computed_value::T as overflow; use properties::longhands::overflow_x::computed_value::T as overflow;
@ -54,7 +57,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo /// https://drafts.csswg.org/css2/visuren.html#dis-pos-flo
fn blockify_if_necessary(&mut self, fn blockify_if_necessary(&mut self,
layout_parent_style: &ComputedValues, layout_parent_style: &ComputedValues,
skip_root_and_element_display_fixup: bool) { flags: CascadeFlags) {
let mut blockify = false; let mut blockify = false;
macro_rules! blockify_if { macro_rules! blockify_if {
($if_what:expr) => { ($if_what:expr) => {
@ -64,7 +67,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
} }
} }
if !skip_root_and_element_display_fixup { if !flags.contains(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) {
blockify_if!(self.is_root_element); blockify_if!(self.is_root_element);
blockify_if!(layout_parent_style.get_box().clone_display().is_item_container()); blockify_if!(layout_parent_style.get_box().clone_display().is_item_container());
} }
@ -275,6 +278,19 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
} }
} }
/// Native anonymous content converts display:contents into display:inline.
#[cfg(feature = "gecko")]
fn adjust_for_prohibited_display_contents(&mut self, flags: CascadeFlags) {
// TODO: We should probably convert display:contents into display:none
// in some cases too: https://drafts.csswg.org/css-display/#unbox
if !flags.contains(PROHIBIT_DISPLAY_CONTENTS) ||
self.style.get_box().clone_display() != display::contents {
return;
}
self.style.mutate_box().set_display(display::inline);
}
/// -moz-center, -moz-left and -moz-right are used for HTML's alignment. /// -moz-center, -moz-left and -moz-right are used for HTML's alignment.
/// ///
/// This is covering the <div align="right"><table>...</table></div> case. /// This is covering the <div align="right"><table>...</table></div> case.
@ -305,10 +321,13 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// `nsStyleContext::ApplyStyleFixups`. /// `nsStyleContext::ApplyStyleFixups`.
pub fn adjust(&mut self, pub fn adjust(&mut self,
layout_parent_style: &ComputedValues, layout_parent_style: &ComputedValues,
skip_root_and_element_display_fixup: bool) { flags: CascadeFlags) {
#[cfg(feature = "gecko")]
{
self.adjust_for_prohibited_display_contents(flags);
}
self.adjust_for_top_layer(); self.adjust_for_top_layer();
self.blockify_if_necessary(layout_parent_style, self.blockify_if_necessary(layout_parent_style, flags);
skip_root_and_element_display_fixup);
self.adjust_for_position(); self.adjust_for_position();
self.adjust_for_overflow(); self.adjust_for_overflow();
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]