mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
LibWeb: Implement partial SVG relayout
Previously, any SVG geometry attribute change would mark the entire document layout tree as dirty, triggering a full layout pass even though only the SVG subtree was affected. This made SVG geometry animations unnecessarily expensive. Fix this by stopping `needs_layout_update` propagation at the SVGSVGBox boundary and tracking dirty SVG roots separately on the Document. When `update_layout()` finds that only SVG roots need relayout (and the document layout root is clean), it runs SVGFormattingContext on each dirty SVG root in a fresh LayoutState and commits the results directly, bypassing the full document layout pass entirely. This results in a substantial performance improvement on pages with animated SVGs, such as https://www.cloudflare.com/, https://www.duolingo.com/, and our GC graph explorer page.
This commit is contained in:
committed by
Alexander Kalenik
parent
f051bc45fc
commit
abecc746d7
Notes:
github-actions[bot]
2026-02-09 02:04:14 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/abecc746d7c Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7816
@@ -30,6 +30,7 @@
|
||||
#include <LibWeb/Layout/FormattingContext.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Layout/SVGSVGBox.h>
|
||||
#include <LibWeb/Layout/TableWrapper.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
@@ -1479,6 +1480,21 @@ void Node::set_needs_layout_update(DOM::SetNeedsLayoutReason reason)
|
||||
if (ancestor->m_needs_layout_update)
|
||||
break;
|
||||
ancestor->m_needs_layout_update = true;
|
||||
if (auto* svg_box = as_if<SVGSVGBox>(ancestor)) {
|
||||
// Absolutely positioned elements are laid out by the formatting context (FC) of their
|
||||
// containing block, not by the FC of their parent. When an abspos element lives inside
|
||||
// an SVG subtree (e.g. inside <foreignObject>) but its containing block is an ancestor
|
||||
// outside that subtree, partial SVG relayout cannot lay it out: only the SVGFormattingContext
|
||||
// runs, while the containing block's FC (which is responsible for the abspos) does not.
|
||||
// In this case we must not stop propagation here — letting needs_layout_update reach the
|
||||
// layout root ensures update_layout() takes the full layout path instead.
|
||||
if (is_absolutely_positioned()) {
|
||||
if (auto cb = containing_block(); cb && !svg_box->is_inclusive_ancestor_of(*cb))
|
||||
continue;
|
||||
}
|
||||
document().mark_svg_root_as_needing_relayout(*svg_box);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset intrinsic size caches for ancestors up to abspos or SVG root boundary.
|
||||
|
||||
Reference in New Issue
Block a user