Make WordPress Core


Ignore:
Timestamp:
09/02/2024 11:19:08 PM (17 months ago)
Author:
dmsnell
Message:

HTML API: Allow subdividing text nodes by meaningful prefixes.

HTML parsing rules at times differentiate character tokens that are all null bytes, all whitespace, or other content. This patch introduces a new function which may be used to classify text node sub-regions and lead to more efficient application of these parsing rules.

Further, when classified in this way, application code may skip some rules and decoding entirely, improving performance. For example, this can be used to ease the implementation of skipping inter-element whitespace, which is usually not rendered.

Developed in https://github.com/WordPress/wordpress-develop/pull/7236
Discussed in https://core.trac.wordpress.org/ticket/61974

Props dmsnell, jonsurrell.
Fixes #61974.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/html-api/class-wp-html-processor.php

    r58967 r58970  
    844844        if ( self::PROCESS_NEXT_NODE === $node_to_process ) {
    845845            parent::next_token();
     846            if (
     847                WP_HTML_Tag_Processor::STATE_TEXT_NODE === $this->parser_state ||
     848                WP_HTML_Tag_Processor::STATE_CDATA_NODE === $this->parser_state
     849            ) {
     850                parent::subdivide_text_appropriately();
     851            }
    846852        }
    847853
     
    10571063             */
    10581064            case '#text':
    1059                 $text = $this->get_modifiable_text();
    1060                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1065                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    10611066                    return $this->step();
    10621067                }
     
    11461151             */
    11471152            case '#text':
    1148                 $text = $this->get_modifiable_text();
    1149                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1153                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    11501154                    return $this->step();
    11511155                }
     
    12281232             */
    12291233            case '#text':
    1230                 $text = $this->get_modifiable_text();
    1231                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1234                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    12321235                    return $this->step();
    12331236                }
     
    13241327                 * > U+000D CARRIAGE RETURN (CR), or U+0020 SPACE
    13251328                 */
    1326                 $text = $this->get_modifiable_text();
    1327                 if ( '' === $text ) {
    1328                     /*
    1329                      * If the text is empty after processing HTML entities and stripping
    1330                      * U+0000 NULL bytes then ignore the token.
    1331                      */
    1332                     return $this->step();
    1333                 }
    1334 
    1335                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1329                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    13361330                    // Insert the character.
    13371331                    $this->insert_html_element( $this->state->current_token );
     
    15531547             */
    15541548            case '#text':
    1555                 $text = $this->get_modifiable_text();
    1556                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1549                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    15571550                    return $this->step_in_head();
    15581551                }
     
    16551648             */
    16561649            case '#text':
    1657                 $text = $this->get_modifiable_text();
    1658                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     1650                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    16591651                    // Insert the character.
    16601652                    $this->insert_html_element( $this->state->current_token );
     
    17941786        switch ( $op ) {
    17951787            case '#text':
    1796                 $current_token = $this->bookmarks[ $this->state->current_token->bookmark_name ];
    1797 
    17981788                /*
    17991789                 * > A character token that is U+0000 NULL
     
    18051795                 * the active formats should be reconstructed.
    18061796                 */
    1807                 if (
    1808                     1 <= $current_token->length &&
    1809                     "\x00" === $this->html[ $current_token->start ] &&
    1810                     strspn( $this->html, "\x00", $current_token->start, $current_token->length ) === $current_token->length
    1811                 ) {
     1797                if ( parent::TEXT_IS_NULL_SEQUENCE === $this->text_node_classification ) {
    18121798                    // Parse error: ignore the token.
    18131799                    return $this->step();
     
    18211807                 * contain character references which decode only to whitespace.
    18221808                 */
    1823                 $text = $this->get_modifiable_text();
    1824                 if ( strlen( $text ) !== strspn( $text, " \t\n\f\r" ) ) {
     1809                if ( parent::TEXT_IS_GENERIC === $this->text_node_classification ) {
    18251810                    $this->state->frameset_ok = false;
    18261811                }
     
    28302815                    )
    28312816                ) {
    2832                     $text = $this->get_modifiable_text();
    28332817                    /*
    28342818                     * If the text is empty after processing HTML entities and stripping
    28352819                     * U+0000 NULL bytes then ignore the token.
    28362820                     */
    2837                     if ( '' === $text ) {
     2821                    if ( parent::TEXT_IS_NULL_SEQUENCE === $this->text_node_classification ) {
    28382822                        return $this->step();
    28392823                    }
     
    28582842                     * @see https://html.spec.whatwg.org/#parsing-main-intabletext
    28592843                     */
    2860                     if ( strlen( $text ) === strspn( $text, " \t\f\r\n" ) ) {
     2844                    if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    28612845                        $this->insert_html_element( $this->state->current_token );
    28622846                        return true;
     
    31783162             */
    31793163            case '#text':
    3180                 $text = $this->get_modifiable_text();
    3181                 if ( '' === $text ) {
    3182                     /*
    3183                      * If the text is empty after processing HTML entities and stripping
    3184                      * U+0000 NULL bytes then ignore the token.
    3185                      */
    3186                     return $this->step();
    3187                 }
    3188 
    3189                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     3164                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    31903165                    // Insert the character.
    31913166                    $this->insert_html_element( $this->state->current_token );
     
    36103585             */
    36113586            case '#text':
    3612                 $current_token = $this->bookmarks[ $this->state->current_token->bookmark_name ];
    3613 
    36143587                /*
    36153588                 * > A character token that is U+0000 NULL
     
    36183591                 * entirely ignored and should not return to calling code.
    36193592                 */
    3620                 if (
    3621                     1 <= $current_token->length &&
    3622                     "\x00" === $this->html[ $current_token->start ] &&
    3623                     strspn( $this->html, "\x00", $current_token->start, $current_token->length ) === $current_token->length
    3624                 ) {
     3593                if ( parent::TEXT_IS_NULL_SEQUENCE === $this->text_node_classification ) {
    36253594                    // Parse error: ignore the token.
    36263595                    return $this->step();
     
    39873956             */
    39883957            case '#text':
    3989                 $text = $this->get_modifiable_text();
    3990                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     3958                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    39913959                    return $this->step_in_body();
    39923960                }
     
    40734041             */
    40744042            case '#text':
    4075                 $text = $this->get_modifiable_text();
    4076                 $text = $this->get_modifiable_text();
    4077                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     4043                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    40784044                    return $this->step_in_body();
    40794045                }
     
    41944160             */
    41954161            case '#text':
    4196                 $text = $this->get_modifiable_text();
    4197                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     4162                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    41984163                    return $this->step_in_body();
    41994164                }
     
    42894254             */
    42904255            case '#text':
    4291                 $text = $this->get_modifiable_text();
    4292                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     4256                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    42934257                    return $this->step_in_body();
    42944258                }
     
    43564320             */
    43574321            case '#text':
    4358                 $text = $this->get_modifiable_text();
    4359                 if ( strlen( $text ) === strspn( $text, " \t\n\f\r" ) ) {
     4322                if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) {
    43604323                    return $this->step_in_body();
    43614324                }
     
    44134376
    44144377        switch ( $op ) {
     4378            case '#cdata-section':
    44154379            case '#text':
    44164380                /*
     
    44254389                 * contain character references which decode only to whitespace.
    44264390                 */
    4427                 $text = $this->get_modifiable_text();
    4428                 if ( strlen( $text ) !== strspn( $text, " \t\n\f\r" ) ) {
     4391                if ( parent::TEXT_IS_GENERIC === $this->text_node_classification ) {
    44294392                    $this->state->frameset_ok = false;
    44304393                }
     
    44364399             * > A comment token
    44374400             */
    4438             case '#cdata-section':
    44394401            case '#comment':
    44404402            case '#funky-comment':
Note: See TracChangeset for help on using the changeset viewer.