diff --git a/src/browser/dom/character_data.zig b/src/browser/dom/character_data.zig index 871b77ec..774572a3 100644 --- a/src/browser/dom/character_data.zig +++ b/src/browser/dom/character_data.zig @@ -24,7 +24,8 @@ const Node = @import("node.zig").Node; const Comment = @import("comment.zig").Comment; const Text = @import("text.zig"); const ProcessingInstruction = @import("processing_instruction.zig").ProcessingInstruction; -const HTMLElem = @import("../html/elements.zig"); +const Element = @import("element.zig").Element; +const ElementUnion = @import("element.zig").Union; // CharacterData interfaces pub const Interfaces = .{ @@ -49,20 +50,20 @@ pub const CharacterData = struct { return try parser.characterDataLength(self); } - pub fn get_nextElementSibling(self: *parser.CharacterData) !?HTMLElem.Union { + pub fn get_nextElementSibling(self: *parser.CharacterData) !?ElementUnion { const res = try parser.nodeNextElementSibling(parser.characterDataToNode(self)); if (res == null) { return null; } - return try HTMLElem.toInterface(HTMLElem.Union, res.?); + return try Element.toInterface(res.?); } - pub fn get_previousElementSibling(self: *parser.CharacterData) !?HTMLElem.Union { + pub fn get_previousElementSibling(self: *parser.CharacterData) !?ElementUnion { const res = try parser.nodePreviousElementSibling(parser.characterDataToNode(self)); if (res == null) { return null; } - return try HTMLElem.toInterface(HTMLElem.Union, res.?); + return try Element.toInterface(res.?); } // Read/Write attributes diff --git a/src/browser/dom/document.zig b/src/browser/dom/document.zig index bfc4aa15..7a6b5b6d 100644 --- a/src/browser/dom/document.zig +++ b/src/browser/dom/document.zig @@ -66,10 +66,8 @@ pub const Document = struct { return DOMImplementation{}; } - pub fn get_documentElement(self: *parser.Document) !?ElementUnion { - const e = try parser.documentGetDocumentElement(self); - if (e == null) return null; - return try Element.toInterface(e.?); + pub fn get_documentElement(self: *parser.Document) !?*parser.Element { + return try parser.documentGetDocumentElement(self); } pub fn get_documentURI(self: *parser.Document) ![]const u8 { diff --git a/src/browser/dom/element.zig b/src/browser/dom/element.zig index 054ba57e..af556b46 100644 --- a/src/browser/dom/element.zig +++ b/src/browser/dom/element.zig @@ -55,8 +55,23 @@ pub const Element = struct { }; pub fn toInterface(e: *parser.Element) !Union { - return try HTMLElem.toInterface(Union, e); - // SVGElement and MathML are not supported yet. + return toInterfaceT(Union, e); + } + + pub fn toInterfaceT(comptime T: type, e: *parser.Element) !T { + const tagname = try parser.elementGetTagName(e) orelse { + // in case of null tagname, return the element as it. + return .{ .Element = e }; + }; + + // TODO SVGElement and MathML are not supported yet. + + const tag = parser.Tag.fromString(tagname) catch { + // if the tag is invalid, we don't have an HTMLElement. + return .{ .Element = e }; + }; + + return HTMLElem.toInterfaceFromTag(T, e, tag); } // JS funcs @@ -344,13 +359,13 @@ pub const Element = struct { pub fn get_previousElementSibling(self: *parser.Element) !?Union { const res = try parser.nodePreviousElementSibling(parser.elementToNode(self)); if (res == null) return null; - return try HTMLElem.toInterface(HTMLElem.Union, res.?); + return try toInterface(res.?); } pub fn get_nextElementSibling(self: *parser.Element) !?Union { const res = try parser.nodeNextElementSibling(parser.elementToNode(self)); if (res == null) return null; - return try HTMLElem.toInterface(HTMLElem.Union, res.?); + return try toInterface(res.?); } fn getElementById(self: *parser.Element, id: []const u8) !?*parser.Node { diff --git a/src/browser/dom/node.zig b/src/browser/dom/node.zig index cca301ce..25c15431 100644 --- a/src/browser/dom/node.zig +++ b/src/browser/dom/node.zig @@ -29,6 +29,7 @@ const EventTarget = @import("event_target.zig").EventTarget; const Attr = @import("attribute.zig").Attr; const CData = @import("character_data.zig"); const Element = @import("element.zig").Element; +const ElementUnion = @import("element.zig").Union; const NodeList = @import("nodelist.zig").NodeList; const Document = @import("document.zig").Document; const DocumentType = @import("document_type.zig").DocumentType; @@ -40,7 +41,6 @@ const Walker = @import("walker.zig").WalkerDepthFirst; // HTML const HTML = @import("../html/html.zig"); -const HTMLElem = @import("../html/elements.zig"); // Node interfaces pub const Interfaces = .{ @@ -67,7 +67,7 @@ pub const Node = struct { pub fn toInterface(node: *parser.Node) !Union { return switch (try parser.nodeType(node)) { - .element => try HTMLElem.toInterface( + .element => try Element.toInterfaceT( Union, @as(*parser.Element, @ptrCast(node)), ), @@ -145,12 +145,12 @@ pub const Node = struct { return try Node.toInterface(res.?); } - pub fn get_parentElement(self: *parser.Node) !?HTMLElem.Union { + pub fn get_parentElement(self: *parser.Node) !?ElementUnion { const res = try parser.nodeParentElement(self); if (res == null) { return null; } - return try HTMLElem.toInterface(HTMLElem.Union, @as(*parser.Element, @ptrCast(res.?))); + return try Element.toInterface(res.?); } pub fn get_nodeName(self: *parser.Node) ![]const u8 { diff --git a/src/browser/dump.zig b/src/browser/dump.zig index f69ba095..0fbc7e44 100644 --- a/src/browser/dump.zig +++ b/src/browser/dump.zig @@ -62,7 +62,7 @@ pub fn writeNode(node: *parser.Node, opts: Opts, writer: anytype) anyerror!void switch (try parser.nodeType(node)) { .element => { // open the tag - const tag_type = try parser.elementHTMLGetTagType(@ptrCast(node)); + const tag_type = try parser.nodeHTMLGetTagType(node) orelse .undef; if (tag_type == .script and opts.exclude_scripts) { return; } @@ -150,7 +150,7 @@ pub fn writeChildren(root: *parser.Node, opts: Opts, writer: anytype) !void { // area, base, br, col, embed, hr, img, input, link, meta, source, track, wbr // https://html.spec.whatwg.org/#void-elements fn isVoid(elem: *parser.Element) !bool { - const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem))); + const tag = try parser.elementTag(elem); return switch (tag) { .area, .base, .br, .col, .embed, .hr, .img, .input, .link => true, .meta, .source, .track, .wbr => true, diff --git a/src/browser/html/elements.zig b/src/browser/html/elements.zig index 785c3fda..5be01a1e 100644 --- a/src/browser/html/elements.zig +++ b/src/browser/html/elements.zig @@ -34,6 +34,7 @@ const CSSStyleDeclaration = @import("../cssom/CSSStyleDeclaration.zig"); // HTMLElement interfaces pub const Interfaces = .{ + Element, HTMLElement, HTMLUnknownElement, HTMLAnchorElement, @@ -1108,78 +1109,75 @@ pub const HTMLVideoElement = struct { pub const subtype = .node; }; -pub fn toInterface(comptime T: type, e: *parser.Element) !T { - const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(e); - const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem))); - +pub fn toInterfaceFromTag(comptime T: type, e: *parser.Element, tag: parser.Tag) !T { return switch (tag) { - .abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => .{ .HTMLElement = @as(*parser.ElementHTML, @ptrCast(elem)) }, - .a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(elem)) }, - .applet => .{ .HTMLAppletElement = @as(*parser.Applet, @ptrCast(elem)) }, - .area => .{ .HTMLAreaElement = @as(*parser.Area, @ptrCast(elem)) }, - .audio => .{ .HTMLAudioElement = @as(*parser.Audio, @ptrCast(elem)) }, - .base => .{ .HTMLBaseElement = @as(*parser.Base, @ptrCast(elem)) }, - .body => .{ .HTMLBodyElement = @as(*parser.Body, @ptrCast(elem)) }, - .br => .{ .HTMLBRElement = @as(*parser.BR, @ptrCast(elem)) }, - .button => .{ .HTMLButtonElement = @as(*parser.Button, @ptrCast(elem)) }, - .canvas => .{ .HTMLCanvasElement = @as(*parser.Canvas, @ptrCast(elem)) }, - .dl => .{ .HTMLDListElement = @as(*parser.DList, @ptrCast(elem)) }, - .data => .{ .HTMLDataElement = @as(*parser.Data, @ptrCast(elem)) }, - .datalist => .{ .HTMLDataListElement = @as(*parser.DataList, @ptrCast(elem)) }, - .dialog => .{ .HTMLDialogElement = @as(*parser.Dialog, @ptrCast(elem)) }, - .dir => .{ .HTMLDirectoryElement = @as(*parser.Directory, @ptrCast(elem)) }, - .div => .{ .HTMLDivElement = @as(*parser.Div, @ptrCast(elem)) }, - .embed => .{ .HTMLEmbedElement = @as(*parser.Embed, @ptrCast(elem)) }, - .fieldset => .{ .HTMLFieldSetElement = @as(*parser.FieldSet, @ptrCast(elem)) }, - .font => .{ .HTMLFontElement = @as(*parser.Font, @ptrCast(elem)) }, - .form => .{ .HTMLFormElement = @as(*parser.Form, @ptrCast(elem)) }, - .frame => .{ .HTMLFrameElement = @as(*parser.Frame, @ptrCast(elem)) }, - .frameset => .{ .HTMLFrameSetElement = @as(*parser.FrameSet, @ptrCast(elem)) }, - .hr => .{ .HTMLHRElement = @as(*parser.HR, @ptrCast(elem)) }, - .head => .{ .HTMLHeadElement = @as(*parser.Head, @ptrCast(elem)) }, - .h1, .h2, .h3, .h4, .h5, .h6 => .{ .HTMLHeadingElement = @as(*parser.Heading, @ptrCast(elem)) }, - .html => .{ .HTMLHtmlElement = @as(*parser.Html, @ptrCast(elem)) }, - .iframe => .{ .HTMLIFrameElement = @as(*parser.IFrame, @ptrCast(elem)) }, - .img => .{ .HTMLImageElement = @as(*parser.Image, @ptrCast(elem)) }, - .input => .{ .HTMLInputElement = @as(*parser.Input, @ptrCast(elem)) }, - .li => .{ .HTMLLIElement = @as(*parser.LI, @ptrCast(elem)) }, - .label => .{ .HTMLLabelElement = @as(*parser.Label, @ptrCast(elem)) }, - .legend => .{ .HTMLLegendElement = @as(*parser.Legend, @ptrCast(elem)) }, - .link => .{ .HTMLLinkElement = @as(*parser.Link, @ptrCast(elem)) }, - .map => .{ .HTMLMapElement = @as(*parser.Map, @ptrCast(elem)) }, - .meta => .{ .HTMLMetaElement = @as(*parser.Meta, @ptrCast(elem)) }, - .meter => .{ .HTMLMeterElement = @as(*parser.Meter, @ptrCast(elem)) }, - .ins, .del => .{ .HTMLModElement = @as(*parser.Mod, @ptrCast(elem)) }, - .ol => .{ .HTMLOListElement = @as(*parser.OList, @ptrCast(elem)) }, - .object => .{ .HTMLObjectElement = @as(*parser.Object, @ptrCast(elem)) }, - .optgroup => .{ .HTMLOptGroupElement = @as(*parser.OptGroup, @ptrCast(elem)) }, - .option => .{ .HTMLOptionElement = @as(*parser.Option, @ptrCast(elem)) }, - .output => .{ .HTMLOutputElement = @as(*parser.Output, @ptrCast(elem)) }, - .p => .{ .HTMLParagraphElement = @as(*parser.Paragraph, @ptrCast(elem)) }, - .param => .{ .HTMLParamElement = @as(*parser.Param, @ptrCast(elem)) }, - .picture => .{ .HTMLPictureElement = @as(*parser.Picture, @ptrCast(elem)) }, - .pre => .{ .HTMLPreElement = @as(*parser.Pre, @ptrCast(elem)) }, - .progress => .{ .HTMLProgressElement = @as(*parser.Progress, @ptrCast(elem)) }, - .blockquote, .q => .{ .HTMLQuoteElement = @as(*parser.Quote, @ptrCast(elem)) }, - .script => .{ .HTMLScriptElement = @as(*parser.Script, @ptrCast(elem)) }, - .select => .{ .HTMLSelectElement = @as(*parser.Select, @ptrCast(elem)) }, - .source => .{ .HTMLSourceElement = @as(*parser.Source, @ptrCast(elem)) }, - .span => .{ .HTMLSpanElement = @as(*parser.Span, @ptrCast(elem)) }, - .style => .{ .HTMLStyleElement = @as(*parser.Style, @ptrCast(elem)) }, - .table => .{ .HTMLTableElement = @as(*parser.Table, @ptrCast(elem)) }, - .caption => .{ .HTMLTableCaptionElement = @as(*parser.TableCaption, @ptrCast(elem)) }, - .th, .td => .{ .HTMLTableCellElement = @as(*parser.TableCell, @ptrCast(elem)) }, - .col, .colgroup => .{ .HTMLTableColElement = @as(*parser.TableCol, @ptrCast(elem)) }, - .tr => .{ .HTMLTableRowElement = @as(*parser.TableRow, @ptrCast(elem)) }, - .thead, .tbody, .tfoot => .{ .HTMLTableSectionElement = @as(*parser.TableSection, @ptrCast(elem)) }, - .template => .{ .HTMLTemplateElement = @as(*parser.Template, @ptrCast(elem)) }, - .textarea => .{ .HTMLTextAreaElement = @as(*parser.TextArea, @ptrCast(elem)) }, - .time => .{ .HTMLTimeElement = @as(*parser.Time, @ptrCast(elem)) }, - .title => .{ .HTMLTitleElement = @as(*parser.Title, @ptrCast(elem)) }, - .track => .{ .HTMLTrackElement = @as(*parser.Track, @ptrCast(elem)) }, - .ul => .{ .HTMLUListElement = @as(*parser.UList, @ptrCast(elem)) }, - .video => .{ .HTMLVideoElement = @as(*parser.Video, @ptrCast(elem)) }, - .undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(elem)) }, + .abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => .{ .HTMLElement = @as(*parser.ElementHTML, @ptrCast(e)) }, + .a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(e)) }, + .applet => .{ .HTMLAppletElement = @as(*parser.Applet, @ptrCast(e)) }, + .area => .{ .HTMLAreaElement = @as(*parser.Area, @ptrCast(e)) }, + .audio => .{ .HTMLAudioElement = @as(*parser.Audio, @ptrCast(e)) }, + .base => .{ .HTMLBaseElement = @as(*parser.Base, @ptrCast(e)) }, + .body => .{ .HTMLBodyElement = @as(*parser.Body, @ptrCast(e)) }, + .br => .{ .HTMLBRElement = @as(*parser.BR, @ptrCast(e)) }, + .button => .{ .HTMLButtonElement = @as(*parser.Button, @ptrCast(e)) }, + .canvas => .{ .HTMLCanvasElement = @as(*parser.Canvas, @ptrCast(e)) }, + .dl => .{ .HTMLDListElement = @as(*parser.DList, @ptrCast(e)) }, + .data => .{ .HTMLDataElement = @as(*parser.Data, @ptrCast(e)) }, + .datalist => .{ .HTMLDataListElement = @as(*parser.DataList, @ptrCast(e)) }, + .dialog => .{ .HTMLDialogElement = @as(*parser.Dialog, @ptrCast(e)) }, + .dir => .{ .HTMLDirectoryElement = @as(*parser.Directory, @ptrCast(e)) }, + .div => .{ .HTMLDivElement = @as(*parser.Div, @ptrCast(e)) }, + .embed => .{ .HTMLEmbedElement = @as(*parser.Embed, @ptrCast(e)) }, + .fieldset => .{ .HTMLFieldSetElement = @as(*parser.FieldSet, @ptrCast(e)) }, + .font => .{ .HTMLFontElement = @as(*parser.Font, @ptrCast(e)) }, + .form => .{ .HTMLFormElement = @as(*parser.Form, @ptrCast(e)) }, + .frame => .{ .HTMLFrameElement = @as(*parser.Frame, @ptrCast(e)) }, + .frameset => .{ .HTMLFrameSetElement = @as(*parser.FrameSet, @ptrCast(e)) }, + .hr => .{ .HTMLHRElement = @as(*parser.HR, @ptrCast(e)) }, + .head => .{ .HTMLHeadElement = @as(*parser.Head, @ptrCast(e)) }, + .h1, .h2, .h3, .h4, .h5, .h6 => .{ .HTMLHeadingElement = @as(*parser.Heading, @ptrCast(e)) }, + .html => .{ .HTMLHtmlElement = @as(*parser.Html, @ptrCast(e)) }, + .iframe => .{ .HTMLIFrameElement = @as(*parser.IFrame, @ptrCast(e)) }, + .img => .{ .HTMLImageElement = @as(*parser.Image, @ptrCast(e)) }, + .input => .{ .HTMLInputElement = @as(*parser.Input, @ptrCast(e)) }, + .li => .{ .HTMLLIElement = @as(*parser.LI, @ptrCast(e)) }, + .label => .{ .HTMLLabelElement = @as(*parser.Label, @ptrCast(e)) }, + .legend => .{ .HTMLLegendElement = @as(*parser.Legend, @ptrCast(e)) }, + .link => .{ .HTMLLinkElement = @as(*parser.Link, @ptrCast(e)) }, + .map => .{ .HTMLMapElement = @as(*parser.Map, @ptrCast(e)) }, + .meta => .{ .HTMLMetaElement = @as(*parser.Meta, @ptrCast(e)) }, + .meter => .{ .HTMLMeterElement = @as(*parser.Meter, @ptrCast(e)) }, + .ins, .del => .{ .HTMLModElement = @as(*parser.Mod, @ptrCast(e)) }, + .ol => .{ .HTMLOListElement = @as(*parser.OList, @ptrCast(e)) }, + .object => .{ .HTMLObjectElement = @as(*parser.Object, @ptrCast(e)) }, + .optgroup => .{ .HTMLOptGroupElement = @as(*parser.OptGroup, @ptrCast(e)) }, + .option => .{ .HTMLOptionElement = @as(*parser.Option, @ptrCast(e)) }, + .output => .{ .HTMLOutputElement = @as(*parser.Output, @ptrCast(e)) }, + .p => .{ .HTMLParagraphElement = @as(*parser.Paragraph, @ptrCast(e)) }, + .param => .{ .HTMLParamElement = @as(*parser.Param, @ptrCast(e)) }, + .picture => .{ .HTMLPictureElement = @as(*parser.Picture, @ptrCast(e)) }, + .pre => .{ .HTMLPreElement = @as(*parser.Pre, @ptrCast(e)) }, + .progress => .{ .HTMLProgressElement = @as(*parser.Progress, @ptrCast(e)) }, + .blockquote, .q => .{ .HTMLQuoteElement = @as(*parser.Quote, @ptrCast(e)) }, + .script => .{ .HTMLScriptElement = @as(*parser.Script, @ptrCast(e)) }, + .select => .{ .HTMLSelectElement = @as(*parser.Select, @ptrCast(e)) }, + .source => .{ .HTMLSourceElement = @as(*parser.Source, @ptrCast(e)) }, + .span => .{ .HTMLSpanElement = @as(*parser.Span, @ptrCast(e)) }, + .style => .{ .HTMLStyleElement = @as(*parser.Style, @ptrCast(e)) }, + .table => .{ .HTMLTableElement = @as(*parser.Table, @ptrCast(e)) }, + .caption => .{ .HTMLTableCaptionElement = @as(*parser.TableCaption, @ptrCast(e)) }, + .th, .td => .{ .HTMLTableCellElement = @as(*parser.TableCell, @ptrCast(e)) }, + .col, .colgroup => .{ .HTMLTableColElement = @as(*parser.TableCol, @ptrCast(e)) }, + .tr => .{ .HTMLTableRowElement = @as(*parser.TableRow, @ptrCast(e)) }, + .thead, .tbody, .tfoot => .{ .HTMLTableSectionElement = @as(*parser.TableSection, @ptrCast(e)) }, + .template => .{ .HTMLTemplateElement = @as(*parser.Template, @ptrCast(e)) }, + .textarea => .{ .HTMLTextAreaElement = @as(*parser.TextArea, @ptrCast(e)) }, + .time => .{ .HTMLTimeElement = @as(*parser.Time, @ptrCast(e)) }, + .title => .{ .HTMLTitleElement = @as(*parser.Title, @ptrCast(e)) }, + .track => .{ .HTMLTrackElement = @as(*parser.Track, @ptrCast(e)) }, + .ul => .{ .HTMLUListElement = @as(*parser.UList, @ptrCast(e)) }, + .video => .{ .HTMLVideoElement = @as(*parser.Video, @ptrCast(e)) }, + .undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(e)) }, }; } diff --git a/src/browser/netsurf.zig b/src/browser/netsurf.zig index 9b17cf5a..72eedee7 100644 --- a/src/browser/netsurf.zig +++ b/src/browser/netsurf.zig @@ -328,6 +328,24 @@ pub const Tag = enum(u8) { else => upperName(@tagName(tag)), }; } + + pub fn fromString(tagname: []const u8) !Tag { + inline for (@typeInfo(Tag).@"enum".fields) |field| { + if (std.ascii.eqlIgnoreCase(field.name, tagname)) { + return @enumFromInt(field.value); + } + } + + return error.Invalid; + } + + const testing = @import("../testing.zig"); + test "Tag.fromString" { + try testing.expect(try Tag.fromString("ABBR") == .abbr); + try testing.expect(try Tag.fromString("abbr") == .abbr); + + try testing.expect(Tag.fromString("foo") == error.Invalid); + } }; // DOMException @@ -1410,13 +1428,13 @@ pub inline fn nodeToDocument(node: *Node) *Document { return @as(*Document, @ptrCast(node)); } -// Combination of nodeToElement + elementHTMLGetTagType +// Combination of nodeToElement + elementTag pub fn nodeHTMLGetTagType(node: *Node) !?Tag { if (try nodeType(node) != .element) { return null; } - const html_element: *ElementHTML = @ptrCast(node); - return try elementHTMLGetTagType(html_element); + + return try elementTag(@ptrCast(node)); } // CharacterData @@ -1577,6 +1595,20 @@ fn elementVtable(elem: *Element) c.dom_element_vtable { return getVtable(c.dom_element_vtable, Element, elem); } +pub fn elementTag(elem: *Element) !Tag { + const tagname = try elementGetTagName(elem) orelse return .undef; + return Tag.fromString(tagname) catch .undef; +} + +pub fn elementGetTagName(elem: *Element) !?[]const u8 { + var s: ?*String = undefined; + const err = elementVtable(elem).dom_element_get_tag_name.?(elem, &s); + try DOMErr(err); + if (s == null) return null; + + return strToData(s.?); +} + pub fn elementGetAttribute(elem: *Element, name: []const u8) !?[]const u8 { var s: ?*String = undefined; const err = elementVtable(elem).dom_element_get_attribute.?(elem, try strFromData(name), &s); @@ -1770,21 +1802,6 @@ fn elementHTMLVtable(elem_html: *ElementHTML) c.dom_html_element_vtable { return getVtable(c.dom_html_element_vtable, ElementHTML, elem_html); } -pub fn elementHTMLGetTagType(elem_html: *ElementHTML) !Tag { - var tag_type: c.dom_html_element_type = undefined; - const err = elementHTMLVtable(elem_html).dom_html_element_get_tag_type.?(elem_html, &tag_type); - try DOMErr(err); - - if (tag_type >= 255) { - // This is questionable, but std.meta.intToEnum has more overhead - // Added this because this WPT test started to fail once we - // introduced an SVGElement: - // html/dom/documents/dom-tree-accessors/document.title-09.html - return Tag.undef; - } - return @as(Tag, @enumFromInt(tag_type)); -} - // HTMLScriptElement // scriptToElt is an helper to convert an script to an element. @@ -2139,14 +2156,45 @@ pub inline fn documentCreateDocument(title: ?[]const u8) !*DocumentHTML { return doc_html; } -pub inline fn documentCreateElement(doc: *Document, tag_name: []const u8) !*Element { +fn documentCreateHTMLElement(doc: *Document, tag_name: []const u8) !*Element { + std.debug.assert(doc.is_html); + + var elem: ?*Element = undefined; + const err = c._dom_html_document_create_element(doc, try strFromData(tag_name), &elem); + try DOMErr(err); + return elem.?; +} + +pub fn documentCreateElement(doc: *Document, tag_name: []const u8) !*Element { + if (doc.is_html) { + return documentCreateHTMLElement(doc, tag_name); + } + var elem: ?*Element = undefined; const err = documentVtable(doc).dom_document_create_element.?(doc, try strFromData(tag_name), &elem); try DOMErr(err); return elem.?; } -pub inline fn documentCreateElementNS(doc: *Document, ns: []const u8, tag_name: []const u8) !*Element { +fn documentCreateHTMLElementNS(doc: *Document, ns: []const u8, tag_name: []const u8) !*Element { + std.debug.assert(doc.is_html); + + var elem: ?*Element = undefined; + const err = c._dom_html_document_create_element_ns( + doc, + try strFromData(ns), + try strFromData(tag_name), + &elem, + ); + try DOMErr(err); + return elem.?; +} + +pub fn documentCreateElementNS(doc: *Document, ns: []const u8, tag_name: []const u8) !*Element { + if (doc.is_html) { + return documentCreateHTMLElementNS(doc, ns, tag_name); + } + var elem: ?*Element = undefined; const err = documentVtable(doc).dom_document_create_element_ns.?( doc, diff --git a/src/browser/page.zig b/src/browser/page.zig index aece1cbe..eff09152 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -365,7 +365,7 @@ pub const Page = struct { const current = next.?; const e = parser.nodeToElement(current); - const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(e))); + const tag = try parser.elementTag(e); if (tag != .script) { // ignore non-js script. @@ -809,7 +809,7 @@ pub const Page = struct { if (try parser.elementGetAttribute(element, "form")) |form_id| { const document = parser.documentHTMLToDocument(self.window.document); const form_element = try parser.documentGetElementById(document, form_id) orelse return null; - if (try parser.elementHTMLGetTagType(@ptrCast(form_element)) == .form) { + if (try parser.elementTag(@ptrCast(form_element)) == .form) { return @ptrCast(form_element); } return null; diff --git a/src/browser/xhr/form_data.zig b/src/browser/xhr/form_data.zig index 48e03ad3..6dc1a69f 100644 --- a/src/browser/xhr/form_data.zig +++ b/src/browser/xhr/form_data.zig @@ -141,7 +141,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page continue; } - const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(element))); + const tag = try parser.elementTag(element); switch (tag) { .input => { const tpe = try parser.inputGetType(@ptrCast(element)); @@ -246,7 +246,7 @@ fn collectSelectValues(arena: Allocator, select: *parser.Select, name: []const u fn getSubmitterName(submitter_: ?*parser.ElementHTML) !?[]const u8 { const submitter = submitter_ orelse return null; - const tag = try parser.elementHTMLGetTagType(submitter); + const tag = try parser.elementTag(@ptrCast(submitter)); const element: *parser.Element = @ptrCast(submitter); const name = try parser.elementGetAttribute(element, "name"); diff --git a/vendor/netsurf/libdom b/vendor/netsurf/libdom index 11b5bf86..16a0d916 160000 --- a/vendor/netsurf/libdom +++ b/vendor/netsurf/libdom @@ -1 +1 @@ -Subproject commit 11b5bf869adda7a9402c196a99ea443bd1557eb5 +Subproject commit 16a0d9168473c5521519c240c1f2aabf8f74cef1