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/flexbox.rs b/components/layout_2020/flexbox.rs new file mode 100644 index 00000000000..beccba69cc5 --- /dev/null +++ b/components/layout_2020/flexbox.rs @@ -0,0 +1,62 @@ +/* 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::context::LayoutContext; +use crate::dom_traversal::{NodeExt, NonReplacedContents}; +use crate::formatting_contexts::IndependentLayout; +use crate::positioned::PositioningContext; +use crate::sizing::{BoxContentSizes, ContentSizesRequest}; +use crate::ContainingBlock; +use servo_arc::Arc; +use style::properties::ComputedValues; +use style::values::specified::text::TextDecorationLine; + +// FIXME: `min-width: auto` is not zero: https://drafts.csswg.org/css-flexbox/#min-size-auto + +#[derive(Debug, Serialize)] +pub(crate) struct FlexContainer { + unimplemented_fallback: crate::flow::BlockFormattingContext, +} + +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 (unimplemented_fallback, content_sizes) = + crate::flow::BlockFormattingContext::construct( + context, + node, + style, + contents, + content_sizes, + propagated_text_decoration_line, + ); + ( + Self { + unimplemented_fallback, + }, + content_sizes, + ) + } + + pub(crate) fn layout( + &self, + layout_context: &LayoutContext, + positioning_context: &mut PositioningContext, + containing_block: &ContainingBlock, + tree_rank: usize, + ) -> IndependentLayout { + self.unimplemented_fallback.layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + ) + } +} diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 9e73a17891e..a94b9b374d1 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)); @@ -103,6 +122,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 +142,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/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"]