LibWeb: Always do parent document layout updates before updating style

We were doing this manually within `Document::update_layout()` and
`CSSStyleProperties::get_direct_property()` but we should do it for all
callers of `Document::update_style()`
This commit is contained in:
Callum Law 2025-10-29 22:39:24 +13:00 committed by Alexander Kalenik
parent b5db79be6d
commit 56e2ac8a9d
Notes: github-actions[bot] 2025-11-02 22:55:42 +00:00
5 changed files with 38 additions and 13 deletions

View file

@ -517,14 +517,6 @@ Optional<StyleProperty> CSSStyleProperties::get_direct_property(PropertyNameAndI
Layout::NodeWithStyle* layout_node = abstract_element.layout_node();
// Pending changes to an ancestor document's layout can affect an element's computed style e.g. an IFrame's
// width being changed can affect media query evaluation and the value of the `vw` unit.
// FIXME: This is likely overkill and can be optimized
for (auto const& navigable : abstract_element.document().ancestor_navigables()) {
if (navigable->active_document())
navigable->active_document()->update_layout(DOM::UpdateLayoutReason::ResolvedCSSStyleDeclarationProperty);
}
// FIXME: Be smarter about updating layout if there's no layout node.
// We may legitimately have no layout node if we're not visible, but this protects against situations
// where we're requesting the computed style before layout has happened.

View file

@ -1342,11 +1342,6 @@ void Document::update_layout(UpdateLayoutReason reason)
if (!navigable || navigable->active_document() != this)
return;
// NOTE: If our parent document needs a relayout, we must do that *first*.
// This is necessary as the parent layout may cause our viewport to change.
if (navigable->container() && &navigable->container()->document() != this)
navigable->container()->document().update_layout(reason);
update_style();
if (m_layout_root && !m_layout_root->needs_layout_update())
@ -1557,6 +1552,11 @@ void Document::update_layout(UpdateLayoutReason reason)
void Document::update_style()
{
// NOTE: If our parent document needs a relayout, we must do that *first*. This is required as it may cause the
// viewport to change which will can affect media query evaluation and the value of the `vw` unit.
if (navigable()->container() && &navigable()->container()->document() != this)
navigable()->container()->document().update_layout(UpdateLayoutReason::ChildDocumentStyleUpdate);
if (!browsing_context())
return;

View file

@ -78,6 +78,7 @@ enum class InvalidateLayoutTreeReason {
X(CanvasRenderingContext2DSetStrokeStyle) \
X(CanvasSetFillStyle) \
X(CursorBlinkTimer) \
X(ChildDocumentStyleUpdate) \
X(Debugging) \
X(DocumentElementFromPoint) \
X(DocumentElementsFromPoint) \

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<iframe
width="499"
id="frame"
srcdoc="
<!DOCTYPE html>
<html>
<style>
@keyframes foo {}
@media (width >= 500px) {
#bar {
animation: foo 1s;
}
}
</style>
<div id='bar'></div>
</html>
"
></iframe>
<script src="../include.js"></script>
<script>
promiseTest(async () => {
await new Promise(resolve => window.addEventListener("load", resolve));
frame.width = "500";
println(frame.contentDocument.getAnimations().length);
});
</script>
</html>