srctree

Robin Linden parent 5b20ff92 a2baeec0
html2: Finish up the outline of the AfterHead state

inlinesplit
html2/parser_states.cpp added: 96, removed: 6, total 90
@@ -419,6 +419,21 @@ std::optional<InsertionMode> InHeadNoscript::process(IActions &a, html2::Token c
}
 
std::optional<InsertionMode> AfterHead::process(IActions &a, html2::Token const &token) {
if (is_boring_whitespace(token)) {
a.insert_character(std::get<html2::CharacterToken>(token));
return {};
}
 
if (std::holds_alternative<html2::CommentToken>(token)) {
// TODO(robinlinden): Insert.
return {};
}
 
if (std::holds_alternative<html2::DoctypeToken>(token)) {
// Parse error.
return {};
}
 
if (auto const *start = std::get_if<html2::StartTagToken>(&token); start != nullptr) {
if (start->tag_name == "html") {
return InBody{}.process(a, token);
@@ -430,7 +445,11 @@ std::optional<InsertionMode> AfterHead::process(IActions &a, html2::Token const
return InBody{};
}
 
// TODO(robinlinden): frameset
if (start->tag_name == "frameset") {
a.insert_element_for(*start);
// TODO(robinlinden): Switch to InFrameset.
return {};
}
 
static constexpr auto kInHeadElements = std::to_array<std::string_view>({
"base"sv,
@@ -453,8 +472,30 @@ std::optional<InsertionMode> AfterHead::process(IActions &a, html2::Token const
a.remove_from_open_elements("head");
return {};
}
 
if (start->tag_name == "head") {
// Parse error.
return {};
}
}
 
if (auto const *end = std::get_if<html2::EndTagToken>(&token); end != nullptr) {
if (end->tag_name == "template") {
// TODO(robinlinden): Process using InHead's rules once implemented.
return {};
}
 
if (end->tag_name == "body" || end->tag_name == "html" || end->tag_name == "br") {
// Treat as "anything else."
} else {
// Parse error.
return {};
}
}
 
// TODO(robinlinden): Insert an HTML element for "body", switch to InBody,
// reprocess current token. We can't really do this before we're ready to
// drop the old html parser's element handling.
return {};
}
 
 
html2/parser_states.h added: 96, removed: 6, total 90
@@ -109,7 +109,6 @@ struct InHeadNoscript {
};
 
// https://html.spec.whatwg.org/multipage/parsing.html#the-after-head-insertion-mode
// Incomplete.
struct AfterHead {
std::optional<InsertionMode> process(IActions &, html2::Token const &);
};
 
html2/parser_states_test.cpp added: 96, removed: 6, total 90
@@ -295,6 +295,21 @@ void in_head_noscript_tests() {
}
 
void after_head_tests() {
etest::test("AfterHead: boring whitespace", [] {
auto res = parse("<head></head> ", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}, dom::Text{" "}}});
});
 
etest::test("AfterHead: comment", [] {
auto res = parse("<head></head><!-- comment -->", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: doctype", [] {
auto res = parse("<head></head><!doctype html>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: html", [] {
auto res = parse("<html foo=bar><head></head><html foo=baz hello=world>", {});
auto const &head = std::get<dom::Element>(res.document.html().children.at(0));
@@ -308,7 +323,7 @@ void after_head_tests() {
});
 
etest::test("AfterHead: base, basefont, bgsound, link", [] {
auto res = parse("<head></head><base> <basefont> <bgsound> <link>", {});
auto res = parse("<head></head><base><basefont><bgsound><link>", {});
 
auto head_children =
NodeVec{dom::Element{"base"}, dom::Element{"basefont"}, dom::Element{"bgsound"}, dom::Element{"link"}};
@@ -316,6 +331,41 @@ void after_head_tests() {
 
expect_eq(res.document.html(), dom::Element{"html", {}, {std::move(head)}});
});
 
etest::test("AfterHead: head", [] {
auto res = parse("<head></head><head>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: </template>", [] {
auto res = parse("<head></head></template>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: </body>", [] {
auto res = parse("<head></head></body>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: </html>", [] {
auto res = parse("<head></head></html>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: </br>", [] {
auto res = parse("<head></head></br>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: </error>", [] {
auto res = parse("<head></head></error>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}}});
});
 
etest::test("AfterHead: <frameset>", [] {
auto res = parse("<head></head><frameset>", {});
expect_eq(res.document.html(), dom::Element{"html", {}, {dom::Element{"head"}, dom::Element{"frameset"}}});
});
}
 
} // namespace