From 82989554abf6ca8f261de9a51c9e3d3c20f5e68b Mon Sep 17 00:00:00 2001 From: BenJilks Date: Sat, 10 Aug 2024 23:13:26 +0100 Subject: [PATCH] LibWeb: Use reverse direction on flex containers with `rtl` direction If a flex container has `direction: rtl` set, reverse the row direction. --- .../expected/writing-modes-direction-flex.txt | 53 +++++++++++++++++++ .../input/writing-modes-direction-flex.html | 5 ++ .../Libraries/LibWeb/CSS/ComputedValues.h | 4 ++ Userland/Libraries/LibWeb/CSS/Enums.json | 4 ++ Userland/Libraries/LibWeb/CSS/Properties.json | 5 +- .../Libraries/LibWeb/CSS/StyleProperties.cpp | 6 +++ .../Libraries/LibWeb/CSS/StyleProperties.h | 1 + .../LibWeb/Layout/FlexFormattingContext.cpp | 13 +++++ .../LibWeb/Layout/FlexFormattingContext.h | 2 +- Userland/Libraries/LibWeb/Layout/Node.cpp | 3 ++ 10 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/writing-modes-direction-flex.txt create mode 100644 Tests/LibWeb/Layout/input/writing-modes-direction-flex.html diff --git a/Tests/LibWeb/Layout/expected/writing-modes-direction-flex.txt b/Tests/LibWeb/Layout/expected/writing-modes-direction-flex.txt new file mode 100644 index 00000000000..dcbb25dd0e7 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/writing-modes-direction-flex.txt @@ -0,0 +1,53 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x50 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x34 children: not-inline + Box
at (8,8) content-size 784x17 flex-container(row) [FFC] children: not-inline + BlockContainer
at (763.96875,8) content-size 28.03125x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [763.96875,8 28.03125x17] baseline: 13.296875 + "aaa" + TextNode <#text> + BlockContainer
at (735.5625,8) content-size 28.40625x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [735.5625,8 28.40625x17] baseline: 13.296875 + "bbb" + TextNode <#text> + BlockContainer
at (708.890625,8) content-size 26.671875x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [708.890625,8 26.671875x17] baseline: 13.296875 + "ccc" + TextNode <#text> + BlockContainer <(anonymous)> at (8,25) content-size 784x0 children: inline + TextNode <#text> + Box
at (8,25) content-size 784x17 flex-container(row-reverse) [FFC] children: not-inline + BlockContainer
at (8,25) content-size 28.03125x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [8,25 28.03125x17] baseline: 13.296875 + "aaa" + TextNode <#text> + BlockContainer
at (36.03125,25) content-size 28.40625x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [36.03125,25 28.40625x17] baseline: 13.296875 + "bbb" + TextNode <#text> + BlockContainer
at (64.4375,25) content-size 26.671875x17 flex-item [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [64.4375,25 26.671875x17] baseline: 13.296875 + "ccc" + TextNode <#text> + BlockContainer <(anonymous)> at (8,42) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x50] + PaintableWithLines (BlockContainer) [8,8 784x34] + PaintableBox (Box
) [8,8 784x17] + PaintableWithLines (BlockContainer
) [763.96875,8 28.03125x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
) [735.5625,8 28.40625x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
) [708.890625,8 26.671875x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [8,25 784x0] + PaintableBox (Box
) [8,25 784x17] + PaintableWithLines (BlockContainer
) [8,25 28.03125x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
) [36.03125,25 28.40625x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
) [64.4375,25 26.671875x17] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [8,42 784x0] diff --git a/Tests/LibWeb/Layout/input/writing-modes-direction-flex.html b/Tests/LibWeb/Layout/input/writing-modes-direction-flex.html new file mode 100644 index 00000000000..bdfe7aa1f4e --- /dev/null +++ b/Tests/LibWeb/Layout/input/writing-modes-direction-flex.html @@ -0,0 +1,5 @@ + + +
aaa
bbb
ccc
+
aaa
bbb
ccc
+ diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 82873ef911e..b3d6b72625d 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -178,6 +178,7 @@ public: static CSS::TableLayout table_layout() { return CSS::TableLayout::Auto; } static QuotesData quotes() { return QuotesData { .type = QuotesData::Type::Auto }; } static CSS::TransformBox transform_box() { return CSS::TransformBox::ViewBox; } + static CSS::Direction direction() { return CSS::Direction::Ltr; } // https://www.w3.org/TR/SVG/geometry.html static LengthPercentage cx() { return CSS::Length::make_px(0); } @@ -422,6 +423,7 @@ public: Vector> const& grid_template_areas() const { return m_noninherited.grid_template_areas; } CSS::ObjectFit object_fit() const { return m_noninherited.object_fit; } CSS::ObjectPosition object_position() const { return m_noninherited.object_position; } + CSS::Direction direction() const { return m_inherited.direction; } CSS::LengthBox const& inset() const { return m_noninherited.inset; } const CSS::LengthBox& margin() const { return m_noninherited.margin; } @@ -531,6 +533,7 @@ protected: CSS::ListStylePosition list_style_position { InitialValues::list_style_position() }; CSS::Visibility visibility { InitialValues::visibility() }; CSS::QuotesData quotes { InitialValues::quotes() }; + CSS::Direction direction { InitialValues::direction() }; Optional fill; CSS::FillRule fill_rule { InitialValues::fill_rule() }; @@ -756,6 +759,7 @@ public: void set_quotes(CSS::QuotesData value) { m_inherited.quotes = value; } void set_object_fit(CSS::ObjectFit value) { m_noninherited.object_fit = value; } void set_object_position(CSS::ObjectPosition value) { m_noninherited.object_position = value; } + void set_direction(CSS::Direction value) { m_inherited.direction = value; } void set_fill(SVGPaint value) { m_inherited.fill = value; } void set_stroke(SVGPaint value) { m_inherited.stroke = value; } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index 74fc49c9c00..b5c47d71950 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -144,6 +144,10 @@ "zoom-in", "zoom-out" ], + "direction": [ + "ltr", + "rtl" + ], "display-box": [ "contents", "none" diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 1a89a8ecb10..a3b2a70f465 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -1065,9 +1065,8 @@ "animation-type": "none", "inherited": true, "initial": "ltr", - "valid-identifiers": [ - "ltr", - "rtl" + "valid-types": [ + "direction" ] }, "display": { diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 486204bda80..9c8c4e61882 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -1085,6 +1085,12 @@ Optional StyleProperties::table_layout() const return value_id_to_table_layout(value->to_identifier()); } +Optional StyleProperties::direction() const +{ + auto value = property(CSS::PropertyID::Direction); + return value_id_to_direction(value->to_identifier()); +} + Optional StyleProperties::mask_type() const { auto value = property(CSS::PropertyID::MaskType); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index d6dad7a51f7..233263c61b6 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -130,6 +130,7 @@ public: Optional object_fit() const; CSS::ObjectPosition object_position() const; Optional table_layout() const; + Optional direction() const; static Vector transformations_for_style_value(StyleValue const& value); Vector transformations() const; diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index 9c0978e5d0f..069a6dfa1b5 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -194,6 +194,19 @@ void FlexFormattingContext::parent_context_did_dimension_child_root_box() }); } +// https://www.w3.org/TR/css-flexbox-1/#flex-direction-property +bool FlexFormattingContext::is_direction_reverse() const +{ + switch (flex_container().computed_values().direction()) { + case CSS::Direction::Ltr: + return m_flex_direction == CSS::FlexDirection::ColumnReverse || m_flex_direction == CSS::FlexDirection::RowReverse; + case CSS::Direction::Rtl: + return m_flex_direction == CSS::FlexDirection::ColumnReverse || m_flex_direction == CSS::FlexDirection::Row; + default: + VERIFY_NOT_REACHED(); + } +} + void FlexFormattingContext::populate_specified_margins(FlexItem& item, CSS::FlexDirection flex_direction) const { auto width_of_containing_block = m_flex_container_state.content_width(); diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h index 29ce48054d3..8f18950314f 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h @@ -195,7 +195,7 @@ private: bool is_row_layout() const { return m_flex_direction == CSS::FlexDirection::Row || m_flex_direction == CSS::FlexDirection::RowReverse; } bool is_single_line() const { return flex_container().computed_values().flex_wrap() == CSS::FlexWrap::Nowrap; } - bool is_direction_reverse() const { return m_flex_direction == CSS::FlexDirection::ColumnReverse || m_flex_direction == CSS::FlexDirection::RowReverse; } + bool is_direction_reverse() const; void populate_specified_margins(FlexItem&, CSS::FlexDirection) const; void determine_intrinsic_size_of_flex_container(); diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 3221a4af974..8a18aa07ac7 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -872,6 +872,9 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) computed_values.set_object_position(computed_style.object_position()); + if (auto direction = computed_style.direction(); direction.has_value()) + computed_values.set_direction(direction.value()); + if (auto scrollbar_width = computed_style.scrollbar_width(); scrollbar_width.has_value()) computed_values.set_scrollbar_width(scrollbar_width.value());