LibWeb: Recompute inherited style even if there is no layout node

`recompute_inherited_style()` assumed that there is no work to do if the
element has no layout node. This however is not necessarily true.

In particular, the following can happen:
1. The element in question is a descendant at least two layers below an
   element that has `display: none`, i.e. with at least one other
   element between them. (If it is a direct child, a full style
   recomputation will be forced for unrelated reasons).
2. TreeBuilder decides to skip creating layout nodes for the `display:
   none` element and all its descendants.
3. Due to some change on the ancestor (e.g. class added, id changed),
   the value of a property that can be inherited changes on the
   ancestor.
4. The property value of the descendant now also needs to change.

In that scenario, we won't compute the entire style of the descendant,
since that already happened. But we do need to update its inherited
properties because the old ones are now stale. At that point we still
don't have a layout node for the element since it will only be created
after this style update.

Instead of skipping the update for inherited properties, simply allow
`recompute_inherited_style()` to run even in absence of a layout node.
And then apply the style to the layout node only if one exists. If none
exists, the style will be applied later if and when a corresponding
layout node is created.

This partially fixes the blank main navigation menus on
https://bleepingcomputer.com.
This commit is contained in:
InvalidUsernameException 2026-04-21 16:56:37 +02:00 committed by Jelle Raaijmakers
parent 059a5a245a
commit 67e3b2d446
2 changed files with 5 additions and 6 deletions

View file

@ -1025,9 +1025,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style(bool& did_cha
CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
{
auto computed_properties = this->computed_properties();
// NB: We use unsafe_layout_node() because we're in the middle of style recalculation
// and layout is inherently stale while recomputing inherited styles.
if (!m_cascaded_properties || !computed_properties || !unsafe_layout_node())
if (!m_cascaded_properties || !computed_properties)
return {};
CSS::RequiredInvalidationAfterStyleChange invalidation;
@ -1090,7 +1088,8 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
// NB: unsafe_layout_node() because we're applying recomputed inherited styles during
// style recalculation, before layout has been updated.
unsafe_layout_node()->apply_style(*computed_properties);
if (unsafe_layout_node())
unsafe_layout_node()->apply_style(*computed_properties);
if (invalidation.repaint)
set_needs_repaint();
return invalidation;

View file

@ -1,4 +1,4 @@
Visibility before: hidden
Color before: rgb(255, 0, 0)
Visibility after: hidden
Color after: rgb(255, 0, 0)
Visibility after: visible
Color after: rgb(0, 128, 0)