Skip to content

Commit d68b404

Browse files
committed
Iterate on active formatting
1 parent d366f16 commit d68b404

2 files changed

Lines changed: 73 additions & 35 deletions

File tree

src/wp-includes/html-api/class-wp-html-active-formatting-elements.php

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class WP_HTML_Active_Formatting_Elements {
3939
*
4040
* @since 6.4.0
4141
*
42-
* @var WP_HTML_Token[]
42+
* @var Array<AFE_Element|AFE_Marker>
4343
*/
4444
private $stack = array();
4545

@@ -53,9 +53,9 @@ class WP_HTML_Active_Formatting_Elements {
5353
* @access private
5454
*
5555
* @param int $index Number of nodes from the top node to return.
56-
* @return WP_HTML_Token|null Node at the given index in the stack, if one exists, otherwise null.
56+
* @return AFE_Element|AFE_Marker|null Node at the given index in the stack, if one exists, otherwise null.
5757
*/
58-
public function at( $nth ) {
58+
public function at( $nth ): AFE_Element|AFE_Marker|null {
5959
return $this->stack[ $nth - 1 ];
6060
}
6161

@@ -67,9 +67,9 @@ public function at( $nth ) {
6767
* @param WP_HTML_Token $token Look for this node in the stack.
6868
* @return bool Whether the referenced node is in the stack of active formatting elements.
6969
*/
70-
public function contains_node( WP_HTML_Token $token ) {
70+
public function contains_node( WP_HTML_Token $token ): bool {
7171
foreach ( $this->walk_up() as $item ) {
72-
if ( $token->bookmark_name === $item->bookmark_name ) {
72+
if ( $item instanceof AFE_Element && $token->bookmark_name === $item->token->bookmark_name ) {
7373
return true;
7474
}
7575
}
@@ -103,7 +103,7 @@ public function current_node() {
103103
}
104104

105105
/**
106-
* Inserts a "marker" at the end of the list of active formatting elements.
106+
* Inserts a marker at the end of the list of active formatting elements.
107107
*
108108
* > The markers are inserted when entering applet, object, marquee,
109109
* > template, td, th, and caption elements, and are used to prevent
@@ -115,7 +115,7 @@ public function current_node() {
115115
* @since 6.7.0
116116
*/
117117
public function insert_marker(): void {
118-
$this->push( new WP_HTML_Token( null, 'marker', false ) );
118+
$this->push( new AFE_Marker() );
119119
}
120120

121121
/**
@@ -125,9 +125,9 @@ public function insert_marker(): void {
125125
*
126126
* @see https://html.spec.whatwg.org/#push-onto-the-list-of-active-formatting-elements
127127
*
128-
* @param WP_HTML_Token $token Push this node onto the stack.
128+
* @param AFE_Element|AFE_Marker $token Push this node onto the stack.
129129
*/
130-
public function push( WP_HTML_Token $token ) {
130+
public function push( AFE_Element|AFE_Marker $afe ): void {
131131
/*
132132
* > If there are already three elements in the list of active formatting elements after the last marker,
133133
* > if any, or anywhere in the list if there are no markers, that have the same tag name, namespace, and
@@ -139,21 +139,20 @@ public function push( WP_HTML_Token $token ) {
139139
*
140140
* @todo Implement the "Noah's Ark clause" to only add up to three of any given kind of formatting elements to the stack.
141141
*/
142-
// > Add element to the list of active formatting elements.
143-
$this->stack[] = $token;
142+
$this->stack[] = $afe;
144143
}
145144

146145
/**
147146
* Removes a node from the stack of active formatting elements.
148147
*
149148
* @since 6.4.0
150149
*
151-
* @param WP_HTML_Token $token Remove this node from the stack, if it's there already.
150+
* @param AFE_Element|AFE_Marker $node Remove this node from the stack, if it's there already.
152151
* @return bool Whether the node was found and removed from the stack of active formatting elements.
153152
*/
154-
public function remove_node( WP_HTML_Token $token ) {
153+
public function remove_node( AFE_Element $node ) {
155154
foreach ( $this->walk_up() as $position_from_end => $item ) {
156-
if ( $token->bookmark_name !== $item->bookmark_name ) {
155+
if ( $item instanceof AFE_Element && $node->token->bookmark_name !== $item->token->bookmark_name ) {
157156
continue;
158157
}
159158

@@ -237,9 +236,28 @@ public function walk_up() {
237236
public function clear_up_to_last_marker(): void {
238237
foreach ( $this->walk_up() as $item ) {
239238
array_pop( $this->stack );
240-
if ( 'marker' === $item->node_name ) {
239+
if ( $item instanceof AFE_Marker ) {
241240
break;
242241
}
243242
}
244243
}
245244
}
245+
246+
class AFE_Marker {}
247+
class AFE_Element {
248+
/** @var string */
249+
public $namespace;
250+
/** @var string */
251+
public $tag_name;
252+
/** @var array<string, string|bool|null> */
253+
public $attributes;
254+
/** @var WP_HTML_Token */
255+
public $token;
256+
257+
public function __construct( string $tag_namespace, string $tag_name, array $attributes, WP_HTML_Token $token ) {
258+
$this->namespace = $tag_namespace;
259+
$this->tag_name = $tag_name;
260+
$this->attributes = $attributes;
261+
$this->token = $token;
262+
}
263+
}

src/wp-includes/html-api/class-wp-html-processor.php

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ private function bail( string $message ) {
442442

443443
$active_formats = array();
444444
foreach ( $this->state->active_formatting_elements->walk_down() as $item ) {
445-
$active_formats[] = $item->node_name;
445+
$active_formats[] = $item instanceof AFE_Marker ? '(marker)' : $item->tag_name;
446446
}
447447

448448
$this->last_error = self::ERROR_UNSUPPORTED;
@@ -2350,10 +2350,10 @@ private function step_in_body(): bool {
23502350
*/
23512351
case '+A':
23522352
foreach ( $this->state->active_formatting_elements->walk_up() as $item ) {
2353-
switch ( $item->node_name ) {
2354-
case 'marker':
2355-
break;
2356-
2353+
if ( $item instanceof AFE_Marker ) {
2354+
break;
2355+
}
2356+
switch ( $item->tag_name ) {
23572357
case 'A':
23582358
$this->run_adoption_agency_algorithm();
23592359
$this->state->active_formatting_elements->remove_node( $item );
@@ -2364,7 +2364,7 @@ private function step_in_body(): bool {
23642364

23652365
$this->reconstruct_active_formatting_elements();
23662366
$this->insert_html_element( $this->state->current_token );
2367-
$this->state->active_formatting_elements->push( $this->state->current_token );
2367+
$this->push_active_formatting_element( $this->state->current_token );
23682368
return true;
23692369

23702370
/*
@@ -2385,7 +2385,7 @@ private function step_in_body(): bool {
23852385
case '+U':
23862386
$this->reconstruct_active_formatting_elements();
23872387
$this->insert_html_element( $this->state->current_token );
2388-
$this->state->active_formatting_elements->push( $this->state->current_token );
2388+
$this->push_active_formatting_element( $this->state->current_token );
23892389
return true;
23902390

23912391
/*
@@ -2401,7 +2401,7 @@ private function step_in_body(): bool {
24012401
}
24022402

24032403
$this->insert_html_element( $this->state->current_token );
2404-
$this->state->active_formatting_elements->push( $this->state->current_token );
2404+
$this->push_active_formatting_element( $this->state->current_token );
24052405
return true;
24062406

24072407
/*
@@ -5121,7 +5121,7 @@ public function seek( $bookmark_name ): bool {
51215121
}
51225122

51235123
foreach ( $this->state->active_formatting_elements->walk_up() as $item ) {
5124-
if ( 'context-node' === $item->bookmark_name ) {
5124+
if ( 'context-node' === $item->token->bookmark_name ) {
51255125
break;
51265126
}
51275127

@@ -5401,8 +5401,8 @@ private function reconstruct_active_formatting_elements(): bool {
54015401
* > elements, then there is nothing to reconstruct; stop this algorithm.
54025402
*/
54035403
if (
5404-
'marker' === $last_entry->node_name ||
5405-
$this->state->stack_of_open_elements->contains_node( $last_entry )
5404+
$last_entry instanceof AFE_Marker ||
5405+
$this->state->stack_of_open_elements->contains_node( $last_entry->token )
54065406
) {
54075407
return false;
54085408
}
@@ -5433,8 +5433,8 @@ private function reconstruct_active_formatting_elements(): bool {
54335433
* > the stack of open elements, go to the step labeled rewind.
54345434
*/
54355435
if (
5436-
'marker' !== $entry->node_name &&
5437-
! $this->state->stack_of_open_elements->contains_node( $entry )
5436+
! $entry instanceof AFE_Marker &&
5437+
! $this->state->stack_of_open_elements->contains_node( $entry->token )
54385438
) {
54395439
goto rewind;
54405440
}
@@ -5451,7 +5451,7 @@ private function reconstruct_active_formatting_elements(): bool {
54515451
* > element entry was created, to obtain new element.
54525452
*/
54535453
create:
5454-
$this->insert_html_element( $entry );
5454+
$this->insert_html_element( $entry->token );
54555455

54565456
/*
54575457
* > 9. Replace the entry for entry in the list with an entry for new element.
@@ -5690,11 +5690,11 @@ private function run_adoption_agency_algorithm(): void {
56905690
*/
56915691
$formatting_element = null;
56925692
foreach ( $this->state->active_formatting_elements->walk_up() as $item ) {
5693-
if ( 'marker' === $item->node_name ) {
5693+
if ( $item instanceof AFE_Marker ) {
56945694
break;
56955695
}
56965696

5697-
if ( $subject === $item->node_name ) {
5697+
if ( $subject === $item->tag_name ) {
56985698
$formatting_element = $item;
56995699
break;
57005700
}
@@ -5706,13 +5706,13 @@ private function run_adoption_agency_algorithm(): void {
57065706
}
57075707

57085708
// > 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.
5709-
if ( ! $this->state->stack_of_open_elements->contains_node( $formatting_element ) ) {
5709+
if ( ! $this->state->stack_of_open_elements->contains_node( $formatting_element->token ) ) {
57105710
$this->state->active_formatting_elements->remove_node( $formatting_element );
57115711
return;
57125712
}
57135713

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

@@ -5723,7 +5723,7 @@ private function run_adoption_agency_algorithm(): void {
57235723
$is_above_formatting_element = true;
57245724
$furthest_block = null;
57255725
foreach ( $this->state->stack_of_open_elements->walk_down() as $item ) {
5726-
if ( $is_above_formatting_element && $formatting_element->bookmark_name !== $item->bookmark_name ) {
5726+
if ( $is_above_formatting_element && $formatting_element->token->bookmark_name !== $item->bookmark_name ) {
57275727
continue;
57285728
}
57295729

@@ -5747,7 +5747,7 @@ private function run_adoption_agency_algorithm(): void {
57475747
foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) {
57485748
$this->state->stack_of_open_elements->pop();
57495749

5750-
if ( $formatting_element->bookmark_name === $item->bookmark_name ) {
5750+
if ( $formatting_element->token->bookmark_name === $item->bookmark_name ) {
57515751
$this->state->active_formatting_elements->remove_node( $formatting_element );
57525752
return;
57535753
}
@@ -6211,4 +6211,24 @@ protected static function get_encoding( string $label ): ?string {
62116211
* @access private
62126212
*/
62136213
const CONSTRUCTOR_UNLOCK_CODE = 'Use WP_HTML_Processor::create_fragment() instead of calling the class constructor directly.';
6214+
6215+
private function push_active_formatting_element( WP_HTML_Token $token ) {
6216+
$bookmark = $this->bookmarks[ $token->bookmark_name ];
6217+
$proc = new WP_HTML_Tag_Processor(
6218+
substr( $this->html, $bookmark->start, $bookmark->length )
6219+
);
6220+
$proc->change_parsing_namespace( $token->namespace );
6221+
$proc->next_tag();
6222+
$attributes = array();
6223+
foreach ( $proc->get_attribute_names_with_prefix( '' ) as $name ) {
6224+
$attributes[ $name ] = $proc->get_attribute( $name );
6225+
}
6226+
$afe = new AFE_Element(
6227+
$token->namespace,
6228+
$token->node_name,
6229+
$attributes,
6230+
$token
6231+
);
6232+
$this->state->active_formatting_elements->push( $afe );
6233+
}
62146234
}

0 commit comments

Comments
 (0)