Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML API: Work on 62583 #7904

Draft
wants to merge 6 commits into
base: trunk
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 72 additions & 15 deletions src/wp-includes/html-api/class-wp-html-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,11 @@ private function next_visitable_token(): bool {
* until there are events or until there are no more
* tokens works in the meantime and isn't obviously wrong.
*/
if ( empty( $this->element_queue ) && $this->step() ) {
return $this->next_visitable_token();
if ( empty( $this->element_queue ) ) {
if ( $this->step() ) {
assert( array() !== $this->element_queue );
return $this->next_visitable_token();
}
Comment on lines +766 to +770
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for debugging and is never intended to be merged.

}

// Process the next event on the queue.
Expand Down Expand Up @@ -2290,7 +2293,14 @@ private function step_in_body(): bool {
*/

$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_BODY;
return true;
/*
* The BODY element is not removed from the stack of open elements.
* Only internal state has changed, this does not qualify as a "step"
* in terms of advancing through the document to another token.
* Nothing has been pushed or popped.
* Proceed to parse the next item.
*/
return $this->step();

/*
* > An end tag whose tag name is "html"
Expand Down Expand Up @@ -2769,8 +2779,15 @@ private function step_in_body(): bool {
case '-STRONG':
case '-TT':
case '-U':
$this->run_adoption_agency_algorithm();
return true;
/*
* Only return if the adoption_agency_algorithm modifies the
* stack of open elements.
* Otherwise, proceed.
*/
if ( $this->run_adoption_agency_algorithm() ) {
return true;
}
return $this->step();

/*
* > A start tag whose tag name is one of: "applet", "marquee", "object"
Expand Down Expand Up @@ -4363,7 +4380,14 @@ private function step_after_body(): bool {
}

$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_AFTER_BODY;
return true;
/*
* The HTML element is not removed from the stack of open elements.
* Only internal state has changed, this does not qualify as a "step"
* in terms of advancing through the document to another token.
* Nothing has been pushed or popped.
* Proceed to parse the next item.
*/
return $this->step();
}

/*
Expand Down Expand Up @@ -4558,7 +4582,14 @@ private function step_after_frameset(): bool {
*/
case '-HTML':
$this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_AFTER_FRAMESET;
return true;
/*
* The HTML element is not removed from the stack of open elements.
* Only internal state has changed, this does not qualify as a "step"
* in terms of advancing through the document to another token.
* Nothing has been pushed or popped.
* Proceed to parse the next item.
*/
return $this->step();

/*
* > A start tag whose tag name is "noframes"
Expand Down Expand Up @@ -4910,13 +4941,35 @@ private function step_in_foreign_content(): bool {
* > Any other end tag
*/
if ( $this->is_tag_closer() ) {
/*
* > Run these steps:
* >
* > 1. Initialize node to be the current node (the bottommost node of the stack).
* > 2. If node's tag name, converted to ASCII lowercase, is not the same as
* > the tag name of the token, then this is a parse error.
* > 3. Loop: If node is the topmost element in the stack of open elements,
* > then return. (fragment case)
* > 4. If node's tag name, converted to ASCII lowercase, is the same as the
* > tag name of the token, pop elements from the stack of open elements
* > until node has been popped from the stack, and then return.
* > 5. Set node to the previous entry in the stack of open elements.
* > 6. If node is not an element in the HTML namespace, return to the step
* > labeled loop.
* > 7. Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content.
*/

$node = $this->state->stack_of_open_elements->current_node();
if ( $tag_name !== $node->node_name ) {
// @todo Indicate a parse error once it's possible.
}

$has_modified = false;
in_foreign_content_end_tag_loop:
if ( $node === $this->state->stack_of_open_elements->at( 1 ) ) {
return true;
if ( $has_modified ) {
return true;
}
return $this->step();
}

/*
Expand All @@ -4930,6 +4983,7 @@ private function step_in_foreign_content(): bool {
if ( $node === $item ) {
return true;
}
$has_modified = true;
}
}

Expand Down Expand Up @@ -6004,8 +6058,10 @@ private function reset_insertion_mode_appropriately(): void {
* @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input.
*
* @see https://html.spec.whatwg.org/#adoption-agency-algorithm
*
* @return bool Whether the algorithm has modified the stack of open elements.
*/
private function run_adoption_agency_algorithm(): void {
private function run_adoption_agency_algorithm(): bool {
$budget = 1000;
$subject = $this->get_tag();
$current_node = $this->state->stack_of_open_elements->current_node();
Expand All @@ -6017,13 +6073,14 @@ private function run_adoption_agency_algorithm(): void {
! $this->state->active_formatting_elements->contains_node( $current_node )
) {
$this->state->stack_of_open_elements->pop();
return;
return true;
}

$outer_loop_counter = 0;
$has_modified = false;
while ( $budget-- > 0 ) {
if ( $outer_loop_counter++ >= 8 ) {
return;
return $has_modified;
}

/*
Expand Down Expand Up @@ -6052,12 +6109,12 @@ private function run_adoption_agency_algorithm(): void {
// > If formatting element is not in the stack of open elements, then this is a parse error; remove the element from the list, and return.
if ( ! $this->state->stack_of_open_elements->contains_node( $formatting_element ) ) {
$this->state->active_formatting_elements->remove_node( $formatting_element );
return;
return $has_modified;
}

// > If formatting element is in the stack of open elements, but the element is not in scope, then this is a parse error; return.
if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $formatting_element->node_name ) ) {
return;
return $has_modified;
}

/*
Expand Down Expand Up @@ -6090,11 +6147,11 @@ private function run_adoption_agency_algorithm(): void {
if ( null === $furthest_block ) {
foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) {
$this->state->stack_of_open_elements->pop();

if ( $formatting_element->bookmark_name === $item->bookmark_name ) {
$this->state->active_formatting_elements->remove_node( $formatting_element );
return;
return true;
}
$has_modified = true;
}
}

Expand Down
Loading