diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 8838787defc..a6d4815090f 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -477,6 +477,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { }) } } + + fn skip_root_and_item_based_display_fixup(&self) -> bool { + false + } } impl<'le> PartialEq for ServoLayoutElement<'le> { diff --git a/components/style/dom.rs b/components/style/dom.rs index da476cedbaf..5c66bbc0e0f 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -269,4 +269,9 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre fn mutate_data(&self) -> Option> { self.get_data().map(|x| x.borrow_mut()) } + + /// 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; } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 5a8c462db9e..6b124d55d20 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -371,6 +371,15 @@ impl<'le> TElement for GeckoElement<'le> { fn get_data(&self) -> Option<&AtomicRefCell> { unsafe { self.0.mServoData.get().as_ref() } } + + fn skip_root_and_item_based_display_fixup(&self) -> bool { + // We don't want to fix up display values of native anonymous content. + // Additionally, we want to skip root-based display fixup for document + // level native anonymous content subtree roots, since they're not + // really roots from the style fixup perspective. Checking that we + // are NAC handles both cases. + self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0 + } } impl<'le> PartialEq for GeckoElement<'le> { diff --git a/components/style/matching.rs b/components/style/matching.rs index e883d11bc3e..3b0a396507d 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -14,7 +14,7 @@ use cascade_info::CascadeInfo; use context::{SharedStyleContext, StyleContext}; use data::{ComputedStyle, ElementData, ElementStyles, PseudoStyles}; use dom::{TElement, TNode, TRestyleDamage, UnsafeNode}; -use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade}; +use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; use properties::longhands::display::computed_value as display; use rule_tree::StrongRuleNode; use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl}; @@ -405,6 +405,9 @@ trait PrivateMatchMethods: TElement { if booleans.shareable { cascade_flags.insert(SHAREABLE) } + if self.skip_root_and_item_based_display_fixup() { + cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) + } let this_style = match parent_style { Some(ref parent_style) => { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 00be40d30a9..c424ca705a7 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1035,7 +1035,24 @@ fn static_assert() { "-moz-groupbox", gecko_enum_prefix="StyleDisplay", gecko_strip_moz_prefix=False) %> - ${impl_keyword('display', 'mDisplay', display_keyword, True)} + + pub fn set_display(&mut self, v: longhands::display::computed_value::T) { + use properties::longhands::display::computed_value::T as Keyword; + // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts + let result = match v { + % for value in display_keyword.values_for('gecko'): + Keyword::${to_rust_ident(value)} => + structs::${display_keyword.gecko_constant(value)}, + % endfor + }; + self.gecko.mDisplay = result; + self.gecko.mOriginalDisplay = result; + } + pub fn copy_display_from(&mut self, other: &Self) { + self.gecko.mDisplay = other.gecko.mDisplay; + self.gecko.mOriginalDisplay = other.gecko.mOriginalDisplay; + } + <%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"> // overflow-y is implemented as a newtype of overflow-x, so we need special handling. // We could generalize this if we run into other newtype keywords. diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 97e3271e8b6..46688434651 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1436,6 +1436,8 @@ bitflags! { /// Whether to inherit all styles from the parent. If this flag is not present, /// non-inherited styles are reset to their initial values. const INHERIT_ALL = 0x02, + /// Whether to skip any root element and flex/grid item display style fixup. + const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x04, } } @@ -1630,30 +1632,50 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D, longhands::position::SpecifiedValue::absolute | longhands::position::SpecifiedValue::fixed); let floated = style.get_box().clone_float() != longhands::float::SpecifiedValue::none; - let is_flex_item = - context.inherited_style.get_box().clone_display() == computed_values::display::T::flex; - if positioned || floated || is_root_element || is_flex_item { + // FIXME(heycam): We should look past any display:contents ancestors to + // determine if we are a flex or grid item, but we don't have access to + // grandparent or higher style here. + let is_item = matches!(context.inherited_style.get_box().clone_display(), + % if product == "gecko": + computed_values::display::T::grid | + % endif + computed_values::display::T::flex); + let (blockify_root, blockify_item) = match flags.contains(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP) { + false => (is_root_element, is_item), + true => (false, false), + }; + if positioned || floated || blockify_root || blockify_item { use computed_values::display::T; let specified_display = style.get_box().clone_display(); let computed_display = match specified_display { - T::inline_table => { - Some(T::table) - } - T::inline | T::inline_block | - T::table_row_group | T::table_column | - T::table_column_group | T::table_header_group | - T::table_footer_group | T::table_row | T::table_cell | - T::table_caption => { - Some(T::block) - } - _ => None + // Values that have a corresponding block-outside version. + T::inline_table => Some(T::table), + % if product == "gecko": + T::inline_flex => Some(T::flex), + T::inline_grid => Some(T::grid), + T::_webkit_inline_box => Some(T::_webkit_box), + % endif + + // Special handling for contents and list-item on the root element for Gecko. + % if product == "gecko": + T::contents | T::list_item if blockify_root => Some(T::block), + % endif + + // Values that are not changed by blockification. + T::block | T::flex | T::list_item | T::table => None, + % if product == "gecko": + T::contents | T::grid | T::_webkit_box => None, + % endif + + // Everything becomes block. + _ => Some(T::block), }; if let Some(computed_display) = computed_display { let box_ = style.mutate_box(); box_.set_display(computed_display); % if product == "servo": - box_.set__servo_display_for_hypothetical_box(if is_root_element || is_flex_item { + box_.set__servo_display_for_hypothetical_box(if blockify_root || blockify_item { computed_display } else { specified_display