mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-30 17:25:58 -04:00
webapi: derive SVG prototype chains
This commit is contained in:
committed by
Karl Seguin
parent
6f82bdcd51
commit
7140cfab5a
@@ -354,49 +354,44 @@ pub fn htmlMediaElement(self: *Factory, child: anytype) !*@TypeOf(child) {
|
||||
}
|
||||
|
||||
pub fn svgElement(self: *Factory, tag_name: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ EventTarget, Node, Element, Element.Svg, @TypeOf(child) },
|
||||
).allocate(self._slab.allocator());
|
||||
const types = comptime svgPrototypeTypes(@TypeOf(child));
|
||||
const chain = try PrototypeChain(types).allocate(self._slab.allocator());
|
||||
|
||||
try self.setSvgChainBase(chain, tag_name);
|
||||
chain.setLeaf(4, child);
|
||||
return chain.get(4);
|
||||
}
|
||||
|
||||
pub fn svgGraphicsElement(self: *Factory, tag_name: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ EventTarget, Node, Element, Element.Svg, Element.Svg.Graphics, @TypeOf(child) },
|
||||
).allocate(self._slab.allocator());
|
||||
|
||||
try self.setSvgChainBase(chain, tag_name);
|
||||
chain.setMiddle(4, Element.Svg.Graphics.Type);
|
||||
chain.setLeaf(5, child);
|
||||
return chain.get(5);
|
||||
}
|
||||
|
||||
pub fn svgGeometryElement(self: *Factory, tag_name: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ EventTarget, Node, Element, Element.Svg, Element.Svg.Graphics, Element.Svg.Graphics.Geometry, @TypeOf(child) },
|
||||
).allocate(self._slab.allocator());
|
||||
|
||||
try self.setSvgChainBase(chain, tag_name);
|
||||
chain.setMiddle(4, Element.Svg.Graphics.Type);
|
||||
chain.setMiddle(5, Element.Svg.Graphics.Geometry.Type);
|
||||
chain.setLeaf(6, child);
|
||||
return chain.get(6);
|
||||
}
|
||||
|
||||
fn setSvgChainBase(self: *Factory, chain: anytype, tag_name: []const u8) !void {
|
||||
chain.setRoot(EventTarget.Type);
|
||||
chain.setMiddle(1, Node.Type);
|
||||
chain.setMiddle(2, Element.Type);
|
||||
inline for (1..types.len - 1) |i| {
|
||||
const T = types[i];
|
||||
if (T == Element.Svg) {
|
||||
chain.set(i, .{
|
||||
._proto = chain.get(i - 1),
|
||||
._tag_name = try String.init(self._arena, tag_name, .{}),
|
||||
._type = unionInit(Element.Svg.Type, chain.get(i + 1)),
|
||||
});
|
||||
} else {
|
||||
chain.setMiddle(i, T.Type);
|
||||
}
|
||||
}
|
||||
chain.setLeaf(types.len - 1, child);
|
||||
return chain.get(types.len - 1);
|
||||
}
|
||||
|
||||
// Manually set Element.Svg with the tag_name
|
||||
chain.set(3, .{
|
||||
._proto = chain.get(2),
|
||||
._tag_name = try String.init(self._arena, tag_name, .{}),
|
||||
._type = unionInit(Element.Svg.Type, chain.get(4)),
|
||||
});
|
||||
fn svgPrototypeTypes(comptime Child: type) []const type {
|
||||
comptime {
|
||||
var types: []const type = &[_]type{Child};
|
||||
var T = Child;
|
||||
|
||||
while (T != EventTarget) {
|
||||
if (!@hasField(T, "_proto")) {
|
||||
@compileError(@typeName(T) ++ " does not lead to EventTarget through _proto");
|
||||
}
|
||||
T = reflect.Struct(@FieldType(T, "_proto"));
|
||||
types = &[_]type{T} ++ types;
|
||||
}
|
||||
|
||||
if (types.len < 5 or types[3] != Element.Svg) {
|
||||
@compileError(@typeName(Child) ++ " is not an SVG prototype chain");
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xhrEventTarget(_: *const Factory, allocator: Allocator, child: anytype) !*@TypeOf(child) {
|
||||
|
||||
@@ -890,37 +890,37 @@ pub fn createElementNS(frame: *Frame, namespace: Element.Namespace, name: []cons
|
||||
// SVG tag names are case-sensitive; no lowering before matching.
|
||||
switch (name.len) {
|
||||
1 => switch (name[0]) {
|
||||
'g' => return createSvgGraphicsElementT(frame, Graphics.G, name, attribute_iterator),
|
||||
'a' => return createSvgGraphicsElementT(frame, Graphics.A, name, attribute_iterator),
|
||||
'g' => return createSvgElementT(frame, Graphics.G, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
'a' => return createSvgElementT(frame, Graphics.A, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
3 => switch (@as(u24, @bitCast(name[0..3].*))) {
|
||||
asUint("svg") => return createSvgGraphicsElementT(frame, Graphics.Svg, name, attribute_iterator),
|
||||
asUint("use") => return createSvgGraphicsElementT(frame, Graphics.Use, name, attribute_iterator),
|
||||
asUint("svg") => return createSvgElementT(frame, Graphics.Svg, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
asUint("use") => return createSvgElementT(frame, Graphics.Use, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
4 => switch (@as(u32, @bitCast(name[0..4].*))) {
|
||||
asUint("defs") => return createSvgGraphicsElementT(frame, Graphics.Defs, name, attribute_iterator),
|
||||
asUint("rect") => return createSvgGeometryElementT(frame, Geometry.Rect, name, attribute_iterator),
|
||||
asUint("line") => return createSvgGeometryElementT(frame, Geometry.Line, name, attribute_iterator),
|
||||
asUint("path") => return createSvgGeometryElementT(frame, Geometry.Path, name, attribute_iterator),
|
||||
asUint("defs") => return createSvgElementT(frame, Graphics.Defs, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
asUint("rect") => return createSvgElementT(frame, Geometry.Rect, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
asUint("line") => return createSvgElementT(frame, Geometry.Line, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
asUint("path") => return createSvgElementT(frame, Geometry.Path, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
5 => switch (@as(u40, @bitCast(name[0..5].*))) {
|
||||
asUint("image") => return createSvgGraphicsElementT(frame, Graphics.Image, name, attribute_iterator),
|
||||
asUint("image") => return createSvgElementT(frame, Graphics.Image, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
6 => switch (@as(u48, @bitCast(name[0..6].*))) {
|
||||
asUint("circle") => return createSvgGeometryElementT(frame, Geometry.Circle, name, attribute_iterator),
|
||||
asUint("circle") => return createSvgElementT(frame, Geometry.Circle, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
7 => switch (@as(u56, @bitCast(name[0..7].*))) {
|
||||
asUint("ellipse") => return createSvgGeometryElementT(frame, Geometry.Ellipse, name, attribute_iterator),
|
||||
asUint("polygon") => return createSvgGeometryElementT(frame, Geometry.Polygon, name, attribute_iterator),
|
||||
asUint("ellipse") => return createSvgElementT(frame, Geometry.Ellipse, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
asUint("polygon") => return createSvgElementT(frame, Geometry.Polygon, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
8 => switch (@as(u64, @bitCast(name[0..8].*))) {
|
||||
asUint("polyline") => return createSvgGeometryElementT(frame, Geometry.Polyline, name, attribute_iterator),
|
||||
asUint("polyline") => return createSvgElementT(frame, Geometry.Polyline, name, attribute_iterator, .{ ._proto = undefined }),
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
@@ -970,16 +970,6 @@ fn createSvgElementT(frame: *Frame, comptime E: type, tag_name: []const u8, attr
|
||||
return initSvgElement(frame, svg_element_ptr.asElement(), attribute_iterator);
|
||||
}
|
||||
|
||||
fn createSvgGraphicsElementT(frame: *Frame, comptime E: type, tag_name: []const u8, attribute_iterator: anytype) !*Node {
|
||||
const svg_element_ptr = try frame._factory.svgGraphicsElement(tag_name, E{ ._proto = undefined });
|
||||
return initSvgElement(frame, svg_element_ptr.asElement(), attribute_iterator);
|
||||
}
|
||||
|
||||
fn createSvgGeometryElementT(frame: *Frame, comptime E: type, tag_name: []const u8, attribute_iterator: anytype) !*Node {
|
||||
const svg_element_ptr = try frame._factory.svgGeometryElement(tag_name, E{ ._proto = undefined });
|
||||
return initSvgElement(frame, svg_element_ptr.asElement(), attribute_iterator);
|
||||
}
|
||||
|
||||
fn initSvgElement(frame: *Frame, element: *Element, attribute_iterator: anytype) !*Node {
|
||||
element._namespace = .svg;
|
||||
element._attributes.normalize = false;
|
||||
|
||||
@@ -48,8 +48,10 @@
|
||||
testing.expectEqual(true, root instanceof SVGGraphicsElement);
|
||||
testing.expectEqual(true, root instanceof SVGElement);
|
||||
testing.expectEqual(true, root instanceof Element);
|
||||
testing.expectEqual(true, root instanceof Node);
|
||||
testing.expectEqual(false, root instanceof SVGGeometryElement);
|
||||
testing.expectEqual('svg', root.tagName);
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', root.namespaceURI);
|
||||
|
||||
const rect = $('#rect1');
|
||||
testing.expectEqual(true, rect instanceof SVGRectElement);
|
||||
@@ -75,8 +77,10 @@
|
||||
// Elements without a dedicated type stay generic, but are still SVGElement.
|
||||
const filter = $('#filter1');
|
||||
testing.expectEqual(true, filter instanceof SVGElement);
|
||||
testing.expectEqual(true, filter instanceof Element);
|
||||
testing.expectEqual(false, filter instanceof SVGGraphicsElement);
|
||||
testing.expectEqual('filter', filter.tagName);
|
||||
testing.expectEqual('http://www.w3.org/2000/svg', filter.namespaceURI);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -85,13 +89,20 @@
|
||||
const NS = 'http://www.w3.org/2000/svg';
|
||||
const rect = document.createElementNS(NS, 'rect');
|
||||
testing.expectEqual(true, rect instanceof SVGRectElement);
|
||||
testing.expectEqual(true, rect instanceof SVGGeometryElement);
|
||||
testing.expectEqual(true, rect instanceof SVGGraphicsElement);
|
||||
testing.expectEqual(true, rect instanceof SVGElement);
|
||||
testing.expectEqual(true, rect instanceof Element);
|
||||
testing.expectEqual('rect', rect.tagName);
|
||||
testing.expectEqual(NS, rect.namespaceURI);
|
||||
|
||||
// SVG tag names are case-sensitive: 'RECT' isn't a rect element.
|
||||
const notRect = document.createElementNS(NS, 'RECT');
|
||||
testing.expectEqual(false, notRect instanceof SVGRectElement);
|
||||
testing.expectEqual(true, notRect instanceof SVGElement);
|
||||
testing.expectEqual(true, notRect instanceof Element);
|
||||
testing.expectEqual('RECT', notRect.tagName);
|
||||
testing.expectEqual(NS, notRect.namespaceURI);
|
||||
|
||||
const svg = document.createElementNS(NS, 'svg');
|
||||
testing.expectEqual(true, svg instanceof SVGSVGElement);
|
||||
|
||||
Reference in New Issue
Block a user