From c856f562899dcb408eeb5e34ccbfe4badc577068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Wed, 9 Sep 2026 21:45:18 +0200 Subject: [PATCH] Materialize inline styles where layout reads them Visibility probes no longer decide whether an element's style attribute gets parsed into a CSSStyleProperties object. The three layout readers (getElementAxis, positionStyle, horizontalPosition) create it on demand through Element.inlineStyle, and StyleManager only ever folds the attribute text. That removes the scan/materialize mode threaded through every probe, and a JS layout read now only materializes the elements whose inline style it actually reads. --- src/SemanticTree.zig | 4 +- src/browser/Frame.zig | 2 +- src/browser/RenderTree.zig | 2 +- src/browser/StyleManager.zig | 135 ++++++------------ src/browser/dump.zig | 2 +- src/browser/interactive.zig | 6 +- src/browser/links.zig | 2 +- src/browser/webapi/Document.zig | 2 +- src/browser/webapi/Element.zig | 66 +++++---- src/browser/webapi/ResizeObserver.zig | 2 +- .../webapi/css/CSSStyleDeclaration.zig | 4 +- src/browser/webapi/element/Html.zig | 2 +- src/server/cdp/AXNode.zig | 2 +- 13 files changed, 104 insertions(+), 127 deletions(-) diff --git a/src/SemanticTree.zig b/src/SemanticTree.zig index efbd0f593..0953ff859 100644 --- a/src/SemanticTree.zig +++ b/src/SemanticTree.zig @@ -130,9 +130,9 @@ fn walk( // Hidden subtrees are never entered, so below the root only the // element's own display matters. const hidden = if (current_depth == 0) - !el.isVisible(self.frame, .scan) + !el.isVisible(self.frame) else - self.frame._style_manager.hasDisplayNone(el, .scan); + self.frame._style_manager.hasDisplayNone(el); if (hidden) { return; } diff --git a/src/browser/Frame.zig b/src/browser/Frame.zig index 41acc3d86..0114c5ebc 100644 --- a/src/browser/Frame.zig +++ b/src/browser/Frame.zig @@ -3121,7 +3121,7 @@ pub fn attributeRemove(self: *Frame, element: *Element, name: String, old_value: } fn styleAttributeChanged(self: *Frame, element: *Element, value: ?[]const u8) void { - const style = element.getStyle(self) orelse return; + const style = element.existingStyle(self) orelse return; style.asCSSStyleDeclaration().styleAttributeChanged(value, self) catch |err| { log.err(.frame, "style attribute reparse", .{ .err = err, .type = self._type, .url = self.url }); }; diff --git a/src/browser/RenderTree.zig b/src/browser/RenderTree.zig index d9f2981b8..f85241347 100644 --- a/src/browser/RenderTree.zig +++ b/src/browser/RenderTree.zig @@ -152,7 +152,7 @@ fn visibleDisplay(el: *Element, frame: *Frame) ?StyleManager.Display { if (tag.isMetadata() or tag == .svg) { return null; } - const d = frame._style_manager.display(el, .scan); + const d = frame._style_manager.display(el); if (d == .none) { return null; } diff --git a/src/browser/StyleManager.zig b/src/browser/StyleManager.zig index 95123c69c..07ca8a45a 100644 --- a/src/browser/StyleManager.zig +++ b/src/browser/StyleManager.zig @@ -587,30 +587,30 @@ const Probe = enum { hidden, visibility, pointer_events }; const Memo = std.AutoHashMapUnmanaged(*Element, Props); -pub fn isHidden(self: *StyleManager, el: *Element, options: CheckVisibilityOptions, comptime access: InlineAccess) bool { +pub fn isHidden(self: *StyleManager, el: *Element, options: CheckVisibilityOptions) bool { self.rebuildIfDirty() catch return false; - return self.anyInChain(el, access, .hidden, options); + return self.anyInChain(el, .hidden, options); } /// Computed display:none for a single element (own property, no ancestor walk). /// Honors the UA stylesheet rules per HTML Rendering §15.3.1 "Hidden elements". -pub fn hasDisplayNone(self: *StyleManager, el: *Element, comptime access: InlineAccess) bool { - return self.display(el, access) == .none; +pub fn hasDisplayNone(self: *StyleManager, el: *Element) bool { + return self.display(el) == .none; } /// Own property, no ancestor walk; honors the UA hidden-element rules. -pub fn display(self: *StyleManager, el: *Element, comptime access: InlineAccess) Display { +pub fn display(self: *StyleManager, el: *Element) Display { self.rebuildIfDirty() catch return .other; - return self.ownProps(el, access).display; + return self.ownProps(el).display; } /// Computed display:none coming only from inline style or an author stylesheet /// rule — the UA stylesheet's hidden elements (,