LibWeb: Support parsing "select" elements (outside of tables)

This commit is contained in:
Andreas Kling 2020-05-30 19:58:52 +02:00
parent 60352c7b9b
commit ca6fbefbc9
Notes: sideshowbarker 2024-07-19 05:56:12 +09:00
4 changed files with 173 additions and 2 deletions

View file

@ -141,6 +141,12 @@ void HTMLDocumentParser::process_using_the_rules_for(InsertionMode mode, HTMLTok
case InsertionMode::InTableText:
handle_in_table_text(token);
break;
case InsertionMode::InSelectInTable:
handle_in_select_in_table(token);
break;
case InsertionMode::InSelect:
handle_in_select(token);
break;
default:
ASSERT_NOT_REACHED();
}
@ -220,6 +226,11 @@ Element& HTMLDocumentParser::current_node()
return m_stack_of_open_elements.current_node();
}
Element& HTMLDocumentParser::node_before_current_node()
{
return m_stack_of_open_elements.elements().at(m_stack_of_open_elements.elements().size() - 2);
}
RefPtr<Node> HTMLDocumentParser::find_appropriate_place_for_inserting_node()
{
auto& target = current_node();
@ -1201,7 +1212,22 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
}
if (token.is_start_tag() && token.tag_name() == "select") {
TODO();
reconstruct_the_active_formatting_elements();
insert_html_element(token);
m_frameset_ok = false;
switch (m_insertion_mode) {
case InsertionMode::InTable:
case InsertionMode::InCaption:
case InsertionMode::InTableBody:
case InsertionMode::InRow:
case InsertionMode::InCell:
m_insertion_mode = InsertionMode::InSelectInTable;
break;
default:
m_insertion_mode = InsertionMode::InSelect;
break;
}
return;
}
if (token.is_start_tag() && token.tag_name().is_one_of("optgroup", "option")) {
@ -1539,7 +1565,14 @@ void HTMLDocumentParser::handle_in_table_body(HTMLToken& token)
}
if (token.is_end_tag() && token.tag_name().is_one_of("tbody", "tfoot", "thead")) {
TODO();
if (!m_stack_of_open_elements.has_in_table_scope(token.tag_name())) {
PARSE_ERROR();
return;
}
clear_the_stack_back_to_a_table_body_context();
m_stack_of_open_elements.pop();
m_insertion_mode = InsertionMode::InTable;
return;
}
if ((token.is_start_tag() && token.tag_name().is_one_of("caption", "col", "colgroup", "tbody", "tfoot", "thead"))
@ -1621,6 +1654,132 @@ void HTMLDocumentParser::handle_in_table(HTMLToken& token)
TODO();
}
void HTMLDocumentParser::handle_in_select_in_table(HTMLToken& token)
{
(void)token;
TODO();
}
void HTMLDocumentParser::handle_in_select(HTMLToken& token)
{
if (token.is_character()) {
if (token.codepoint() == 0) {
PARSE_ERROR();
return;
}
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") {
process_using_the_rules_for(InsertionMode::InBody, token);
return;
}
if (token.is_start_tag() && token.tag_name() == "option") {
if (current_node().tag_name() == "option") {
m_stack_of_open_elements.pop();
}
insert_html_element(token);
return;
}
if (token.is_start_tag() && token.tag_name() == "optgroup") {
if (current_node().tag_name() == "option") {
m_stack_of_open_elements.pop();
}
if (current_node().tag_name() == "optgroup") {
m_stack_of_open_elements.pop();
}
insert_html_element(token);
return;
}
if (token.is_end_tag() && token.tag_name() == "optgroup") {
if (current_node().tag_name() == "option" && node_before_current_node().tag_name() == "optgroup")
m_stack_of_open_elements.pop();
if (current_node().tag_name() == "optgroup") {
m_stack_of_open_elements.pop();
} else {
PARSE_ERROR();
return;
}
return;
}
if (token.is_end_tag() && token.tag_name() == "option") {
if (current_node().tag_name() == "option") {
m_stack_of_open_elements.pop();
} else {
PARSE_ERROR();
return;
}
return;
}
if (token.is_end_tag() && token.tag_name() == "select") {
if (m_stack_of_open_elements.has_in_select_scope("select")) {
PARSE_ERROR();
return;
}
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("select");
reset_the_insertion_mode_appropriately();
return;
}
if (token.is_start_tag() && token.tag_name() == "select") {
PARSE_ERROR();
if (!m_stack_of_open_elements.has_in_select_scope("select"))
return;
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("select");
reset_the_insertion_mode_appropriately();
return;
}
if (token.is_start_tag() && token.tag_name().is_one_of("input", "keygen", "textarea")) {
PARSE_ERROR();
if (!m_stack_of_open_elements.has_in_select_scope("select")) {
return;
}
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("select");
reset_the_insertion_mode_appropriately();
process_using_the_rules_for(m_insertion_mode, token);
return;
}
if (token.is_start_tag() && token.tag_name().is_one_of("script", "template")) {
process_using_the_rules_for(InsertionMode::InHead, token);
return;
}
if (token.is_end_tag() && token.tag_name() == "template") {
process_using_the_rules_for(InsertionMode::InHead, token);
return;
}
if (token.is_end_of_file()) {
process_using_the_rules_for(InsertionMode::InBody, 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) {

View file

@ -96,6 +96,8 @@ private:
void handle_in_row(HTMLToken&);
void handle_in_cell(HTMLToken&);
void handle_in_table_text(HTMLToken&);
void handle_in_select_in_table(HTMLToken&);
void handle_in_select(HTMLToken&);
void stop_parsing() { m_stop_parsing = true; }
@ -105,6 +107,7 @@ private:
RefPtr<Node> find_appropriate_place_for_inserting_node();
RefPtr<Element> insert_html_element(HTMLToken&);
Element& current_node();
Element& node_before_current_node();
void insert_character(u32 data);
void insert_comment(HTMLToken&);
void reconstruct_the_active_formatting_elements();

View file

@ -94,6 +94,14 @@ bool StackOfOpenElements::has_in_list_item_scope(const FlyString& tag_name) cons
return has_in_scope_impl(tag_name, list);
}
bool StackOfOpenElements::has_in_select_scope(const FlyString& tag_name) const
{
auto list = s_base_list;
list.append("option");
list.append("optgroup");
return has_in_scope_impl(tag_name, list);
}
bool StackOfOpenElements::contains(const Element& element) const
{
for (auto& element_on_stack : m_elements) {

View file

@ -51,6 +51,7 @@ public:
bool has_in_button_scope(const FlyString& tag_name) const;
bool has_in_table_scope(const FlyString& tag_name) const;
bool has_in_list_item_scope(const FlyString& tag_name) const;
bool has_in_select_scope(const FlyString& tag_name) const;
bool has_in_scope(const Element&) const;