diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 929a760c0fc..459f3328324 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -454,6 +454,9 @@ mod gen { columns: { enabled: bool, }, + flexbox: { + enabled: bool, + }, #[serde(default = "default_layout_threads")] threads: i64, viewport: { diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index c043d3b75d3..6d463608fe7 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -64,14 +64,14 @@ where &mut self, node: Node, text: Cow<'dom, str>, - parent_style: &ServoArc, + parent_style: ServoArc, ); /// Or pseudo-element fn handle_element( &mut self, node: Node, - style: &ServoArc, + style: ServoArc, display: DisplayGeneratingBox, contents: Contents, box_slot: BoxSlot<'dom>, @@ -89,7 +89,7 @@ fn traverse_children_of<'dom, Node>( for child in iter_child_nodes(parent_element) { if let Some(contents) = child.as_text() { - handler.handle_text(child, contents, &child.style(context)); + handler.handle_text(child, contents, child.style(context)); } else if child.is_element() { traverse_element(child, context, handler); } @@ -122,7 +122,7 @@ fn traverse_element<'dom, Node>( Display::GeneratingBox(display) => { let contents = replaced.map_or(Contents::OfElement, Contents::Replaced); let box_slot = element.element_box_slot(); - handler.handle_element(element, &style, display, contents, box_slot); + handler.handle_element(element, style, display, contents, box_slot); }, } } @@ -148,7 +148,7 @@ fn traverse_pseudo_element<'dom, Node>( let items = generate_pseudo_element_content(&style, element, context); let box_slot = element.pseudo_element_box_slot(which); let contents = Contents::OfPseudoElement(items); - handler.handle_element(element, &style, display, contents, box_slot); + handler.handle_element(element, style, display, contents, box_slot); }, } } else { @@ -169,7 +169,7 @@ fn traverse_pseudo_element_contents<'dom, Node>( for item in items { match item { PseudoElementContentItem::Text(text) => { - handler.handle_text(node, text.into(), pseudo_element_style) + handler.handle_text(node, text.into(), pseudo_element_style.clone()) }, PseudoElementContentItem::Replaced(contents) => { let item_style = anonymous_style.get_or_insert_with(|| { @@ -193,7 +193,7 @@ fn traverse_pseudo_element_contents<'dom, Node>( ); handler.handle_element( node, - item_style, + item_style.clone(), display_inline, Contents::Replaced(contents), // We don’t keep pointers to boxes generated by contents of pseudo-elements diff --git a/components/layout_2020/element_data.rs b/components/layout_2020/element_data.rs index e4f682bade9..f0b1b198432 100644 --- a/components/layout_2020/element_data.rs +++ b/components/layout_2020/element_data.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::cell::ArcRefCell; +use crate::flexbox::FlexLevelBox; use crate::flow::inline::InlineLevelBox; use crate::flow::BlockLevelBox; @@ -17,4 +18,5 @@ pub(super) enum LayoutBox { DisplayContents, BlockLevel(ArcRefCell), InlineLevel(ArcRefCell), + FlexLevel(ArcRefCell), } diff --git a/components/layout_2020/flexbox.rs b/components/layout_2020/flexbox.rs new file mode 100644 index 00000000000..fd0dd519c2d --- /dev/null +++ b/components/layout_2020/flexbox.rs @@ -0,0 +1,261 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::cell::ArcRefCell; +use crate::context::LayoutContext; +use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler}; +use crate::element_data::LayoutBox; +use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout}; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; +use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest}; +use crate::style_ext::DisplayGeneratingBox; +use crate::ContainingBlock; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use servo_arc::Arc; +use std::borrow::Cow; +use style::properties::ComputedValues; +use style::values::computed::Length; +use style::values::specified::text::TextDecorationLine; +use style::Zero; + +// FIXME: `min-width: auto` is not zero: https://drafts.csswg.org/css-flexbox/#min-size-auto + +#[derive(Debug, Serialize)] +pub(crate) struct FlexContainer { + children: Vec>, +} + +#[derive(Debug, Serialize)] +pub(crate) enum FlexLevelBox { + FlexItem(IndependentFormattingContext), + OutOfFlowAbsolutelyPositionedBox(Arc), +} + +impl FlexContainer { + pub fn construct<'dom>( + context: &LayoutContext, + node: impl NodeExt<'dom>, + style: &Arc, + contents: NonReplacedContents, + content_sizes: ContentSizesRequest, + propagated_text_decoration_line: TextDecorationLine, + ) -> (Self, BoxContentSizes) { + let text_decoration_line = + propagated_text_decoration_line | style.clone_text_decoration_line(); + let mut builder = FlexContainerBuilder { + context, + node, + style, + text_decoration_line, + contiguous_text_runs: Vec::new(), + jobs: Vec::new(), + has_text_runs: false, + }; + contents.traverse(context, node, style, &mut builder); + let content_sizes = content_sizes.compute(|| { + // FIXME + ContentSizes::zero() + }); + (builder.finish(), content_sizes) + } +} + +/// https://drafts.csswg.org/css-flexbox/#flex-items +struct FlexContainerBuilder<'a, 'dom, Node> { + context: &'a LayoutContext<'a>, + node: Node, + style: &'a Arc, + text_decoration_line: TextDecorationLine, + contiguous_text_runs: Vec>, + /// To be run in parallel with rayon in `finish` + jobs: Vec>, + has_text_runs: bool, +} + +enum FlexLevelJob<'dom, Node> { + /// Or pseudo-element + Element { + node: Node, + style: Arc, + display: DisplayGeneratingBox, + contents: Contents, + box_slot: BoxSlot<'dom>, + }, + TextRuns(Vec>), +} + +struct TextRun<'dom, Node> { + node: Node, + text: Cow<'dom, str>, + parent_style: Arc, +} + +impl<'a, 'dom, Node: 'dom> TraversalHandler<'dom, Node> for FlexContainerBuilder<'a, 'dom, Node> +where + Node: NodeExt<'dom>, +{ + fn handle_text(&mut self, node: Node, text: Cow<'dom, str>, parent_style: Arc) { + self.contiguous_text_runs.push(TextRun { + node, + text, + parent_style, + }) + } + + /// Or pseudo-element + fn handle_element( + &mut self, + node: Node, + style: Arc, + display: DisplayGeneratingBox, + contents: Contents, + box_slot: BoxSlot<'dom>, + ) { + // FIXME: are text runs considered "contiguous" if they are only separated + // by an out-of-flow abspos element? + // (That is, are they wrapped in the same anonymous flex item, or each its own?) + self.wrap_any_text_in_anonymous_block_container(); + + self.jobs.push(FlexLevelJob::Element { + node, + style, + display, + contents, + box_slot, + }) + } +} + +/// https://drafts.csswg.org/css-text/#white-space +fn is_only_document_white_space(run: &TextRun<'_, Node>) -> bool { + // FIXME: is this the right definition? See + // https://github.com/w3c/csswg-drafts/issues/5146 + // https://github.com/w3c/csswg-drafts/issues/5147 + run.text + .bytes() + .all(|byte| matches!(byte, b' ' | b'\n' | b'\t')) +} + +impl<'a, 'dom, Node: 'dom> FlexContainerBuilder<'a, 'dom, Node> +where + Node: NodeExt<'dom>, +{ + fn wrap_any_text_in_anonymous_block_container(&mut self) { + let runs = std::mem::take(&mut self.contiguous_text_runs); + if runs.iter().all(is_only_document_white_space) { + // There is no text run, or they all only contain document white space characters + } else { + self.jobs.push(FlexLevelJob::TextRuns(runs)); + self.has_text_runs = true; + } + } + + fn finish(mut self) -> FlexContainer { + self.wrap_any_text_in_anonymous_block_container(); + + let anonymous_style = if self.has_text_runs { + Some( + self.context + .shared_context() + .stylist + .style_for_anonymous::( + &self.context.shared_context().guards, + &style::selector_parser::PseudoElement::ServoText, + self.style, + ), + ) + } else { + None + }; + + let mut children = std::mem::take(&mut self.jobs) + .into_par_iter() + .map(|job| match job { + FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem( + IndependentFormattingContext::construct_for_text_runs( + self.context, + self.node, + anonymous_style.clone().unwrap(), + runs.into_iter().map(|run| crate::flow::inline::TextRun { + tag: run.node.as_opaque(), + text: run.text.into(), + parent_style: run.parent_style, + }), + ContentSizesRequest::None, // FIXME: request sizes when we start using them + self.text_decoration_line, + ), + )), + FlexLevelJob::Element { + node, + style, + display, + contents, + box_slot, + } => { + let display_inside = match display { + DisplayGeneratingBox::OutsideInside { inside, .. } => inside, + }; + let box_ = if style.get_box().position.is_absolutely_positioned() { + // https://drafts.csswg.org/css-flexbox/#abspos-items + ArcRefCell::new(FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( + AbsolutelyPositionedBox::construct( + self.context, + node, + style.clone(), + display_inside, + contents, + ), + ))) + } else { + ArcRefCell::new(FlexLevelBox::FlexItem( + IndependentFormattingContext::construct( + self.context, + node, + style.clone(), + display_inside, + contents, + ContentSizesRequest::None, // FIXME: request sizes when we start using them + self.text_decoration_line, + ), + )) + }; + box_slot.set(LayoutBox::FlexLevel(box_.clone())); + box_ + }, + }) + .collect::>(); + + // https://drafts.csswg.org/css-flexbox/#order-modified-document-order + children.sort_by_key(|child| match &*child.borrow() { + FlexLevelBox::FlexItem(item) => item.style.clone_order(), + + // “Absolutely-positioned children of a flex container are treated + // as having order: 0 for the purpose of determining their painting order + // relative to flex items.” + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => 0, + }); + + FlexContainer { children } + } +} + +impl FlexContainer { + pub(crate) fn layout( + &self, + layout_context: &LayoutContext, + positioning_context: &mut PositioningContext, + containing_block: &ContainingBlock, + tree_rank: usize, + ) -> IndependentLayout { + // FIXME + let _ = layout_context; + let _ = positioning_context; + let _ = containing_block; + let _ = tree_rank; + IndependentLayout { + fragments: Vec::new(), + content_block_size: Length::zero(), + } + } +} diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 186a4b4d4ff..f91330f45fb 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -47,6 +47,30 @@ impl BlockFormattingContext { }; (bfc, inline_content_sizes) } + + pub fn construct_for_text_runs<'dom>( + context: &LayoutContext, + runs: impl Iterator, + content_sizes: ContentSizesRequest, + text_decoration_line: TextDecorationLine, + ) -> (Self, BoxContentSizes) { + // FIXME: do white space collapsing + let inline_level_boxes = runs + .map(|run| ArcRefCell::new(InlineLevelBox::TextRun(run))) + .collect(); + + let ifc = InlineFormattingContext { + inline_level_boxes, + text_decoration_line, + }; + let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context)); + let contents = BlockContainer::InlineFormattingContext(ifc); + let bfc = Self { + contents, + contains_floats: false, + }; + (bfc, content_sizes) + } } struct BlockLevelJob<'dom, Node> { @@ -249,7 +273,7 @@ where fn handle_element( &mut self, node: Node, - style: &Arc, + style: Arc, display: DisplayGeneratingBox, contents: Contents, box_slot: BoxSlot<'dom>, @@ -265,22 +289,12 @@ where // https://drafts.csswg.org/css2/visuren.html#dis-pos-flo if box_style.position.is_absolutely_positioned() { self.handle_absolutely_positioned_element( - node, - style.clone(), - inside, - contents, - box_slot, + node, style, inside, contents, box_slot, ) } else if box_style.float.is_floating() { - self.handle_float_element(node, style.clone(), inside, contents, box_slot) + self.handle_float_element(node, style, inside, contents, box_slot) } else { - self.handle_block_level_element( - node, - style.clone(), - inside, - contents, - box_slot, - ) + self.handle_block_level_element(node, style, inside, contents, box_slot) } }, }, @@ -291,7 +305,7 @@ where &mut self, node: Node, input: Cow<'dom, str>, - parent_style: &Arc, + parent_style: Arc, ) { let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input); if leading_whitespace || !input.is_empty() { @@ -341,7 +355,6 @@ where } if let Some(text) = new_text_run_contents { - let parent_style = parent_style.clone(); inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun { tag: node.as_opaque(), parent_style, @@ -418,7 +431,7 @@ where fn handle_inline_level_element( &mut self, node: Node, - style: &Arc, + style: Arc, display_inside: DisplayInside, contents: Contents, ) -> ArcRefCell { @@ -449,14 +462,15 @@ where inline_box.last_fragment = true; ArcRefCell::new(InlineLevelBox::InlineBox(inline_box)) } else { + let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length()); ArcRefCell::new(InlineLevelBox::Atomic( IndependentFormattingContext::construct( self.context, node, - style.clone(), + style, display_inside, contents, - ContentSizesRequest::inline_if(!style.inline_size_is_length()), + content_sizes, // Text decorations are not propagated to atomic inline-level descendants. TextDecorationLine::NONE, ), diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 61f6ca888b2..4c86b477d14 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -10,6 +10,7 @@ use crate::display_list::stacking_context::{ }; use crate::dom_traversal::{iter_child_nodes, Contents, NodeExt}; use crate::element_data::LayoutBox; +use crate::flexbox::FlexLevelBox; use crate::flow::construct::ContainsFloats; use crate::flow::float::FloatBox; use crate::flow::inline::InlineLevelBox; @@ -119,6 +120,7 @@ impl BoxTree { enum UpdatePoint { AbsolutelyPositionedBlockLevelBox(ArcRefCell), AbsolutelyPositionedInlineLevelBox(ArcRefCell), + AbsolutelyPositionedFlexLevelBox(ArcRefCell), } fn update_point<'dom, Node>( @@ -188,6 +190,14 @@ impl BoxTree { }, _ => return None, }, + LayoutBox::FlexLevel(flex_level_box) => match &*flex_level_box.borrow() { + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) + if box_style.position.is_absolutely_positioned() => + { + UpdatePoint::AbsolutelyPositionedFlexLevelBox(flex_level_box.clone()) + }, + _ => return None, + }, }; Some((primary_style.clone(), display_inside, update_point)) } @@ -217,6 +227,12 @@ impl BoxTree { out_of_flow_absolutely_positioned_box, ); }, + UpdatePoint::AbsolutelyPositionedFlexLevelBox(flex_level_box) => { + *flex_level_box.borrow_mut() = + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox( + out_of_flow_absolutely_positioned_box, + ); + }, } return true; } diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 9e73a17891e..a721b54ba0f 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -4,6 +4,7 @@ use crate::context::LayoutContext; use crate::dom_traversal::{Contents, NodeExt}; +use crate::flexbox::FlexContainer; use crate::flow::BlockFormattingContext; use crate::fragments::Fragment; use crate::positioned::PositioningContext; @@ -43,6 +44,7 @@ pub(crate) struct IndependentLayout { #[derive(Debug, Serialize)] enum IndependentFormattingContextContents { Flow(BlockFormattingContext), + Flex(FlexContainer), // Not called FC in specs, but behaves close enough Replaced(ReplacedContent), @@ -53,6 +55,7 @@ pub(crate) struct NonReplacedIFC<'a>(NonReplacedIFCKind<'a>); enum NonReplacedIFCKind<'a> { Flow(&'a BlockFormattingContext), + Flex(&'a FlexContainer), } impl IndependentFormattingContext { @@ -83,6 +86,22 @@ impl IndependentFormattingContext { contents: IndependentFormattingContextContents::Flow(bfc), } }, + DisplayInside::Flex => { + let (fc, content_sizes) = FlexContainer::construct( + context, + node, + &style, + non_replaced, + content_sizes, + propagated_text_decoration_line, + ); + Self { + tag: node.as_opaque(), + style, + content_sizes, + contents: IndependentFormattingContextContents::Flex(fc), + } + }, }, Err(replaced) => { let content_sizes = content_sizes.compute(|| replaced.inline_content_sizes(&style)); @@ -96,6 +115,28 @@ impl IndependentFormattingContext { } } + pub fn construct_for_text_runs<'dom>( + context: &LayoutContext, + node: impl NodeExt<'dom>, + style: Arc, + runs: impl Iterator, + content_sizes: ContentSizesRequest, + propagated_text_decoration_line: TextDecorationLine, + ) -> Self { + let (bfc, content_sizes) = BlockFormattingContext::construct_for_text_runs( + context, + runs, + content_sizes, + propagated_text_decoration_line, + ); + Self { + tag: node.as_opaque(), + style, + content_sizes, + contents: IndependentFormattingContextContents::Flow(bfc), + } + } + pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> { use self::IndependentFormattingContextContents as Contents; use self::NonReplacedIFC as NR; @@ -103,6 +144,7 @@ impl IndependentFormattingContext { match &self.contents { Contents::Replaced(r) => Ok(r), Contents::Flow(f) => Err(NR(Kind::Flow(f))), + Contents::Flex(f) => Err(NR(Kind::Flex(f))), } } } @@ -122,6 +164,12 @@ impl NonReplacedIFC<'_> { containing_block, tree_rank, ), + NonReplacedIFCKind::Flex(fc) => fc.layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + ), } } } diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index f4f3a81d065..24dc902bdd4 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -15,6 +15,7 @@ pub mod data; pub mod display_list; mod dom_traversal; pub mod element_data; +mod flexbox; mod flow; mod formatting_contexts; mod fragments; diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index dc3930d7058..f5e1a9dbca3 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -48,6 +48,7 @@ pub(crate) enum DisplayOutside { pub(crate) enum DisplayInside { Flow, FlowRoot, + Flex, } /// Percentages resolved but not `auto` margins @@ -394,6 +395,7 @@ impl From for Display { let inside = match packed.inside() { stylo::DisplayInside::Flow => DisplayInside::Flow, stylo::DisplayInside::FlowRoot => DisplayInside::FlowRoot, + stylo::DisplayInside::Flex => DisplayInside::Flex, // These should not be values of DisplayInside, but oh well stylo::DisplayInside::None => return Display::None, diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 3af5f86561b..239c2edd5cb 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -266,7 +266,8 @@ ${helpers.predefined_type( "order", "Integer", "0", - engines="gecko servo-2013", + engines="gecko servo-2013 servo-2020", + servo_2020_pref="layout.flexbox.enabled", extra_prefixes="webkit", animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-flexbox/#order-property", diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 4f767e89bee..212ea92f10b 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -34,6 +34,17 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool { static_prefs::pref!("layout.css.xul-box-display-values.content.enabled") } +fn flexbox_enabled() -> bool { + if cfg!(feature = "servo-layout-2020") { + servo_config::prefs::pref_map() + .get("layout.flexbox.enabled") + .as_bool() + .unwrap_or(false) + } else { + true + } +} + /// Defines an element’s display type, which consists of /// the two basic qualities of how an element generates boxes /// @@ -63,7 +74,6 @@ pub enum DisplayInside { Contents, Flow, FlowRoot, - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] Flex, #[cfg(feature = "gecko")] Grid, @@ -146,9 +156,7 @@ impl Display { pub const Block: Self = Self::new(DisplayOutside::Block, DisplayInside::Flow); #[cfg(feature = "gecko")] pub const FlowRoot: Self = Self::new(DisplayOutside::Block, DisplayInside::FlowRoot); - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] pub const Flex: Self = Self::new(DisplayOutside::Block, DisplayInside::Flex); - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] pub const InlineFlex: Self = Self::new(DisplayOutside::Inline, DisplayInside::Flex); #[cfg(feature = "gecko")] pub const Grid: Self = Self::new(DisplayOutside::Block, DisplayInside::Grid); @@ -317,9 +325,9 @@ impl Display { #[inline] pub fn is_atomic_inline_level(&self) -> bool { match *self { - Display::InlineBlock => true, + Display::InlineBlock | Display::InlineFlex => true, #[cfg(any(feature = "servo-layout-2013"))] - Display::InlineFlex | Display::InlineTable => true, + Display::InlineTable => true, _ => false, } } @@ -330,7 +338,6 @@ impl Display { /// This is used to implement various style fixups. pub fn is_item_container(&self) -> bool { match self.inside() { - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] DisplayInside::Flex => true, #[cfg(feature = "gecko")] DisplayInside::Grid => true, @@ -432,12 +439,9 @@ impl ToCss for Display { _ => match (outside, inside) { #[cfg(feature = "gecko")] (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"), + (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"), #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] - (DisplayOutside::Inline, DisplayInside::Flex) | - (DisplayOutside::Inline, DisplayInside::Table) => { - dest.write_str("inline-")?; - inside.to_css(dest) - }, + (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"), #[cfg(feature = "gecko")] (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"), (_, inside) => { @@ -467,12 +471,11 @@ fn parse_display_inside<'i, 't>( ) -> Result> { Ok(try_match_ident_ignore_ascii_case! { input, "flow" => DisplayInside::Flow, + "flex" if flexbox_enabled() => DisplayInside::Flex, #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))] "flow-root" => DisplayInside::FlowRoot, #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] "table" => DisplayInside::Table, - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] - "flex" => DisplayInside::Flex, #[cfg(feature = "gecko")] "grid" => DisplayInside::Grid, #[cfg(feature = "gecko")] @@ -575,10 +578,8 @@ impl Parse for Display { "inline-block" => Display::InlineBlock, #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] "inline-table" => Display::InlineTable, - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] - "-webkit-flex" => Display::Flex, - #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] - "inline-flex" | "-webkit-inline-flex" => Display::InlineFlex, + "-webkit-flex" if flexbox_enabled() => Display::Flex, + "inline-flex" | "-webkit-inline-flex" if flexbox_enabled() => Display::InlineFlex, #[cfg(feature = "gecko")] "inline-grid" => Display::InlineGrid, #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] diff --git a/resources/prefs.json b/resources/prefs.json index 3d6133d21d2..f70a277df06 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -88,6 +88,7 @@ "js.werror.enabled": false, "layout.animations.test.enabled": false, "layout.columns.enabled": false, + "layout.flexbox.enabled": false, "layout.threads": 3, "layout.viewport.enabled": false, "layout.writing-mode.enabled": false, diff --git a/tests/wpt/metadata/css/css-flexbox/__dir__.ini b/tests/wpt/metadata/css/css-flexbox/__dir__.ini index 383f96c4de9..e4af70583e1 100644 --- a/tests/wpt/metadata/css/css-flexbox/__dir__.ini +++ b/tests/wpt/metadata/css/css-flexbox/__dir__.ini @@ -1 +1 @@ -prefs: ["layout.columns.enabled:true"] +prefs: ["layout.columns.enabled:true", "layout.flexbox.enabled:true"]