Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Support content-visibility css + resolve fixme #267

Merged
merged 2 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Tests/LibWeb/Layout/expected/css-content-visibility.txt
Original file line number Diff line number Diff line change
@@ -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]
2 changes: 2 additions & 0 deletions Tests/LibWeb/Layout/expected/details-closed.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
"I'm a summary"
TextNode <#text>
ListItemMarkerBox <(anonymous)> at (8,8) content-size 12x17 children: not-inline
BlockContainer <slot> at (8,25) content-size 784x0 children: not-inline
BlockContainer <(anonymous)> at (8,25) content-size 784x0 children: inline
TextNode <#text>

Expand All @@ -19,4 +20,5 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (ListItemBox<SUMMARY>) [32,8 760x17]
TextPaintable (TextNode<#text>)
MarkerPaintable (ListItemMarkerBox(anonymous)) [8,8 12x17]
PaintableWithLines (BlockContainer<SLOT>) [8,25 784x0]
PaintableWithLines (BlockContainer(anonymous)) [8,25 784x0]
9 changes: 9 additions & 0 deletions Tests/LibWeb/Layout/input/css-content-visibility.html
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Userland/Libraries/LibWeb/CSS/ComputedValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class InitialValues {
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; }
Expand Down Expand Up @@ -352,6 +353,7 @@ class ComputedValues {
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; }
Expand Down Expand Up @@ -507,6 +509,7 @@ class ComputedValues {
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() };
Expand Down Expand Up @@ -654,6 +657,7 @@ class MutableComputedValues final : public ComputedValues {
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; }
Expand Down
5 changes: 5 additions & 0 deletions Userland/Libraries/LibWeb/CSS/Enums.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@
"right",
"both"
],
"content-visibility": [
"visible",
"auto",
"hidden"
],
"cursor": [
"auto",
"default",
Expand Down
9 changes: 9 additions & 0 deletions Userland/Libraries/LibWeb/CSS/Properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions Userland/Libraries/LibWeb/CSS/StyleInvalidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
6 changes: 6 additions & 0 deletions Userland/Libraries/LibWeb/CSS/StyleProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/CSS/StyleProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class StyleProperties : public RefCounted<StyleProperties> {
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;
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/DOM/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
3 changes: 1 addition & 2 deletions Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,8 @@ void HTMLDetailsElement::update_shadow_tree_style()
display: block;
)~~~"_string));
} else {
// FIXME: Should be `display: block` but we do not support `content-visibility: hidden`.
MUST(m_descendants_slot->set_attribute(HTML::AttributeNames::style, R"~~~(
display: none;
display: block;
content-visibility: hidden;
)~~~"_string));
}
Expand Down
4 changes: 4 additions & 0 deletions Userland/Libraries/LibWeb/Layout/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
21 changes: 17 additions & 4 deletions Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down