LibWeb: Support content-visibility css

This commit is contained in:
Edwin Hoksberg 2024-06-23 14:52:56 +02:00 committed by Sam Atkins
parent bd72ff5669
commit 020b20d817
Notes: sideshowbarker 2024-07-19 21:35:47 +09:00
12 changed files with 69 additions and 7 deletions

View File

@ -0,0 +1,9 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x48 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x32 children: not-inline
BlockContainer <div> at (24,24) content-size 752x0 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x48]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x32]
PaintableWithLines (BlockContainer<DIV>) [8,8 784x32]

View File

@ -0,0 +1,9 @@
<!doctype html><style>
div {
padding: 16px;
content-visibility: hidden;
}
div::before {
content: 'I am invisible';
}
</style><div>I am not visible<span>and nor am I

View File

@ -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

View File

@ -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<Color> 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; }

View File

@ -101,6 +101,11 @@
"right",
"both"
],
"content-visibility": [
"visible",
"auto",
"hidden"
],
"cursor": [
"auto",
"default",

View File

@ -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",

View File

@ -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();
}

View File

@ -744,6 +744,12 @@ StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 in
return { {}, quote_nesting_level };
}
Optional<CSS::ContentVisibility> StyleProperties::content_visibility() const
{
auto value = property(CSS::PropertyID::ContentVisibility);
return value_id_to_content_visibility(value->to_identifier());
}
Optional<CSS::Cursor> StyleProperties::cursor() const
{
auto value = property(CSS::PropertyID::Cursor);

View File

@ -86,6 +86,7 @@ public:
u32 final_quote_nesting_level { 0 };
};
ContentDataAndQuoteNestingLevel content(u32 initial_quote_nesting_level) const;
Optional<CSS::ContentVisibility> content_visibility() const;
Optional<CSS::Cursor> cursor() const;
Optional<CSS::WhiteSpace> white_space() const;
Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;

View File

@ -17,6 +17,7 @@
#include <LibWeb/CSS/ResolvedCSSStyleDeclaration.h>
#include <LibWeb/CSS/SelectorEngine.h>
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/CSS/StyleProperties.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
#include <LibWeb/DOM/Attr.h>

View File

@ -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());

View File

@ -371,15 +371,23 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
auto shadow_root = is<DOM::Element>(dom_node) ? verify_cast<DOM::Element>(dom_node).shadow_root() : nullptr;
auto element_has_content_visibility_hidden = [&dom_node]() {
if (is<DOM::Element>(dom_node)) {
auto& element = static_cast<DOM::Element&>(dom_node);
return element.computed_css_values()->content_visibility() == CSS::ContentVisibility::Hidden;
}
return false;
}();
// Add node for the ::before pseudo-element.
if (is<DOM::Element>(dom_node) && layout_node->can_have_children()) {
if (is<DOM::Element>(dom_node) && layout_node->can_have_children() && !element_has_content_visibility_hidden) {
auto& element = static_cast<DOM::Element&>(dom_node);
push_parent(verify_cast<NodeWithStyle>(*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<NodeWithStyle>(*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<HTML::HTMLSlotElement>(dom_node)) {
auto slottables = static_cast<HTML::HTMLSlotElement&>(dom_node).assigned_nodes_internal();
auto& slot_element = static_cast<HTML::HTMLSlotElement&>(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<NodeWithStyle>(*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::Element>(dom_node) && layout_node->can_have_children()) {
if (is<DOM::Element>(dom_node) && layout_node->can_have_children() && !element_has_content_visibility_hidden) {
auto& element = static_cast<DOM::Element&>(dom_node);
push_parent(verify_cast<NodeWithStyle>(*layout_node));
create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Type::After, AppendOrPrepend::Append);