LibWeb: Recompute child style when parent's display changes
When a parent element's display property changes (e.g., to flex or grid), children may need to be blockified or un-blockified. Previously, children only received a recompute_inherited_style() call which doesn't run the blockification logic. This patch adds a parent_display_changed flag to the recursive style update that forces children to get a full style recompute when their parent's display change triggers a layout tree rebuild.
This commit is contained in:
parent
5fc276872a
commit
3b90eb1d49
4 changed files with 45 additions and 9 deletions
|
|
@ -1515,7 +1515,7 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static CSS::RequiredInvalidationAfterStyleChange update_style_recursively(Node& node, CSS::StyleComputer& style_computer, bool needs_inherited_style_update, bool recompute_elements_depending_on_custom_properties)
|
||||
[[nodiscard]] static CSS::RequiredInvalidationAfterStyleChange update_style_recursively(Node& node, CSS::StyleComputer& style_computer, bool needs_inherited_style_update, bool recompute_elements_depending_on_custom_properties, bool parent_display_changed)
|
||||
{
|
||||
bool const needs_full_style_update = node.document().needs_full_style_update();
|
||||
CSS::RequiredInvalidationAfterStyleChange invalidation;
|
||||
|
|
@ -1532,7 +1532,7 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
CSS::RequiredInvalidationAfterStyleChange node_invalidation;
|
||||
if (is<Element>(node)) {
|
||||
auto& element = static_cast<Element&>(node);
|
||||
if (needs_full_style_update || node.needs_style_update() || (recompute_elements_depending_on_custom_properties && element.style_uses_var_css_function())) {
|
||||
if (needs_full_style_update || node.needs_style_update() || parent_display_changed || (recompute_elements_depending_on_custom_properties && element.style_uses_var_css_function())) {
|
||||
node_invalidation = element.recompute_style(did_change_custom_properties);
|
||||
} else if (needs_inherited_style_update) {
|
||||
node_invalidation = element.recompute_inherited_style();
|
||||
|
|
@ -1559,11 +1559,14 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
}
|
||||
|
||||
bool children_need_inherited_style_update = !invalidation.is_none();
|
||||
if (needs_full_style_update || node.child_needs_style_update() || children_need_inherited_style_update || recompute_elements_depending_on_custom_properties) {
|
||||
// NB: When display changes to/from flex/grid/contents, children may need to be blockified or un-blockified.
|
||||
// This requires a full style recompute, not just inherited style update.
|
||||
bool children_need_full_style_recompute = node_invalidation.rebuild_layout_tree;
|
||||
if (needs_full_style_update || node.child_needs_style_update() || children_need_inherited_style_update || recompute_elements_depending_on_custom_properties || children_need_full_style_recompute) {
|
||||
if (node.is_element()) {
|
||||
if (auto shadow_root = static_cast<DOM::Element&>(node).shadow_root()) {
|
||||
if (needs_full_style_update || shadow_root->needs_style_update() || shadow_root->child_needs_style_update()) {
|
||||
auto subtree_invalidation = update_style_recursively(*shadow_root, style_computer, children_need_inherited_style_update, recompute_elements_depending_on_custom_properties);
|
||||
auto subtree_invalidation = update_style_recursively(*shadow_root, style_computer, children_need_inherited_style_update, recompute_elements_depending_on_custom_properties, children_need_full_style_recompute);
|
||||
if (!is_display_none)
|
||||
invalidation |= subtree_invalidation;
|
||||
}
|
||||
|
|
@ -1571,8 +1574,8 @@ void Document::update_layout(UpdateLayoutReason reason)
|
|||
}
|
||||
|
||||
node.for_each_child([&](auto& child) {
|
||||
if (needs_full_style_update || child.needs_style_update() || children_need_inherited_style_update || child.child_needs_style_update() || recompute_elements_depending_on_custom_properties) {
|
||||
auto subtree_invalidation = update_style_recursively(child, style_computer, children_need_inherited_style_update, recompute_elements_depending_on_custom_properties);
|
||||
if (needs_full_style_update || child.needs_style_update() || children_need_inherited_style_update || child.child_needs_style_update() || recompute_elements_depending_on_custom_properties || children_need_full_style_recompute) {
|
||||
auto subtree_invalidation = update_style_recursively(child, style_computer, children_need_inherited_style_update, recompute_elements_depending_on_custom_properties, children_need_full_style_recompute);
|
||||
if (!is_display_none)
|
||||
invalidation |= subtree_invalidation;
|
||||
}
|
||||
|
|
@ -1628,7 +1631,7 @@ void Document::update_style()
|
|||
|
||||
build_registered_properties_cache();
|
||||
|
||||
auto invalidation = update_style_recursively(*this, style_computer(), false, false);
|
||||
auto invalidation = update_style_recursively(*this, style_computer(), false, false, false);
|
||||
if (!invalidation.is_none())
|
||||
invalidate_display_list();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
Initial child display: inline
|
||||
Color after flex: rgb(0, 0, 0)
|
||||
Display after flex: block
|
||||
Display after block: inline
|
||||
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
|||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail Dynamic changes to `display` causing blockification of children are handled correctly
|
||||
1 Pass
|
||||
Pass Dynamic changes to `display` causing blockification of children are handled correctly
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="author" href="mailto:kling@ladybird.org">
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#container { display: block; }
|
||||
</style>
|
||||
<div id="container">
|
||||
<span id="child">test</span>
|
||||
</div>
|
||||
<script>
|
||||
test(() => {
|
||||
const container = document.getElementById("container");
|
||||
const child = document.getElementById("child");
|
||||
|
||||
// Initially, span should be inline
|
||||
println(`Initial child display: ${getComputedStyle(child).display}`);
|
||||
|
||||
// Change parent to flex - child should get blockified
|
||||
container.style.display = "flex";
|
||||
|
||||
// Query color first (doesn't need layout) to trigger only update_style()
|
||||
println(`Color after flex: ${getComputedStyle(child).color}`);
|
||||
println(`Display after flex: ${getComputedStyle(child).display}`);
|
||||
|
||||
// Change parent back to block - child should un-blockify
|
||||
container.style.display = "block";
|
||||
println(`Display after block: ${getComputedStyle(child).display}`);
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in a new issue