mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-23 08:00:20 +00:00
LibWeb: Update parser with more insertion modes :^)
Implements handling of InHeadNoScript, InSelectInTable, InTemplate, InFrameset, AfterFrameset, and AfterAfterFrameset.
This commit is contained in:
parent
8e24a17d0d
commit
5eb39a5f61
Notes:
sideshowbarker
2024-07-19 05:29:53 +09:00
Author: https://github.com/stelar7 Commit: https://github.com/SerenityOS/serenity/commit/5eb39a5f61a Pull-request: https://github.com/SerenityOS/serenity/pull/2604
6 changed files with 471 additions and 30 deletions
|
@ -87,6 +87,7 @@ void initialize();
|
|||
__ENUMERATE_HTML_TAG(html) \
|
||||
__ENUMERATE_HTML_TAG(i) \
|
||||
__ENUMERATE_HTML_TAG(iframe) \
|
||||
__ENUMERATE_HTML_TAG(image) \
|
||||
__ENUMERATE_HTML_TAG(img) \
|
||||
__ENUMERATE_HTML_TAG(input) \
|
||||
__ENUMERATE_HTML_TAG(keygen) \
|
||||
|
@ -95,6 +96,7 @@ void initialize();
|
|||
__ENUMERATE_HTML_TAG(listing) \
|
||||
__ENUMERATE_HTML_TAG(main) \
|
||||
__ENUMERATE_HTML_TAG(marquee) \
|
||||
__ENUMERATE_HTML_TAG(math) \
|
||||
__ENUMERATE_HTML_TAG(menu) \
|
||||
__ENUMERATE_HTML_TAG(meta) \
|
||||
__ENUMERATE_HTML_TAG(nav) \
|
||||
|
@ -110,6 +112,7 @@ void initialize();
|
|||
__ENUMERATE_HTML_TAG(param) \
|
||||
__ENUMERATE_HTML_TAG(plaintext) \
|
||||
__ENUMERATE_HTML_TAG(pre) \
|
||||
__ENUMERATE_HTML_TAG(ruby) \
|
||||
__ENUMERATE_HTML_TAG(rb) \
|
||||
__ENUMERATE_HTML_TAG(rp) \
|
||||
__ENUMERATE_HTML_TAG(rt) \
|
||||
|
@ -125,6 +128,7 @@ void initialize();
|
|||
__ENUMERATE_HTML_TAG(strong) \
|
||||
__ENUMERATE_HTML_TAG(style) \
|
||||
__ENUMERATE_HTML_TAG(summary) \
|
||||
__ENUMERATE_HTML_TAG(svg) \
|
||||
__ENUMERATE_HTML_TAG(table) \
|
||||
__ENUMERATE_HTML_TAG(tbody) \
|
||||
__ENUMERATE_HTML_TAG(td) \
|
||||
|
|
|
@ -155,6 +155,18 @@ void HTMLDocumentParser::process_using_the_rules_for(InsertionMode mode, HTMLTok
|
|||
case InsertionMode::InColumnGroup:
|
||||
handle_in_column_group(token);
|
||||
break;
|
||||
case InsertionMode::InTemplate:
|
||||
handle_in_template(token);
|
||||
break;
|
||||
case InsertionMode::InFrameset:
|
||||
handle_in_frameset(token);
|
||||
break;
|
||||
case InsertionMode::AfterFrameset:
|
||||
handle_after_frameset(token);
|
||||
break;
|
||||
case InsertionMode::AfterAfterFrameset:
|
||||
handle_after_after_frameset(token);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
@ -254,7 +266,7 @@ NonnullRefPtr<Element> HTMLDocumentParser::create_element_for(HTMLToken& token)
|
|||
{
|
||||
auto element = create_element(document(), token.tag_name());
|
||||
for (auto& attribute : token.m_tag.attributes) {
|
||||
element->set_attribute(attribute.name_builder.to_string(), attribute.value_builder.to_string());
|
||||
element->set_attribute(attribute.local_name_builder.to_string(), attribute.value_builder.to_string());
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
@ -372,6 +384,11 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noscript && !m_scripting_enabled) {
|
||||
insert_html_element(token);
|
||||
m_insertion_mode = InsertionMode::InHeadNoscript;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::script) {
|
||||
auto adjusted_insertion_location = find_appropriate_place_for_inserting_node();
|
||||
auto element = create_element_for(token);
|
||||
|
@ -401,7 +418,7 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
|
|||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::body, HTML::TagNames::html, HTML::TagNames::br)) {
|
||||
TODO();
|
||||
goto AnythingElse;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::template_) {
|
||||
|
@ -422,14 +439,49 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
AnythingElse:
|
||||
m_stack_of_open_elements.pop();
|
||||
m_insertion_mode = InsertionMode::AfterHead;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_in_head_noscript(HTMLToken&)
|
||||
void HTMLDocumentParser::handle_in_head_noscript(HTMLToken& token)
|
||||
{
|
||||
TODO();
|
||||
if (token.is_doctype()) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::html) {
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::noscript) {
|
||||
m_stack_of_open_elements.pop();
|
||||
m_insertion_mode = InsertionMode::InHead;
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_parser_whitespace() || token.is_comment() || (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::basefont, HTML::TagNames::bgsound, HTML::TagNames::link, HTML::TagNames::meta, HTML::TagNames::noframes, HTML::TagNames::style))) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::br) {
|
||||
goto AnythingElse;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::head, HTML::TagNames::noscript)) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
AnythingElse:
|
||||
PARSE_ERROR();
|
||||
m_stack_of_open_elements.pop();
|
||||
m_insertion_mode = InsertionMode::InHead;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::parse_generic_raw_text_element(HTMLToken& token)
|
||||
|
@ -524,7 +576,7 @@ void HTMLDocumentParser::handle_after_head(HTMLToken& token)
|
|||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_) {
|
||||
TODO();
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::body, HTML::TagNames::html, HTML::TagNames::br)) {
|
||||
|
@ -568,7 +620,10 @@ void HTMLDocumentParser::handle_after_body(HTMLToken& token)
|
|||
}
|
||||
|
||||
if (token.is_comment()) {
|
||||
TODO();
|
||||
auto data = token.m_comment_or_character.data.to_string();
|
||||
auto& insertion_location = m_stack_of_open_elements.first();
|
||||
insertion_location.append_child(adopt(*new Comment(document(), data)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_doctype()) {
|
||||
|
@ -581,11 +636,6 @@ void HTMLDocumentParser::handle_after_body(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
stop_parsing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::html) {
|
||||
if (m_parsing_fragment) {
|
||||
TODO();
|
||||
|
@ -594,6 +644,11 @@ void HTMLDocumentParser::handle_after_body(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
stop_parsing();
|
||||
return;
|
||||
}
|
||||
|
||||
PARSE_ERROR();
|
||||
m_insertion_mode = InsertionMode::InBody;
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
|
@ -845,9 +900,9 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
|||
if (m_stack_of_open_elements.contains(HTML::TagNames::template_))
|
||||
return;
|
||||
for (auto& attribute : token.m_tag.attributes) {
|
||||
if (current_node().has_attribute(attribute.name_builder.string_view()))
|
||||
if (current_node().has_attribute(attribute.local_name_builder.string_view()))
|
||||
continue;
|
||||
current_node().set_attribute(attribute.name_builder.to_string(), attribute.value_builder.to_string());
|
||||
current_node().set_attribute(attribute.local_name_builder.to_string(), attribute.value_builder.to_string());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -870,9 +925,9 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
|||
}
|
||||
m_frameset_ok = false;
|
||||
for (auto& attribute : token.m_tag.attributes) {
|
||||
if (node_before_current_node().has_attribute(attribute.name_builder.string_view()))
|
||||
if (node_before_current_node().has_attribute(attribute.local_name_builder.string_view()))
|
||||
continue;
|
||||
node_before_current_node().set_attribute(attribute.name_builder.to_string(), attribute.value_builder.to_string());
|
||||
node_before_current_node().set_attribute(attribute.local_name_builder.to_string(), attribute.value_builder.to_string());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1281,7 +1336,7 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().equals_ignoring_case("image")) {
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::image) {
|
||||
// Parse error. Change the token's tag name to HTML::TagNames::img and reprocess it. (Don't ask.)
|
||||
PARSE_ERROR();
|
||||
token.m_tag.tag_name.clear();
|
||||
|
@ -1361,24 +1416,54 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
|||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::rb, HTML::TagNames::rtc)) {
|
||||
TODO();
|
||||
if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::ruby))
|
||||
generate_implied_end_tags();
|
||||
|
||||
if (current_node().tag_name() != HTML::TagNames::ruby)
|
||||
PARSE_ERROR();
|
||||
|
||||
insert_html_element(token);
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::rp, HTML::TagNames::rt)) {
|
||||
TODO();
|
||||
if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::ruby))
|
||||
generate_implied_end_tags(HTML::TagNames::rtc);
|
||||
|
||||
if (current_node().tag_name() != HTML::TagNames::rtc || current_node().tag_name() != HTML::TagNames::ruby)
|
||||
PARSE_ERROR();
|
||||
|
||||
insert_html_element(token);
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == "math") {
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::math) {
|
||||
dbg() << "<math> element encountered.";
|
||||
reconstruct_the_active_formatting_elements();
|
||||
adjust_mathml_attributes(token);
|
||||
adjust_foreign_attributes(token);
|
||||
|
||||
// FIXME: this should insert a foreign element, but lets just insert it normally for now :^)
|
||||
insert_html_element(token);
|
||||
|
||||
if (token.is_self_closing()) {
|
||||
m_stack_of_open_elements.pop();
|
||||
token.acknowledge_self_closing_flag_if_set();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == "svg") {
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::svg) {
|
||||
dbg() << "<svg> element encountered.";
|
||||
reconstruct_the_active_formatting_elements();
|
||||
adjust_svg_attributes(token);
|
||||
adjust_foreign_attributes(token);
|
||||
|
||||
// FIXME: this should insert a foreign element, but lets just insert it normally for now :^)
|
||||
insert_html_element(token);
|
||||
|
||||
if (token.is_self_closing()) {
|
||||
m_stack_of_open_elements.pop();
|
||||
token.acknowledge_self_closing_flag_if_set();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1418,7 +1503,92 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
|
||||
TODO();
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::adjust_mathml_attributes(HTMLToken& token)
|
||||
{
|
||||
token.adjust_attribute_name("definitionurl", "definitionURL");
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::adjust_svg_attributes(HTMLToken& token)
|
||||
{
|
||||
token.adjust_attribute_name("attributename", "attributeName");
|
||||
token.adjust_attribute_name("attributetype", "attributeType");
|
||||
token.adjust_attribute_name("basefrequency", "baseFrequency");
|
||||
token.adjust_attribute_name("baseprofile", "baseProfile");
|
||||
token.adjust_attribute_name("calcmode", "calcMode");
|
||||
token.adjust_attribute_name("clippathunits", "clipPathUnits");
|
||||
token.adjust_attribute_name("diffuseconstant", "diffuseConstant");
|
||||
token.adjust_attribute_name("edgemode", "edgeMode");
|
||||
token.adjust_attribute_name("filterunits", "filterUnits");
|
||||
token.adjust_attribute_name("glyphref", "glyphRef");
|
||||
token.adjust_attribute_name("gradienttransform", "gradientTransform");
|
||||
token.adjust_attribute_name("gradientunits", "gradientUnits");
|
||||
token.adjust_attribute_name("kernelmatrix", "kernelMatrix");
|
||||
token.adjust_attribute_name("kernelunitlength", "kernelUnitLength");
|
||||
token.adjust_attribute_name("keypoints", "keyPoints");
|
||||
token.adjust_attribute_name("keysplines", "keySplines");
|
||||
token.adjust_attribute_name("keytimes", "keyTimes");
|
||||
token.adjust_attribute_name("lengthadjust", "lengthAdjust");
|
||||
token.adjust_attribute_name("limitingconeangle", "limitingConeAngle");
|
||||
token.adjust_attribute_name("markerheight", "markerHeight");
|
||||
token.adjust_attribute_name("markerunits", "markerUnits");
|
||||
token.adjust_attribute_name("markerwidth", "markerWidth");
|
||||
token.adjust_attribute_name("maskcontentunits", "maskContentUnits");
|
||||
token.adjust_attribute_name("maskunits", "maskUnits");
|
||||
token.adjust_attribute_name("numoctaves", "numOctaves");
|
||||
token.adjust_attribute_name("pathlength", "pathLength");
|
||||
token.adjust_attribute_name("patterncontentunits", "patternContentUnits");
|
||||
token.adjust_attribute_name("patterntransform", "patternTransform");
|
||||
token.adjust_attribute_name("patternunits", "patternUnits");
|
||||
token.adjust_attribute_name("pointsatx", "pointsAtX");
|
||||
token.adjust_attribute_name("pointsaty", "pointsAtY");
|
||||
token.adjust_attribute_name("pointsatz", "pointsAtZ");
|
||||
token.adjust_attribute_name("preservealpha", "preserveAlpha");
|
||||
token.adjust_attribute_name("preserveaspectratio", "preserveAspectRatio");
|
||||
token.adjust_attribute_name("primitiveunits", "primitiveUnits");
|
||||
token.adjust_attribute_name("refx", "refX");
|
||||
token.adjust_attribute_name("refy", "refY");
|
||||
token.adjust_attribute_name("repeatcount", "repeatCount");
|
||||
token.adjust_attribute_name("repeatdur", "repeatDur");
|
||||
token.adjust_attribute_name("requiredextensions", "requiredExtensions");
|
||||
token.adjust_attribute_name("requiredfeatures", "requiredFeatures");
|
||||
token.adjust_attribute_name("specularconstant", "specularConstant");
|
||||
token.adjust_attribute_name("specularexponent", "specularExponent");
|
||||
token.adjust_attribute_name("spreadmethod", "spreadMethod");
|
||||
token.adjust_attribute_name("startoffset", "startOffset");
|
||||
token.adjust_attribute_name("stddeviation", "stdDeviation");
|
||||
token.adjust_attribute_name("stitchtiles", "stitchTiles");
|
||||
token.adjust_attribute_name("surfacescale", "surfaceScale");
|
||||
token.adjust_attribute_name("systemlanguage", "systemLanguage");
|
||||
token.adjust_attribute_name("tablevalues", "tableValues");
|
||||
token.adjust_attribute_name("targetx", "targetX");
|
||||
token.adjust_attribute_name("targety", "targetY");
|
||||
token.adjust_attribute_name("textlength", "textLength");
|
||||
token.adjust_attribute_name("viewbox", "viewBox");
|
||||
token.adjust_attribute_name("viewtarget", "viewTarget");
|
||||
token.adjust_attribute_name("xchannelselector", "xChannelSelector");
|
||||
token.adjust_attribute_name("ychannelselector", "yChannelSelector");
|
||||
token.adjust_attribute_name("zoomandpan", "zoomAndPan");
|
||||
}
|
||||
void HTMLDocumentParser::adjust_foreign_attributes(HTMLToken& token)
|
||||
{
|
||||
auto xlink_namespace = "http://www.w3.org/1999/xlink";
|
||||
token.adjust_foreign_attribute("xlink:actuate", "xlink", "actuate", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:arcrole", "xlink", "arcrole", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:href", "xlink", "href", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:role", "xlink", "role", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:show", "xlink", "show", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:title", "xlink", "title", xlink_namespace);
|
||||
token.adjust_foreign_attribute("xlink:type", "xlink", "type", xlink_namespace);
|
||||
|
||||
auto xml_namespace = "http://www.w3.org/XML/1998/namespace";
|
||||
token.adjust_foreign_attribute("xml:lang", "xml", "lang", xml_namespace);
|
||||
token.adjust_foreign_attribute("xml:space", "xml", "space", xml_namespace);
|
||||
|
||||
auto xmlns_namespace = "http://www.w3.org/2000/xmlns/";
|
||||
token.adjust_foreign_attribute("xmlns", "", "xmlns", xmlns_namespace);
|
||||
token.adjust_foreign_attribute("xmlns:xlink", "xmlns", "xlink", xmlns_namespace);
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::increment_script_nesting_level()
|
||||
|
@ -1714,7 +1884,13 @@ void HTMLDocumentParser::handle_in_table_body(HTMLToken& token)
|
|||
|
||||
if ((token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::col, HTML::TagNames::colgroup, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead))
|
||||
|| (token.is_end_tag() && token.tag_name() == HTML::TagNames::table)) {
|
||||
// FIXME: If the stack of open elements does not have a tbody, thead, or tfoot element in table scope, this is a parse error; ignore the token.
|
||||
|
||||
if (!m_stack_of_open_elements.has_in_table_scope(HTML::TagNames::tbody)
|
||||
|| !m_stack_of_open_elements.has_in_table_scope(HTML::TagNames::thead)
|
||||
|| !m_stack_of_open_elements.has_in_table_scope(HTML::TagNames::tfoot)) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
clear_the_stack_back_to_a_table_body_context();
|
||||
m_stack_of_open_elements.pop();
|
||||
|
@ -1814,7 +1990,7 @@ void HTMLDocumentParser::handle_in_table(HTMLToken& token)
|
|||
return;
|
||||
}
|
||||
if ((token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::style, HTML::TagNames::script, HTML::TagNames::template_))
|
||||
|| (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_)) {
|
||||
|| (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_)) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
@ -1860,8 +2036,27 @@ AnythingElse:
|
|||
|
||||
void HTMLDocumentParser::handle_in_select_in_table(HTMLToken& token)
|
||||
{
|
||||
(void)token;
|
||||
TODO();
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr, HTML::TagNames::td, HTML::TagNames::th)) {
|
||||
PARSE_ERROR();
|
||||
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
|
||||
reset_the_insertion_mode_appropriately();
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr, HTML::TagNames::td, HTML::TagNames::th)) {
|
||||
PARSE_ERROR();
|
||||
|
||||
if (!m_stack_of_open_elements.has_in_table_scope(token.tag_name()))
|
||||
return;
|
||||
|
||||
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
|
||||
reset_the_insertion_mode_appropriately();
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
process_using_the_rules_for(InsertionMode::InSelect, token);
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_in_select(HTMLToken& token)
|
||||
|
@ -2005,7 +2200,7 @@ void HTMLDocumentParser::handle_in_caption(HTMLToken& token)
|
|||
}
|
||||
|
||||
if ((token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::col, HTML::TagNames::colgroup, HTML::TagNames::tbody, HTML::TagNames::td, HTML::TagNames::tfoot, HTML::TagNames::th, HTML::TagNames::thead, HTML::TagNames::tr))
|
||||
|| (token.is_end_tag() && token.tag_name() == HTML::TagNames::table)) {
|
||||
|| (token.is_end_tag() && token.tag_name() == HTML::TagNames::table)) {
|
||||
if (!m_stack_of_open_elements.has_in_table_scope(HTML::TagNames::caption)) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
|
@ -2097,6 +2292,209 @@ void HTMLDocumentParser::handle_in_column_group(HTMLToken& token)
|
|||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_in_template(HTMLToken& token)
|
||||
{
|
||||
if (token.is_character() || token.is_comment() || token.is_doctype()) {
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::base, HTML::TagNames::basefont, HTML::TagNames::bgsound, HTML::TagNames::link, HTML::TagNames::meta, HTML::TagNames::noframes, HTML::TagNames::script, HTML::TagNames::style, HTML::TagNames::template_, HTML::TagNames::title)) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::colgroup, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead)) {
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
m_stack_of_template_insertion_modes.append(InsertionMode::InTable);
|
||||
m_insertion_mode = InsertionMode::InTable;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::col) {
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
m_stack_of_template_insertion_modes.append(InsertionMode::InColumnGroup);
|
||||
m_insertion_mode = InsertionMode::InColumnGroup;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::tr) {
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
m_stack_of_template_insertion_modes.append(InsertionMode::InTableBody);
|
||||
m_insertion_mode = InsertionMode::InTableBody;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th)) {
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
m_stack_of_template_insertion_modes.append(InsertionMode::InRow);
|
||||
m_insertion_mode = InsertionMode::InRow;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag()) {
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
m_stack_of_template_insertion_modes.append(InsertionMode::InBody);
|
||||
m_insertion_mode = InsertionMode::InBody;
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag()) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
if (!m_stack_of_open_elements.contains(HTML::TagNames::template_)) {
|
||||
stop_parsing();
|
||||
} else {
|
||||
PARSE_ERROR();
|
||||
}
|
||||
|
||||
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::template_);
|
||||
m_list_of_active_formatting_elements.clear_up_to_the_last_marker();
|
||||
m_stack_of_template_insertion_modes.take_last();
|
||||
reset_the_insertion_mode_appropriately();
|
||||
process_using_the_rules_for(m_insertion_mode, token);
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_in_frameset(HTMLToken& token)
|
||||
{
|
||||
if (token.is_character() && token.is_parser_whitespace()) {
|
||||
insert_character(token.codepoint());
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_comment()) {
|
||||
insert_comment(token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_doctype()) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::html) {
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::frameset) {
|
||||
insert_html_element(token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::frameset) {
|
||||
// FIXME: If the current node is the root html element, then this is a parse error; ignore the token. (fragment case)
|
||||
|
||||
m_stack_of_open_elements.pop();
|
||||
|
||||
if (m_parsing_fragment && current_node().tag_name() != HTML::TagNames::frameset) {
|
||||
m_insertion_mode = InsertionMode::AfterFrameset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::frame) {
|
||||
insert_html_element(token);
|
||||
m_stack_of_open_elements.pop();
|
||||
token.acknowledge_self_closing_flag_if_set();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noframes) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
//FIXME: If the current node is not the root html element, then this is a parse error.
|
||||
|
||||
stop_parsing();
|
||||
return;
|
||||
}
|
||||
|
||||
PARSE_ERROR();
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_after_frameset(HTMLToken& token)
|
||||
{
|
||||
if (token.is_character() && token.is_parser_whitespace()) {
|
||||
insert_character(token.codepoint());
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_comment()) {
|
||||
insert_comment(token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_doctype()) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::html) {
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::html) {
|
||||
m_insertion_mode = InsertionMode::AfterAfterFrameset;
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noframes) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
stop_parsing();
|
||||
return;
|
||||
}
|
||||
|
||||
PARSE_ERROR();
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::handle_after_after_frameset(HTMLToken& token)
|
||||
{
|
||||
if (token.is_comment()) {
|
||||
auto comment = adopt(*new Comment(document(), token.m_comment_or_character.data.to_string()));
|
||||
document().append_child(move(comment));
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_doctype() || token.is_parser_whitespace() || (token.is_start_tag() && token.tag_name() == HTML::TagNames::html)) {
|
||||
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_end_of_file()) {
|
||||
stop_parsing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noframes) {
|
||||
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||
return;
|
||||
}
|
||||
|
||||
PARSE_ERROR();
|
||||
}
|
||||
|
||||
void HTMLDocumentParser::reset_the_insertion_mode_appropriately()
|
||||
{
|
||||
for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) {
|
||||
|
|
|
@ -100,6 +100,10 @@ private:
|
|||
void handle_in_select(HTMLToken&);
|
||||
void handle_in_caption(HTMLToken&);
|
||||
void handle_in_column_group(HTMLToken&);
|
||||
void handle_in_template(HTMLToken&);
|
||||
void handle_in_frameset(HTMLToken&);
|
||||
void handle_after_frameset(HTMLToken&);
|
||||
void handle_after_after_frameset(HTMLToken&);
|
||||
|
||||
void stop_parsing() { m_stop_parsing = true; }
|
||||
|
||||
|
@ -123,6 +127,10 @@ private:
|
|||
size_t script_nesting_level() const { return m_script_nesting_level; }
|
||||
void reset_the_insertion_mode_appropriately();
|
||||
|
||||
void adjust_mathml_attributes(HTMLToken&);
|
||||
void adjust_svg_attributes(HTMLToken&);
|
||||
void adjust_foreign_attributes(HTMLToken&);
|
||||
|
||||
enum AdoptionAgencyAlgorithmOutcome {
|
||||
DoNothing,
|
||||
RunAnyOtherEndTagSteps,
|
||||
|
@ -138,6 +146,7 @@ private:
|
|||
InsertionMode m_original_insertion_mode { InsertionMode::Initial };
|
||||
|
||||
StackOfOpenElements m_stack_of_open_elements;
|
||||
Vector<InsertionMode> m_stack_of_template_insertion_modes;
|
||||
ListOfActiveFormattingElements m_list_of_active_formatting_elements;
|
||||
|
||||
HTMLTokenizer m_tokenizer;
|
||||
|
|
|
@ -63,7 +63,7 @@ String HTMLToken::to_string() const
|
|||
builder.append(m_tag.tag_name.to_string());
|
||||
builder.append("', { ");
|
||||
for (auto& attribute : m_tag.attributes) {
|
||||
builder.append(attribute.name_builder.to_string());
|
||||
builder.append(attribute.local_name_builder.to_string());
|
||||
builder.append("=\"");
|
||||
builder.append(attribute.value_builder.to_string());
|
||||
builder.append("\" ");
|
||||
|
|
|
@ -118,12 +118,40 @@ public:
|
|||
{
|
||||
ASSERT(is_start_tag() || is_end_tag());
|
||||
for (auto& attribute : m_tag.attributes) {
|
||||
if (attribute_name == attribute.name_builder.string_view())
|
||||
if (attribute_name == attribute.local_name_builder.string_view())
|
||||
return attribute.value_builder.string_view();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void adjust_attribute_name(const FlyString& old_name, const FlyString& new_name)
|
||||
{
|
||||
ASSERT(is_start_tag() || is_end_tag());
|
||||
for (auto& attribute : m_tag.attributes) {
|
||||
if (old_name == attribute.local_name_builder.string_view()) {
|
||||
attribute.local_name_builder.clear();
|
||||
attribute.local_name_builder.append(new_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adjust_foreign_attribute(const FlyString& old_name, const FlyString& prefix, const FlyString& local_name, const FlyString& namespace_)
|
||||
{
|
||||
ASSERT(is_start_tag() || is_end_tag());
|
||||
for (auto& attribute : m_tag.attributes) {
|
||||
if (old_name == attribute.local_name_builder.string_view()) {
|
||||
attribute.prefix_builder.clear();
|
||||
attribute.prefix_builder.append(prefix);
|
||||
|
||||
attribute.local_name_builder.clear();
|
||||
attribute.local_name_builder.append(local_name);
|
||||
|
||||
attribute.namespace_builder.clear();
|
||||
attribute.namespace_builder.append(namespace_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drop_attributes()
|
||||
{
|
||||
ASSERT(is_start_tag() || is_end_tag());
|
||||
|
@ -136,7 +164,9 @@ public:
|
|||
|
||||
private:
|
||||
struct AttributeBuilder {
|
||||
StringBuilder name_builder;
|
||||
StringBuilder prefix_builder;
|
||||
StringBuilder local_name_builder;
|
||||
StringBuilder namespace_builder;
|
||||
StringBuilder value_builder;
|
||||
};
|
||||
|
||||
|
|
|
@ -1037,7 +1037,7 @@ _StartOfFunction:
|
|||
}
|
||||
ANYTHING_ELSE
|
||||
{
|
||||
m_current_token.m_tag.attributes.last().name_builder.append_codepoint(current_input_character.value());
|
||||
m_current_token.m_tag.attributes.last().local_name_builder.append_codepoint(current_input_character.value());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue