From 020b20d817d51dda9c0f9306543c69f4020891eb Mon Sep 17 00:00:00 2001 From: Edwin Hoksberg Date: Sun, 23 Jun 2024 14:52:56 +0200 Subject: [PATCH] LibWeb: Support content-visibility css --- .../expected/css-content-visibility.txt | 9 ++++++++ .../Layout/input/css-content-visibility.html | 9 ++++++++ .../css/getComputedStyle-print-all.txt | 3 ++- .../Libraries/LibWeb/CSS/ComputedValues.h | 4 ++++ Userland/Libraries/LibWeb/CSS/Enums.json | 5 +++++ Userland/Libraries/LibWeb/CSS/Properties.json | 9 ++++++++ .../LibWeb/CSS/StyleInvalidation.cpp | 4 ++-- .../Libraries/LibWeb/CSS/StyleProperties.cpp | 6 ++++++ .../Libraries/LibWeb/CSS/StyleProperties.h | 1 + Userland/Libraries/LibWeb/DOM/Element.cpp | 1 + Userland/Libraries/LibWeb/Layout/Node.cpp | 4 ++++ .../Libraries/LibWeb/Layout/TreeBuilder.cpp | 21 +++++++++++++++---- 12 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/css-content-visibility.txt create mode 100644 Tests/LibWeb/Layout/input/css-content-visibility.html diff --git a/Tests/LibWeb/Layout/expected/css-content-visibility.txt b/Tests/LibWeb/Layout/expected/css-content-visibility.txt new file mode 100644 index 00000000000..088fb3879d0 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-content-visibility.txt @@ -0,0 +1,9 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x48 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x32 children: not-inline + BlockContainer
at (24,24) content-size 752x0 children: not-inline + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x48] + PaintableWithLines (BlockContainer) [8,8 784x32] + PaintableWithLines (BlockContainer
) [8,8 784x32] \ No newline at end of file diff --git a/Tests/LibWeb/Layout/input/css-content-visibility.html b/Tests/LibWeb/Layout/input/css-content-visibility.html new file mode 100644 index 00000000000..5ce60621d4e --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-content-visibility.html @@ -0,0 +1,9 @@ +
I am not visibleand nor am I \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index 97a22823cb9..fc2a41b3184 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -87,6 +87,7 @@ color: rgb(0, 0, 0) column-count: auto column-gap: auto content: normal +content-visibility: visible cursor: auto cx: 0px cy: 0px @@ -119,7 +120,7 @@ grid-row-start: auto grid-template-areas: grid-template-columns: grid-template-rows: -height: 2057px +height: 2074px image-rendering: auto inline-size: auto inset-block-end: auto diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 6a2cd9e6f52..1201095f2b1 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -100,6 +100,7 @@ public: static CSS::CaptionSide caption_side() { return CSS::CaptionSide::Top; } static CSS::Clear clear() { return CSS::Clear::None; } static CSS::Clip clip() { return CSS::Clip::make_auto(); } + static CSS::ContentVisibility content_visibility() { return CSS::ContentVisibility::Visible; } static CSS::Cursor cursor() { return CSS::Cursor::Auto; } static CSS::WhiteSpace white_space() { return CSS::WhiteSpace::Normal; } static CSS::TextAlign text_align() { return CSS::TextAlign::Left; } @@ -352,6 +353,7 @@ public: CSS::CaptionSide caption_side() const { return m_inherited.caption_side; } CSS::Clear clear() const { return m_noninherited.clear; } CSS::Clip clip() const { return m_noninherited.clip; } + CSS::ContentVisibility content_visibility() const { return m_inherited.content_visibility; } CSS::Cursor cursor() const { return m_inherited.cursor; } CSS::ContentData content() const { return m_noninherited.content; } CSS::PointerEvents pointer_events() const { return m_inherited.pointer_events; } @@ -507,6 +509,7 @@ protected: Color color { InitialValues::color() }; Optional accent_color {}; Color webkit_text_fill_color { InitialValues::color() }; + CSS::ContentVisibility content_visibility { InitialValues::content_visibility() }; CSS::Cursor cursor { InitialValues::cursor() }; CSS::ImageRendering image_rendering { InitialValues::image_rendering() }; CSS::PointerEvents pointer_events { InitialValues::pointer_events() }; @@ -654,6 +657,7 @@ public: void set_color(Color color) { m_inherited.color = color; } void set_clip(CSS::Clip const& clip) { m_noninherited.clip = clip; } void set_content(ContentData const& content) { m_noninherited.content = content; } + void set_content_visibility(CSS::ContentVisibility content_visibility) { m_inherited.content_visibility = content_visibility; } void set_cursor(CSS::Cursor cursor) { m_inherited.cursor = cursor; } void set_image_rendering(CSS::ImageRendering value) { m_inherited.image_rendering = value; } void set_pointer_events(CSS::PointerEvents value) { m_inherited.pointer_events = value; } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index 7417904f0a8..59d2d925f69 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -101,6 +101,11 @@ "right", "both" ], + "content-visibility": [ + "visible", + "auto", + "hidden" + ], "cursor": [ "auto", "default", diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 42fac029af7..3dc61948690 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -897,6 +897,15 @@ "no-close-quote" ] }, + "content-visibility": { + "animation-type": "none", + "__comment": "FIXME: Implement animation https://drafts.csswg.org/css-contain/#content-visibility-animation", + "inherited": false, + "initial": "visible", + "valid-types": [ + "content-visibility" + ] + }, "cursor": { "affects-layout": false, "animation-type": "discrete", diff --git a/Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp b/Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp index fd02111a3bd..a9e663641e8 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp @@ -17,9 +17,9 @@ RequiredInvalidationAfterStyleChange compute_property_invalidation(CSS::Property if (!property_value_changed) return invalidation; - // NOTE: If the computed CSS display property changes, we have to rebuild the entire layout tree. + // NOTE: If the computed CSS display/content-visibility property changes, we have to rebuild the entire layout tree. // In the future, we should figure out ways to rebuild a smaller part of the tree. - if (property_id == CSS::PropertyID::Display) { + if (property_id == CSS::PropertyID::Display || property_id == CSS::PropertyID::ContentVisibility) { return RequiredInvalidationAfterStyleChange::full(); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 992f105725f..83ab51ec56a 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -744,6 +744,12 @@ StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 in return { {}, quote_nesting_level }; } +Optional StyleProperties::content_visibility() const +{ + auto value = property(CSS::PropertyID::ContentVisibility); + return value_id_to_content_visibility(value->to_identifier()); +} + Optional StyleProperties::cursor() const { auto value = property(CSS::PropertyID::Cursor); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 70af730d665..c8e80082277 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -86,6 +86,7 @@ public: u32 final_quote_nesting_level { 0 }; }; ContentDataAndQuoteNestingLevel content(u32 initial_quote_nesting_level) const; + Optional content_visibility() const; Optional cursor() const; Optional white_space() const; Optional line_style(CSS::PropertyID) const; diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index e774f1940d5..0134a1f9155 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index acd5a669c34..d94955f8ea5 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -613,6 +613,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) if (overflow_y.has_value()) computed_values.set_overflow_y(overflow_y.value()); + auto content_visibility = computed_style.content_visibility(); + if (content_visibility.has_value()) + computed_values.set_content_visibility(content_visibility.value()); + auto cursor = computed_style.cursor(); if (cursor.has_value()) computed_values.set_cursor(cursor.value()); diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index 5d8126f6e9e..5b637f7d3e7 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -371,15 +371,23 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& auto shadow_root = is(dom_node) ? verify_cast(dom_node).shadow_root() : nullptr; + auto element_has_content_visibility_hidden = [&dom_node]() { + if (is(dom_node)) { + auto& element = static_cast(dom_node); + return element.computed_css_values()->content_visibility() == CSS::ContentVisibility::Hidden; + } + return false; + }(); + // Add node for the ::before pseudo-element. - if (is(dom_node) && layout_node->can_have_children()) { + if (is(dom_node) && layout_node->can_have_children() && !element_has_content_visibility_hidden) { auto& element = static_cast(dom_node); push_parent(verify_cast(*layout_node)); create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Type::Before, AppendOrPrepend::Prepend); pop_parent(); } - if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children()) { + if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children() && !element_has_content_visibility_hidden) { push_parent(verify_cast(*layout_node)); if (shadow_root) { for (auto* node = shadow_root->first_child(); node; node = node->next_sibling()) { @@ -411,7 +419,12 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& } if (is(dom_node)) { - auto slottables = static_cast(dom_node).assigned_nodes_internal(); + auto& slot_element = static_cast(dom_node); + + if (slot_element.computed_css_values()->content_visibility() == CSS::ContentVisibility::Hidden) + return; + + auto slottables = slot_element.assigned_nodes_internal(); push_parent(verify_cast(*layout_node)); for (auto const& slottable : slottables) @@ -499,7 +512,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& } // Add nodes for the ::after pseudo-element. - if (is(dom_node) && layout_node->can_have_children()) { + if (is(dom_node) && layout_node->can_have_children() && !element_has_content_visibility_hidden) { auto& element = static_cast(dom_node); push_parent(verify_cast(*layout_node)); create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Type::After, AppendOrPrepend::Append);