mem: remove _proto field from most Node types

Continues the work started in https://github.com/lightpanda-io/browser/pull/3070

Removes the _proto field from intermediary (non-leaf) elements and uses the
relative positioning from the contiguous allocation. With the work done in
previous commit, this is pretty mechanical.

This essentially saves 8 bytes per type. Pretty small, but now Node->* is
consistently designed 1 way. Empty leaf nodes are still an issue, and the _proto
remains in them (for now). It's an issue because, if it's truly empty, the leaf
can have the same address as the parent or a sibling. This is something we
used to have problems with (hence some types have a _pad: bool). Solvable, but
separately.
This commit is contained in:
Karl Seguin
2026-07-31 15:31:31 +08:00
parent 392bb4c772
commit c52cba3858
81 changed files with 143 additions and 119 deletions

View File

@@ -485,11 +485,12 @@ pub fn svgElement(self: *Factory, tag_name: []const u8, child: anytype) !*@TypeO
inline for (1..types.len - 1) |i| {
const T = types[i];
if (T == Element.Svg) {
chain.set(i, .{
._proto = chain.get(i - 1),
const svg_ptr = chain.get(i);
svg_ptr.* = .{
._tag_name = try String.init(self._arena, tag_name, .{}),
._type = unionInit(Element.Svg.Type, chain.get(i + 1)),
});
};
setProto(svg_ptr, chain.get(i - 1));
} else {
chain.setMiddle(i, T.Type);
}

View File

@@ -404,7 +404,6 @@ pub fn createElementNS(self: *Document, namespace: ?[]const u8, name: []const u8
pub fn createAttribute(_: *const Document, name: String.Global, frame: *Frame) !?*Element.Attribute {
try Element.Attribute.validateAttributeName(name.str);
return frame._factory.node(Element.Attribute{
._proto = undefined,
._name = name.str,
._value = String.empty,
._element = null,
@@ -418,7 +417,6 @@ pub fn createAttributeNS(_: *const Document, namespace: []const u8, name: String
try Element.Attribute.validateAttributeName(name.str);
return frame._factory.node(Element.Attribute{
._proto = undefined,
._name = name.str,
._value = String.empty,
._element = null,

View File

@@ -1211,7 +1211,7 @@ pub fn cloneNode(self: *Node, deep_: ?bool, frame: *Frame) CloneError!*Node {
.document_fragment => |frag| return frag.cloneFragment(deep, frame),
.attribute => |attr| {
const cloned = attr.clone(frame) catch return error.CloneError;
return cloned._proto;
return cloned.asNode();
},
}
}

View File

@@ -21,6 +21,7 @@ const lp = @import("lightpanda");
const js = @import("../../js/js.zig");
const Frame = @import("../../Frame.zig");
const Factory = @import("../../Factory.zig");
const Node = @import("../Node.zig");
const Element = @import("../Element.zig");
@@ -43,10 +44,14 @@ pub const Attribute = @This();
pub const Proto = Node;
_proto: *Node,
_name: String,
_value: String,
_element: ?*Element,
_proto_canary: if (IS_DEBUG) *Node else void = undefined,
pub fn asNode(self: *Attribute) *Node {
return Factory.protoOf(self);
}
pub fn format(self: *const Attribute, writer: *std.Io.Writer) !void {
return formatAttribute(self._name.str(), self._value.str(), writer);
@@ -87,7 +92,6 @@ pub fn isEqualNode(self: *const Attribute, other: *const Attribute) bool {
pub fn clone(self: *const Attribute, frame: *Frame) !*Attribute {
return frame._factory.node(Attribute{
._proto = undefined,
._element = self._element,
._name = self._name,
._value = self._value,
@@ -463,7 +467,6 @@ pub const List = struct {
pub fn toAttribute(self: *const Entry, element: ?*Element, frame: *Frame) !*Attribute {
return frame._factory.node(Attribute{
._proto = undefined,
._element = element,
// The entry's bytes outlive the entry itself, so the
// Attribute can wrap them without duping.

View File

@@ -18,17 +18,17 @@
const std = @import("std");
const lp = @import("lightpanda");
const js = @import("../../js/js.zig");
const reflect = @import("../../reflect.zig");
const global_event_handlers = @import("../global_event_handlers.zig");
const GlobalEventHandler = global_event_handlers.Handler;
const Factory = @import("../../Factory.zig");
const Frame = @import("../../Frame.zig");
const Node = @import("../Node.zig");
const Element = @import("../Element.zig");
const popover = @import("popover.zig");
const global_event_handlers = @import("../global_event_handlers.zig");
const popover = @import("popover.zig");
pub const Anchor = @import("html/Anchor.zig");
pub const Area = @import("html/Area.zig");
pub const Base = @import("html/Base.zig");
@@ -100,13 +100,14 @@ pub const Unknown = @import("html/Unknown.zig");
const log = lp.log;
const IS_DEBUG = @import("builtin").mode == .Debug;
const GlobalEventHandler = global_event_handlers.Handler;
const HtmlElement = @This();
pub const Proto = Element;
_type: Type,
_proto: *Element,
_proto_canary: if (IS_DEBUG) *Element else void = undefined,
// Special constructor for custom elements (autonomous, `extends HTMLElement`).
// Two paths:
@@ -216,11 +217,11 @@ pub fn is(self: *HtmlElement, comptime T: type) ?*T {
}
pub fn asElement(self: *HtmlElement) *Element {
return self._proto;
return Factory.protoOf(self);
}
pub fn asNode(self: *HtmlElement) *Node {
return self._proto.asNode();
return self.asElement().asNode();
}
pub fn asEventTarget(self: *HtmlElement) *@import("../EventTarget.zig") {

View File

@@ -23,6 +23,7 @@ const Frame = @import("../../Frame.zig");
const Node = @import("../Node.zig");
const Element = @import("../Element.zig");
const Factory = @import("../../Factory.zig");
const AnimatedString = @import("../svg/AnimatedString.zig");
pub const Generic = @import("svg/Generic.zig");
pub const Graphics = @import("svg/Graphics.zig");
@@ -39,12 +40,14 @@ pub const Stop = @import("svg/Stop.zig");
const String = lp.String;
const IS_DEBUG = @import("builtin").mode == .Debug;
const Svg = @This();
pub const Proto = Element;
_type: Type,
_proto: *Element,
_tag_name: String, // Svg elements are case-preserving
_proto_canary: if (IS_DEBUG) *Element else void = undefined,
pub const Type = union(enum) {
graphics: *Graphics,
@@ -110,7 +113,7 @@ pub fn getTag(self: *const Svg) Element.Tag {
}
pub fn asElement(self: *Svg) *Element {
return self._proto;
return Factory.protoOf(self);
}
pub fn asNode(self: *Svg) *Node {
return self.asElement().asNode();

View File

@@ -31,10 +31,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Anchor) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Anchor) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Anchor) *Node {
return self.asElement().asNode();

View File

@@ -31,10 +31,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Area) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Area) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Area) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *BR) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *BR) *Node {
return self.asElement().asNode();

View File

@@ -13,7 +13,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Base) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Base) *Node {
return self.asElement().asNode();

View File

@@ -34,7 +34,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Body) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Body) *Node {
return self.asElement().asNode();

View File

@@ -40,10 +40,10 @@ _validity: ?*ValidityState = null,
_popover_target: ?*Element = null,
pub fn asElement(self: *Button) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Button) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Button) *Node {
return self.asElement().asNode();

View File

@@ -36,10 +36,10 @@ _proto: *HtmlElement,
_cached: ?DrawingContext = null,
pub fn asElement(self: *Canvas) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Canvas) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Canvas) *Node {
return self.asElement().asNode();

View File

@@ -42,7 +42,7 @@ _connected_callback_invoked: bool = false,
_disconnected_callback_invoked: bool = false,
pub fn asElement(self: *Custom) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Custom) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *DList) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *DList) *Node {
return self.asElement().asNode();

View File

@@ -30,7 +30,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Data) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Data) *Node {

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *DataList) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *DataList) *Node {
return self.asElement().asNode();

View File

@@ -12,10 +12,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Details) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Details) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Details) *Node {
return self.asElement().asNode();

View File

@@ -13,10 +13,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Dialog) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Dialog) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Dialog) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Directory) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Directory) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Div) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Div) *Node {
return self.asElement().asNode();

View File

@@ -28,10 +28,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Embed) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Embed) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Embed) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *FieldSet) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *FieldSet) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Font) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Font) *Node {
return self.asElement().asNode();

View File

@@ -47,10 +47,10 @@ pub fn asHtmlElement(self: *Form) *HtmlElement {
return self._proto;
}
fn asConstElement(self: *const Form) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asElement(self: *Form) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Form) *Node {
return self.asElement().asNode();

View File

@@ -16,7 +16,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *FrameSet) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *FrameSet) *Node {
return self.asElement().asNode();

View File

@@ -34,7 +34,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *Generic) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Generic) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *HR) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *HR) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Head) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Head) *Node {
return self.asElement().asNode();

View File

@@ -34,7 +34,7 @@ _tag_name: String,
_tag: Element.Tag,
pub fn asElement(self: *Heading) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Heading) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Html) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Html) *Node {
return self.asElement().asNode();

View File

@@ -38,7 +38,7 @@ _executed: bool = false,
_window: ?*Window = null,
pub fn asElement(self: *IFrame) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *IFrame) *Node {
return self.asElement().asNode();

View File

@@ -26,10 +26,10 @@ pub fn constructor(w_: ?u32, h_: ?u32, frame: *Frame) !*Image {
}
pub fn asElement(self: *Image) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Image) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Image) *Node {
return self.asElement().asNode();

View File

@@ -122,10 +122,10 @@ fn dispatchInputEvent(self: *Input, data: ?[]const u8, input_type: []const u8, f
}
pub fn asElement(self: *Input) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Input) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Input) *Node {
return self.asElement().asNode();

View File

@@ -29,7 +29,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *LI) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *LI) *Node {
return self.asElement().asNode();

View File

@@ -13,7 +13,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Label) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Label) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Legend) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Legend) *Node {
return self.asElement().asNode();

View File

@@ -38,10 +38,10 @@ _proto: *HtmlElement,
_sheet: ?*@import("../../css/CSSStyleSheet.zig") = null,
pub fn asElement(self: *Link) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Link) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Link) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Map) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Map) *Node {
return self.asElement().asNode();

View File

@@ -13,7 +13,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Marquee) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Marquee) *Node {
return self.asElement().asNode();

View File

@@ -22,12 +22,15 @@ const Frame = @import("../../../Frame.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const HtmlElement = @import("../Html.zig");
const Event = @import("../../Event.zig");
pub const Audio = @import("Audio.zig");
pub const Video = @import("Video.zig");
const MediaError = @import("../../media/MediaError.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const Media = @This();
pub const Proto = HtmlElement;
@@ -54,7 +57,7 @@ pub const Type = union(enum) {
};
_type: Type,
_proto: *HtmlElement,
_proto_canary: if (IS_DEBUG) *HtmlElement else void = undefined,
_paused: bool = true,
_current_time: f64 = 0,
_volume: f64 = 1.0,
@@ -65,10 +68,10 @@ _network_state: NetworkState = .NETWORK_EMPTY,
_error: ?*MediaError = null,
pub fn asElement(self: *Media) *Element {
return self._proto._proto;
return Factory.protoOf(self).asElement();
}
pub fn asConstElement(self: *const Media) *const Element {
return self._proto._proto;
return Factory.protoOf(@constCast(self)).asElement();
}
pub fn asNode(self: *Media) *Node {
return self.asElement().asNode();

View File

@@ -32,7 +32,7 @@ const MetaElement = Meta;
_proto: *HtmlElement,
pub fn asElement(self: *Meta) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Meta) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Meter) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Meter) *Node {
return self.asElement().asNode();

View File

@@ -16,7 +16,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *Mod) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Mod) *Node {
return self.asElement().asNode();

View File

@@ -29,7 +29,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *OL) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *OL) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Object) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Object) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *OptGroup) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *OptGroup) *Node {
return self.asElement().asNode();

View File

@@ -39,10 +39,10 @@ _default_selected: bool = false,
_disabled: bool = false,
pub fn asElement(self: *Option) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Option) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Option) *Node {
return self.asElement().asNode();

View File

@@ -32,7 +32,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Output) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Output) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Paragraph) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Paragraph) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Param) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Param) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Picture) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Picture) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Pre) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Pre) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Progress) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Progress) *Node {
return self.asElement().asNode();

View File

@@ -17,7 +17,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *Quote) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Quote) *Node {
return self.asElement().asNode();

View File

@@ -37,11 +37,11 @@ _executed: bool = false,
_force_async: bool = true,
pub fn asElement(self: *Script) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Script) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Script) *Node {

View File

@@ -38,10 +38,10 @@ _custom_validity: ?[]const u8 = null,
_validity: ?*ValidityState = null,
pub fn asElement(self: *Select) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Select) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Select) *Node {
return self.asElement().asNode();

View File

@@ -20,11 +20,11 @@ _assigned: std.ArrayList(*Node) = .empty,
_manually_assigned: std.ArrayList(*Node) = .empty,
pub fn asElement(self: *Slot) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Slot) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Slot) *Node {

View File

@@ -12,10 +12,10 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Source) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Source) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Source) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Span) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Span) *Node {
return self.asElement().asNode();

View File

@@ -31,10 +31,10 @@ _proto: *HtmlElement,
_sheet: ?*CSSStyleSheet = null,
pub fn asElement(self: *Style) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Style) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Style) *Node {
return self.asElement().asNode();

View File

@@ -12,7 +12,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Table) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Table) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *TableCaption) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TableCaption) *Node {
return self.asElement().asNode();

View File

@@ -18,7 +18,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *TableCell) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TableCell) *Node {
return self.asElement().asNode();

View File

@@ -16,7 +16,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *TableCol) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TableCol) *Node {
return self.asElement().asNode();

View File

@@ -12,7 +12,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *TableRow) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TableRow) *Node {
return self.asElement().asNode();

View File

@@ -18,7 +18,7 @@ _tag: Element.Tag,
_proto: *HtmlElement,
pub fn asElement(self: *TableSection) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TableSection) *Node {
return self.asElement().asNode();

View File

@@ -38,11 +38,11 @@ _proto: *HtmlElement,
_content: *DocumentFragment,
pub fn asElement(self: *Template) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const Template) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Template) *Node {
return self.asElement().asNode();

View File

@@ -67,10 +67,10 @@ fn dispatchInputEvent(self: *TextArea, data: ?[]const u8, input_type: []const u8
}
pub fn asElement(self: *TextArea) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asConstElement(self: *const TextArea) *const Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *TextArea) *Node {
return self.asElement().asNode();

View File

@@ -11,7 +11,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Time) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Time) *Node {
return self.asElement().asNode();

View File

@@ -10,7 +10,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *Title) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Title) *Node {
return self.asElement().asNode();

View File

@@ -38,7 +38,7 @@ _ready_state: ReadyState,
const ReadyState = enum(u8) { none, loading, loaded, @"error" };
pub fn asElement(self: *Track) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Track) *Node {
return self.asElement().asNode();

View File

@@ -27,7 +27,7 @@ pub const Proto = HtmlElement;
_proto: *HtmlElement,
pub fn asElement(self: *UL) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *UL) *Node {
return self.asElement().asNode();

View File

@@ -33,7 +33,7 @@ _proto: *HtmlElement,
_tag_name: String,
pub fn asElement(self: *Unknown) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Unknown) *Node {
return self.asElement().asNode();

View File

@@ -30,7 +30,7 @@ _proto: *Svg,
_tag: Element.Tag,
pub fn asElement(self: *Generic) *Element {
return self._proto._proto;
return self._proto.asElement();
}
pub fn asNode(self: *Generic) *Node {
return self.asElement().asNode();

View File

@@ -23,6 +23,7 @@ const Frame = @import("../../../Frame.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const DOMPoint = @import("../../DOMPoint.zig");
const Graphics = @import("Graphics.zig");
@@ -37,11 +38,13 @@ pub const Path = @import("Path.zig");
pub const Polygon = @import("Polygon.zig");
pub const Polyline = @import("Polyline.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const Geometry = @This();
pub const Proto = Graphics;
_proto: *Graphics,
_type: Type,
_proto_canary: if (IS_DEBUG) *Graphics else void = undefined,
pub const Type = union(enum) {
rect: *Rect,
@@ -65,7 +68,7 @@ pub fn is(self: *Geometry, comptime T: type) ?*T {
}
pub fn asElement(self: *Geometry) *Element {
return self._proto.asElement();
return Factory.protoOf(self).asElement();
}
pub fn asNode(self: *Geometry) *Node {
return self.asElement().asNode();

View File

@@ -21,6 +21,7 @@ const Frame = @import("../../../Frame.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const AnimatedEnumeration = @import("../../svg/AnimatedEnumeration.zig");
const AnimatedString = @import("../../svg/AnimatedString.zig");
@@ -31,11 +32,13 @@ const Svg = @import("../Svg.zig");
pub const LinearGradient = @import("LinearGradient.zig");
pub const RadialGradient = @import("RadialGradient.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const GradientElement = @This();
pub const Proto = Svg;
_proto: *Svg,
_type: Type,
_proto_canary: if (IS_DEBUG) *Svg else void = undefined,
pub const Type = union(enum) {
linear: *LinearGradient,
@@ -54,7 +57,7 @@ pub fn is(self: *GradientElement, comptime T: type) ?*T {
}
pub fn asElement(self: *GradientElement) *Element {
return self._proto.asElement();
return Factory.protoOf(self).asElement();
}
pub fn asNode(self: *GradientElement) *Node {
return self.asElement().asNode();

View File

@@ -22,6 +22,7 @@ const js = @import("../../../js/js.zig");
const Frame = @import("../../../Frame.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const DOMRect = @import("../../DOMRect.zig");
const DOMMatrixReadOnly = @import("../../DOMMatrixReadOnly.zig");
const SvgElement = @import("../Svg.zig");
@@ -41,11 +42,13 @@ pub const ForeignObject = @import("ForeignObject.zig");
pub const TextContent = @import("TextContent.zig");
pub const Geometry = @import("Geometry.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const Graphics = @This();
pub const Proto = SvgElement;
_proto: *SvgElement,
_type: Type,
_proto_canary: if (IS_DEBUG) *SvgElement else void = undefined,
pub const Type = union(enum) {
svg: *Svg,
@@ -79,7 +82,7 @@ pub fn is(self: *Graphics, comptime T: type) ?*T {
}
pub fn asElement(self: *Graphics) *Element {
return self._proto.asElement();
return Factory.protoOf(self).asElement();
}
pub fn asNode(self: *Graphics) *Node {
return self.asElement().asNode();

View File

@@ -22,6 +22,7 @@ const text_measure = @import("../../../text_measure.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const AnimatedEnumeration = @import("../../svg/AnimatedEnumeration.zig");
const AnimatedLength = @import("../../svg/AnimatedLength.zig");
@@ -31,11 +32,13 @@ const Graphics = @import("Graphics.zig");
pub const TextPositioning = @import("TextPositioning.zig");
pub const TextPath = @import("TextPath.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const TextContent = @This();
pub const Proto = Graphics;
_proto: *Graphics,
_type: Type,
_proto_canary: if (IS_DEBUG) *Graphics else void = undefined,
pub const Type = union(enum) {
positioning: *TextPositioning,
@@ -53,7 +56,7 @@ pub fn is(self: *TextContent, comptime T: type) ?*T {
}
pub fn asElement(self: *TextContent) *Element {
return self._proto.asElement();
return Factory.protoOf(self).asElement();
}
pub fn asNode(self: *TextContent) *Node {
return self.asElement().asNode();

View File

@@ -20,17 +20,20 @@ const js = @import("../../../js/js.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const Factory = @import("../../../Factory.zig");
const TextContent = @import("TextContent.zig");
pub const Text = @import("Text.zig");
pub const TSpan = @import("TSpan.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const TextPositioning = @This();
pub const Proto = TextContent;
_proto: *TextContent,
_type: Type,
_proto_canary: if (IS_DEBUG) *TextContent else void = undefined,
pub const Type = union(enum) {
text: *Text,
@@ -47,7 +50,7 @@ pub fn is(self: *TextPositioning, comptime T: type) ?*T {
}
pub fn asElement(self: *TextPositioning) *Element {
return self._proto.asElement();
return Factory.protoOf(self).asElement();
}
pub fn asNode(self: *TextPositioning) *Node {
return self.asElement().asNode();

View File

@@ -534,7 +534,7 @@ fn appendAttributes(self: *Evaluator, node: *Node, out: *std.ArrayList(*Node)) E
// (Capybara/Selenium polling) reuse the same *Attribute instead
// of leaking fresh ones into page-lifetime storage on every call.
const attribute = try el._attributes.getOrCreateAttribute(entry, el, self.frame);
try out.append(self.arena, attribute._proto);
try out.append(self.arena, attribute.asNode());
}
}