mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:12:44 +00:00 
			
		
		
		
	LibWeb: Support parsing "select" elements (outside of tables)
This commit is contained in:
		
							parent
							
								
									60352c7b9b
								
							
						
					
					
						commit
						ca6fbefbc9
					
				
					 4 changed files with 173 additions and 2 deletions
				
			
		|  | @ -141,6 +141,12 @@ void HTMLDocumentParser::process_using_the_rules_for(InsertionMode mode, HTMLTok | ||||||
|     case InsertionMode::InTableText: |     case InsertionMode::InTableText: | ||||||
|         handle_in_table_text(token); |         handle_in_table_text(token); | ||||||
|         break; |         break; | ||||||
|  |     case InsertionMode::InSelectInTable: | ||||||
|  |         handle_in_select_in_table(token); | ||||||
|  |         break; | ||||||
|  |     case InsertionMode::InSelect: | ||||||
|  |         handle_in_select(token); | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         ASSERT_NOT_REACHED(); |         ASSERT_NOT_REACHED(); | ||||||
|     } |     } | ||||||
|  | @ -220,6 +226,11 @@ Element& HTMLDocumentParser::current_node() | ||||||
|     return m_stack_of_open_elements.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() | RefPtr<Node> HTMLDocumentParser::find_appropriate_place_for_inserting_node() | ||||||
| { | { | ||||||
|     auto& target = current_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") { |     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")) { |     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")) { |     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")) |     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(); |     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() | void HTMLDocumentParser::reset_the_insertion_mode_appropriately() | ||||||
| { | { | ||||||
|     for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) { |     for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) { | ||||||
|  |  | ||||||
|  | @ -96,6 +96,8 @@ private: | ||||||
|     void handle_in_row(HTMLToken&); |     void handle_in_row(HTMLToken&); | ||||||
|     void handle_in_cell(HTMLToken&); |     void handle_in_cell(HTMLToken&); | ||||||
|     void handle_in_table_text(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; } |     void stop_parsing() { m_stop_parsing = true; } | ||||||
| 
 | 
 | ||||||
|  | @ -105,6 +107,7 @@ private: | ||||||
|     RefPtr<Node> find_appropriate_place_for_inserting_node(); |     RefPtr<Node> find_appropriate_place_for_inserting_node(); | ||||||
|     RefPtr<Element> insert_html_element(HTMLToken&); |     RefPtr<Element> insert_html_element(HTMLToken&); | ||||||
|     Element& current_node(); |     Element& current_node(); | ||||||
|  |     Element& node_before_current_node(); | ||||||
|     void insert_character(u32 data); |     void insert_character(u32 data); | ||||||
|     void insert_comment(HTMLToken&); |     void insert_comment(HTMLToken&); | ||||||
|     void reconstruct_the_active_formatting_elements(); |     void reconstruct_the_active_formatting_elements(); | ||||||
|  |  | ||||||
|  | @ -94,6 +94,14 @@ bool StackOfOpenElements::has_in_list_item_scope(const FlyString& tag_name) cons | ||||||
|     return has_in_scope_impl(tag_name, list); |     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 | bool StackOfOpenElements::contains(const Element& element) const | ||||||
| { | { | ||||||
|     for (auto& element_on_stack : m_elements) { |     for (auto& element_on_stack : m_elements) { | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ public: | ||||||
|     bool has_in_button_scope(const FlyString& tag_name) const; |     bool has_in_button_scope(const FlyString& tag_name) const; | ||||||
|     bool has_in_table_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_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; |     bool has_in_scope(const Element&) const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling