diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 03d348030c..c3b1f25a79 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -23,6 +23,9 @@ namespace Web::CSS { +struct FlexBasisContent { }; +using FlexBasis = Variant; + struct AspectRatio { bool use_natural_aspect_ratio_if_available; Optional preferred_ratio; @@ -59,6 +62,7 @@ public: static CSS::Visibility visibility() { return CSS::Visibility::Visible; } static CSS::FlexDirection flex_direction() { return CSS::FlexDirection::Row; } static CSS::FlexWrap flex_wrap() { return CSS::FlexWrap::Nowrap; } + static CSS::FlexBasis flex_basis() { return CSS::Size::make_auto(); } static CSS::ImageRendering image_rendering() { return CSS::ImageRendering::Auto; } static CSS::JustifyContent justify_content() { return CSS::JustifyContent::FlexStart; } static CSS::AlignContent align_content() { return CSS::AlignContent::Stretch; } @@ -164,17 +168,6 @@ struct TransformOrigin { CSS::LengthPercentage y { Percentage(50) }; }; -enum class FlexBasis { - Content, - LengthPercentage, - Auto, -}; - -struct FlexBasisData { - CSS::FlexBasis type { CSS::FlexBasis::Auto }; - Optional length_percentage; -}; - struct ShadowData { Color color {}; CSS::Length offset_x { Length::make_px(0) }; @@ -246,7 +239,7 @@ public: CSS::WhiteSpace white_space() const { return m_inherited.white_space; } CSS::FlexDirection flex_direction() const { return m_noninherited.flex_direction; } CSS::FlexWrap flex_wrap() const { return m_noninherited.flex_wrap; } - FlexBasisData const& flex_basis() const { return m_noninherited.flex_basis; } + FlexBasis const& flex_basis() const { return m_noninherited.flex_basis; } float flex_grow() const { return m_noninherited.flex_grow; } float flex_shrink() const { return m_noninherited.flex_shrink; } int order() const { return m_noninherited.order; } @@ -398,7 +391,7 @@ protected: Vector background_layers; CSS::FlexDirection flex_direction { InitialValues::flex_direction() }; CSS::FlexWrap flex_wrap { InitialValues::flex_wrap() }; - CSS::FlexBasisData flex_basis {}; + CSS::FlexBasis flex_basis { InitialValues::flex_basis() }; float flex_grow { InitialValues::flex_grow() }; float flex_shrink { InitialValues::flex_shrink() }; int order { InitialValues::order() }; @@ -492,7 +485,7 @@ public: BorderData& border_bottom() { return m_noninherited.border_bottom; } void set_flex_direction(CSS::FlexDirection value) { m_noninherited.flex_direction = value; } void set_flex_wrap(CSS::FlexWrap value) { m_noninherited.flex_wrap = value; } - void set_flex_basis(FlexBasisData value) { m_noninherited.flex_basis = move(value); } + void set_flex_basis(FlexBasis value) { m_noninherited.flex_basis = move(value); } void set_flex_grow(float value) { m_noninherited.flex_grow = value; } void set_flex_shrink(float value) { m_noninherited.flex_shrink = value; } void set_order(int value) { m_noninherited.order = value; } diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index 0160e4d7f4..828082197e 100644 --- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -559,18 +559,14 @@ ErrorOr> ResolvedCSSStyleDeclaration::style_value_for_p return NumberStyleValue::create(layout_node.computed_values().fill_opacity()); case PropertyID::FillRule: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().fill_rule())); - case PropertyID::FlexBasis: { - switch (layout_node.computed_values().flex_basis().type) { - case FlexBasis::Content: - return IdentifierStyleValue::create(ValueID::Content); - case FlexBasis::LengthPercentage: - return style_value_for_length_percentage(*layout_node.computed_values().flex_basis().length_percentage); - case FlexBasis::Auto: - return IdentifierStyleValue::create(ValueID::Auto); - default: - VERIFY_NOT_REACHED(); - } - break; + case PropertyID::FlexBasis: + return layout_node.computed_values().flex_basis().visit( + [](CSS::FlexBasisContent const&) -> ErrorOr> { + return IdentifierStyleValue::create(ValueID::Content); + }, + [&](CSS::Size const& size) -> ErrorOr> { + return style_value_for_size(size); + }); case PropertyID::FlexDirection: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().flex_direction())); case PropertyID::FlexGrow: @@ -838,7 +834,6 @@ ErrorOr> ResolvedCSSStyleDeclaration::style_value_for_p dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Computed style for the '{}' property was requested", string_from_property_id(property_id)); return nullptr; } - } } Optional ResolvedCSSStyleDeclaration::property(PropertyID property_id) const diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 5447774005..e8110f531c 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -327,26 +327,14 @@ Optional StyleProperties::flex_wrap() const return value_id_to_flex_wrap(value->to_identifier()); } -Optional StyleProperties::flex_basis() const +Optional StyleProperties::flex_basis() const { auto value = property(CSS::PropertyID::FlexBasis); if (value->is_identifier() && value->to_identifier() == CSS::ValueID::Content) - return { { CSS::FlexBasis::Content, {} } }; + return CSS::FlexBasisContent {}; - if (value->has_auto()) - return { { CSS::FlexBasis::Auto, {} } }; - - if (value->is_percentage()) - return { { CSS::FlexBasis::LengthPercentage, value->as_percentage().percentage() } }; - - if (value->is_length()) - return { { CSS::FlexBasis::LengthPercentage, value->as_length().length() } }; - - if (value->is_calculated()) - return { { CSS::FlexBasis::LengthPercentage, CSS::LengthPercentage { value->as_calculated() } } }; - - return {}; + return size_value(CSS::PropertyID::FlexBasis); } float StyleProperties::flex_grow() const diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 041038c5ee..675325cf45 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -69,7 +69,7 @@ public: Optional list_style_position() const; Optional flex_direction() const; Optional flex_wrap() const; - Optional flex_basis() const; + Optional flex_basis() const; float flex_grow() const; float flex_shrink() const; int order() const; diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index c32c72521f..021b936270 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -27,18 +27,6 @@ template return ::max(min, ::min(value, max)); } -// FIXME: This is a hack helper, remove it when no longer needed. -static CSS::Size to_css_size(CSS::LengthPercentage const& length_percentage) -{ - if (length_percentage.is_auto()) - return CSS::Size::make_auto(); - if (length_percentage.is_length()) - return CSS::Size::make_length(length_percentage.length()); - if (length_percentage.is_calculated()) - return CSS::Size::make_calculated(length_percentage.calculated()); - return CSS::Size::make_percentage(length_percentage.percentage()); -} - CSSPixels FlexFormattingContext::get_pixel_width(Box const& box, CSS::Size const& size) const { auto containing_block_width = containing_block_width_for(box); @@ -537,41 +525,30 @@ void FlexFormattingContext::determine_available_space_for_items(AvailableSpace c } // https://drafts.csswg.org/css-flexbox-1/#propdef-flex-basis -CSS::FlexBasisData FlexFormattingContext::used_flex_basis_for_item(FlexItem const& item) const +CSS::FlexBasis FlexFormattingContext::used_flex_basis_for_item(FlexItem const& item) const { auto flex_basis = item.box->computed_values().flex_basis(); - if (flex_basis.type == CSS::FlexBasis::Auto) { + if (flex_basis.has() && flex_basis.get().is_auto()) { // https://drafts.csswg.org/css-flexbox-1/#valdef-flex-basis-auto // When specified on a flex item, the auto keyword retrieves the value of the main size property as the used flex-basis. // If that value is itself auto, then the used value is content. auto const& main_size = is_row_layout() ? item.box->computed_values().width() : item.box->computed_values().height(); if (main_size.is_auto()) { - flex_basis.type = CSS::FlexBasis::Content; + flex_basis = CSS::FlexBasisContent {}; } else { - flex_basis.type = CSS::FlexBasis::LengthPercentage; - if (main_size.is_length()) { - flex_basis.length_percentage = main_size.length(); - } else if (main_size.is_percentage()) { - flex_basis.length_percentage = main_size.percentage(); - } else if (main_size.is_calculated()) { - flex_basis.length_percentage = CSS::LengthPercentage { main_size.calculated() }; - } else { - // FIXME: Support other size values! - dbgln("FIXME: Unsupported main size for flex-basis: {}", main_size); - flex_basis.type = CSS::FlexBasis::Content; - } + flex_basis = main_size; } } // For example, percentage values of flex-basis are resolved against the flex item’s containing block // (i.e. its flex container); and if that containing block’s size is indefinite, // the used value for flex-basis is content. - if (flex_basis.type == CSS::FlexBasis::LengthPercentage - && flex_basis.length_percentage->is_percentage() + if (flex_basis.has() + && flex_basis.get().is_percentage() && !has_definite_main_size(flex_container())) { - flex_basis.type = CSS::FlexBasis::Content; + flex_basis = CSS::FlexBasisContent {}; } return flex_basis; @@ -609,20 +586,21 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( item.flex_base_size = [&] { item.used_flex_basis = used_flex_basis_for_item(item); - item.used_flex_basis_is_definite = [&](CSS::FlexBasisData const& flex_basis) -> bool { - if (flex_basis.type != CSS::FlexBasis::LengthPercentage) + item.used_flex_basis_is_definite = [&](CSS::FlexBasis const& flex_basis) -> bool { + if (!flex_basis.has()) return false; - if (flex_basis.length_percentage->is_auto()) + auto const& size = flex_basis.get(); + if (size.is_auto() || size.is_min_content() || size.is_max_content() || size.is_fit_content()) return false; - if (flex_basis.length_percentage->is_length()) + if (size.is_length()) return true; bool can_resolve_percentages = is_row_layout() ? m_flex_container_state.has_definite_width() : m_flex_container_state.has_definite_height(); - if (flex_basis.length_percentage->is_calculated()) { - auto const& calc_value = *flex_basis.length_percentage->calculated(); + if (size.is_calculated()) { + auto const& calc_value = size.calculated(); if (calc_value.resolves_to_percentage()) return can_resolve_percentages; if (calc_value.resolves_to_length()) { @@ -632,15 +610,16 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( } return false; } - VERIFY(flex_basis.length_percentage->is_percentage()); + VERIFY(size.is_percentage()); return can_resolve_percentages; - }(item.used_flex_basis); + }(*item.used_flex_basis); // A. If the item has a definite used flex basis, that’s the flex base size. if (item.used_flex_basis_is_definite) { + auto const& size = item.used_flex_basis->get(); if (is_row_layout()) - return get_pixel_width(child_box, to_css_size(item.used_flex_basis.length_percentage.value())); - return get_pixel_height(child_box, to_css_size(item.used_flex_basis.length_percentage.value())); + return get_pixel_width(child_box, size); + return get_pixel_height(child_box, size); } // B. If the flex item has ... @@ -648,7 +627,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( // - a used flex basis of content, and // - a definite cross size, if (item.box->has_preferred_aspect_ratio() - && item.used_flex_basis.type == CSS::FlexBasis::Content + && item.used_flex_basis->has() && has_definite_cross_size(item.box)) { // flex_base_size is calculated from definite cross size and intrinsic aspect ratio return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints( @@ -662,7 +641,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( // and the flex container is being sized under a min-content or max-content constraint // (e.g. when performing automatic table layout [CSS21]), size the item under that constraint. // The flex base size is the item’s resulting main size. - if (item.used_flex_basis.type == CSS::FlexBasis::Content && m_available_space_for_items->main.is_intrinsic_sizing_constraint()) { + if (item.used_flex_basis->has() && m_available_space_for_items->main.is_intrinsic_sizing_constraint()) { if (m_available_space_for_items->main.is_min_content()) return calculate_min_content_main_size(item); return calculate_max_content_main_size(item); @@ -672,7 +651,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( // the available main size is infinite, and the flex item’s inline axis is parallel to the main axis, // lay the item out using the rules for a box in an orthogonal flow [CSS3-WRITING-MODES]. // The flex base size is the item’s max-content main size. - if (item.used_flex_basis.type == CSS::FlexBasis::Content + if (item.used_flex_basis->has() // FIXME: && main_size is infinite && inline axis is parallel to the main axis && false && false) { TODO(); @@ -704,7 +683,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( // This means that *all* intrinsic heights computed within a flex formatting context will // automatically use the fit-content width in case a used width is not known yet. - if (item.used_flex_basis.type == CSS::FlexBasis::Content) { + if (item.used_flex_basis->has()) { return calculate_max_content_main_size(item); } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h index 6aed71c3cb..5335efb980 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h @@ -53,7 +53,7 @@ private: struct FlexItem { JS::NonnullGCPtr box; - CSS::FlexBasisData used_flex_basis {}; + Optional used_flex_basis {}; bool used_flex_basis_is_definite { false }; CSSPixels flex_base_size { 0 }; CSSPixels hypothetical_main_size { 0 }; @@ -214,7 +214,7 @@ private: virtual void parent_context_did_dimension_child_root_box() override; - CSS::FlexBasisData used_flex_basis_for_item(FlexItem const&) const; + CSS::FlexBasis used_flex_basis_for_item(FlexItem const&) const; LayoutState::UsedValues& m_flex_container_state;