HTML API: expect_closer() should report false for self-closing foreign elements.

Previously, `WP_HTML_Processor::expects_closer()` would report `true` for self-closing foreign elements when called without supplying a node in question, but it should have been reporting `true` just as it does for HTML elements.

This patch adds a test case demonstrating the issue and a bugfix.

The `html5lib` test runner was relying on the incorrect behavior, accidentally working. This is also corrected and the `html5lib` test now relies on the correct behavior of `expects_closer()`.

Developed in https://github.com/wordpress/wordpress-develop/pull/7162
Discussed in https://core.trac.wordpress.org/ticket/61576

Follow-up to [58868].

Props: dmsnell.
See #61576.


git-svn-id: https://develop.svn.wordpress.org/trunk@58870 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dennis Snell 2024-08-08 16:13:25 +00:00
parent fe9aa7c48d
commit b9014d69e3
4 changed files with 26 additions and 14 deletions

View File

@ -786,13 +786,15 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
* or `null` if not matched on any token.
*/
public function expects_closer( WP_HTML_Token $node = null ): ?bool {
$token_name = $node->node_name ?? $this->get_token_name();
$token_namespace = $node->namespace ?? $this->get_namespace();
$token_name = $node->node_name ?? $this->get_token_name();
if ( ! isset( $token_name ) ) {
return null;
}
$token_namespace = $node->namespace ?? $this->get_namespace();
$token_has_self_closing = $node->has_self_closing_flag ?? $this->has_self_closing_flag();
return ! (
// Comments, text nodes, and other atomic tokens.
'#' === $token_name[0] ||
@ -803,7 +805,7 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
// Special atomic elements.
( 'html' === $token_namespace && in_array( $token_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) ||
// Self-closing elements in foreign content.
( isset( $node ) && 'html' !== $node->namespace && $node->has_self_closing_flag )
( 'html' !== $token_namespace && $token_has_self_closing )
);
}

View File

@ -2921,7 +2921,7 @@ class WP_HTML_Tag_Processor {
return null;
}
$namespace = $this->get_namespace();
$namespace = $this->get_namespace();
$lower_name = strtolower( $attribute_name );
if ( 'math' === $namespace && 'definitionurl' === $lower_name ) {

View File

@ -503,4 +503,22 @@ class Tests_HtmlApi_WpHtmlProcessor extends WP_UnitTestCase {
$subclass_processor = call_user_func( array( get_class( $subclass_instance ), 'create_fragment' ), '' );
$this->assertInstanceOf( get_class( $subclass_instance ), $subclass_processor, '::create_fragment did not return subclass instance.' );
}
/**
* Ensures that self-closing elements in foreign content properly report
* that they expect no closer.
*
* @ticket 61576
*/
public function test_expects_closer_foreign_content_self_closing() {
$processor = WP_HTML_Processor::create_fragment( '<svg /><math>' );
$this->assertTrue( $processor->next_tag() );
$this->assertSame( 'SVG', $processor->get_tag() );
$this->assertFalse( $processor->expects_closer() );
$this->assertTrue( $processor->next_tag() );
$this->assertSame( 'MATH', $processor->get_tag() );
$this->assertTrue( $processor->expects_closer() );
}
}

View File

@ -207,11 +207,7 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase {
$tag_indent = $indent_level;
if ( 'html' !== $namespace ) {
if ( ! $processor->has_self_closing_flag() ) {
++$indent_level;
}
} elseif ( ! WP_HTML_Processor::is_void( $tag_name ) ) {
if ( $processor->expects_closer() ) {
++$indent_level;
}
@ -275,7 +271,7 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase {
// Self-contained tags contain their inner contents as modifiable text.
$modifiable_text = $processor->get_modifiable_text();
if ( '' !== $modifiable_text ) {
$output .= str_repeat( $indent, $indent_level ) . "\"{$modifiable_text}\"\n";
$output .= str_repeat( $indent, $tag_indent + 1 ) . "\"{$modifiable_text}\"\n";
}
if ( 'html' === $namespace && 'TEMPLATE' === $token_name ) {
@ -283,10 +279,6 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase {
++$indent_level;
}
if ( ! $processor->is_void( $tag_name ) && ! $processor->expects_closer() ) {
--$indent_level;
}
break;
case '#cdata-section':