Make WordPress Core


Ignore:
Timestamp:
12/10/2023 01:17:29 PM (12 months ago)
Author:
zieladam
Message:

HTML API: Track spans of text with (offset, length) instead of (start, end).

Updates the internal representation of the text span coordinates. The mixture of (offset, length) and (start, end) coordinates becomes confusing, this commit replaces it with a (offset, length) pair. There should be no functional or behavioral changes in this patch. For the internal helper classes this patch introduces breaking changes, but those classes are marked private and should not be used outside of the HTML API itself.

Props dmsnell.
Fixes #59993.

File:
1 edited

Legend:

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

    r57116 r57179  
    330330
    331331    /**
     332     * Byte offset in input document where current token starts.
     333     *
     334     * Example:
     335     *
     336     *     <div id="test">...
     337     *     01234
     338     *     - token starts at 0
     339     *
     340     * @since 6.5.0
     341     *
     342     * @var int|null
     343     */
     344    private $token_starts_at;
     345
     346    /**
     347     * Byte length of current token.
     348     *
     349     * Example:
     350     *
     351     *     <div id="test">...
     352     *     012345678901234
     353     *     - token length is 14 - 0 = 14
     354     *
     355     *     a <!-- comment --> is a token.
     356     *     0123456789 123456789 123456789
     357     *     - token length is 17 - 2 = 15
     358     *
     359     * @since 6.5.0
     360     *
     361     * @var int|null
     362     */
     363    private $token_length;
     364
     365    /**
    332366     * Byte offset in input document where current tag name starts.
    333367     *
     
    339373     *
    340374     * @since 6.2.0
     375     *
    341376     * @var int|null
    342377     */
     
    353388     *
    354389     * @since 6.2.0
     390     *
    355391     * @var int|null
    356392     */
    357393    private $tag_name_length;
    358 
    359     /**
    360      * Byte offset in input document where current tag token ends.
    361      *
    362      * Example:
    363      *
    364      *     <div id="test">...
    365      *     0         1   |
    366      *     01234567890123456
    367      *      --- tag name ends at 14
    368      *
    369      * @since 6.2.0
    370      * @var int|null
    371      */
    372     private $tag_ends_at;
    373394
    374395    /**
     
    389410     *     //                 ^ parsing will continue from this point.
    390411     *     $this->attributes = array(
    391      *         'id' => new WP_HTML_Attribute_Match( 'id', null, 6, 17 )
     412     *         'id' => new WP_HTML_Attribute_Token( 'id', 9, 6, 5, 11, false )
    392413     *     );
    393414     *
     
    395416     *     // `class` attribute we will continue and add to this array.
    396417     *     $this->attributes = array(
    397      *         'id'    => new WP_HTML_Attribute_Match( 'id', null, 6, 17 ),
    398      *         'class' => new WP_HTML_Attribute_Match( 'class', 'outline', 18, 32 )
     418     *         'id'    => new WP_HTML_Attribute_Token( 'id', 9, 6, 5, 11, false ),
     419     *         'class' => new WP_HTML_Attribute_Token( 'class', 23, 7, 17, 13, false )
    399420     *     );
    400421     *
     
    485506     *     // Replace an attribute stored with a new value, indices
    486507     *     // sourced from the lazily-parsed HTML recognizer.
    487      *     $start = $attributes['src']->start;
    488      *     $end   = $attributes['src']->end;
    489      *     $modifications[] = new WP_HTML_Text_Replacement( $start, $end, $new_value );
     508     *     $start  = $attributes['src']->start;
     509     *     $length = $attributes['src']->length;
     510     *     $modifications[] = new WP_HTML_Text_Replacement( $start, $length, $new_value );
    490511     *
    491512     *     // Correspondingly, something like this will appear in this array.
     
    567588                return false;
    568589            }
    569             $this->tag_ends_at          = $tag_ends_at;
     590            $this->token_length         = $tag_ends_at - $this->token_starts_at;
    570591            $this->bytes_already_parsed = $tag_ends_at;
    571592
     
    809830        }
    810831
    811         $this->bookmarks[ $name ] = new WP_HTML_Span(
    812             $this->tag_name_starts_at - ( $this->is_closing_tag ? 2 : 1 ),
    813             $this->tag_ends_at
    814         );
     832        $this->bookmarks[ $name ] = new WP_HTML_Span( $this->token_starts_at, $this->token_length );
    815833
    816834        return true;
     
    876894            $at = strpos( $this->html, '</', $at );
    877895
    878             // If there is no possible tag closer then fail.
     896            // Fail if there is no possible tag closer.
    879897            if ( false === $at || ( $at + $tag_length ) >= $doc_length ) {
    880898                $this->bytes_already_parsed = $doc_length;
     
    10941112            }
    10951113
     1114            $this->token_starts_at = $at;
     1115
    10961116            if ( '/' === $this->html[ $at + 1 ] ) {
    10971117                $this->is_closing_tag = true;
     
    13821402                $value_length,
    13831403                $attribute_start,
    1384                 $attribute_end,
     1404                $attribute_end - $attribute_start,
    13851405                ! $has_value
    13861406            );
     
    13971417         * normative case of parsing tags with no duplicate attributes.
    13981418         */
    1399         $duplicate_span = new WP_HTML_Span( $attribute_start, $attribute_end );
     1419        $duplicate_span = new WP_HTML_Span( $attribute_start, $attribute_end - $attribute_start );
    14001420        if ( null === $this->duplicate_attributes ) {
    14011421            $this->duplicate_attributes = array( $comparable_name => array( $duplicate_span ) );
     
    14251445    private function after_tag() {
    14261446        $this->get_updated_html();
     1447        $this->token_starts_at      = null;
     1448        $this->token_length         = null;
    14271449        $this->tag_name_starts_at   = null;
    14281450        $this->tag_name_length      = null;
    1429         $this->tag_ends_at          = null;
    14301451        $this->is_closing_tag       = null;
    14311452        $this->attributes           = array();
     
    16071628        $output_buffer        = '';
    16081629        foreach ( $this->lexical_updates as $diff ) {
    1609             $shift = strlen( $diff->text ) - ( $diff->end - $diff->start );
     1630            $shift = strlen( $diff->text ) - $diff->length;
    16101631
    16111632            // Adjust the cursor position by however much an update affects it.
     
    16211642            $output_buffer       .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied );
    16221643            $output_buffer       .= $diff->text;
    1623             $bytes_already_copied = $diff->end;
     1644            $bytes_already_copied = $diff->start + $diff->length;
    16241645        }
    16251646
     
    16311652         */
    16321653        foreach ( $this->bookmarks as $bookmark_name => $bookmark ) {
     1654            $bookmark_end   = $bookmark->start + $bookmark->length;
     1655
    16331656            /*
    16341657             * Each lexical update which appears before the bookmark's endpoints
     
    16411664
    16421665            foreach ( $this->lexical_updates as $diff ) {
    1643                 if ( $bookmark->start < $diff->start && $bookmark->end < $diff->start ) {
     1666                $diff_end = $diff->start + $diff->length;
     1667
     1668                if ( $bookmark->start < $diff->start && $bookmark_end < $diff->start ) {
    16441669                    break;
    16451670                }
    16461671
    1647                 if ( $bookmark->start >= $diff->start && $bookmark->end < $diff->end ) {
     1672                if ( $bookmark->start >= $diff->start && $bookmark_end < $diff_end ) {
    16481673                    $this->release_bookmark( $bookmark_name );
    16491674                    continue 2;
    16501675                }
    16511676
    1652                 $delta = strlen( $diff->text ) - ( $diff->end - $diff->start );
     1677                $delta = strlen( $diff->text ) - $diff->length;
    16531678
    16541679                if ( $bookmark->start >= $diff->start ) {
     
    16561681                }
    16571682
    1658                 if ( $bookmark->end >= $diff->end ) {
     1683                if ( $bookmark_end >= $diff_end ) {
    16591684                    $tail_delta += $delta;
    16601685                }
    16611686            }
    16621687
    1663             $bookmark->start += $head_delta;
    1664             $bookmark->end   += $tail_delta;
     1688            $bookmark->start  += $head_delta;
     1689            $bookmark->length += $tail_delta - $head_delta;
    16651690        }
    16661691
     
    17441769         * start at the same location and contain the same text.
    17451770         */
    1746         return $a->end - $b->end;
     1771        return $a->length - $b->length;
    17471772    }
    17481773
     
    19721997        }
    19731998
    1974         return '/' === $this->html[ $this->tag_ends_at - 1 ];
     1999        /*
     2000         * The self-closing flag is the solidus at the _end_ of the tag, not the beginning.
     2001         *
     2002         * Example:
     2003         *
     2004         *     <figure />
     2005         *             ^ this appears one character before the end of the closing ">".
     2006         */
     2007        return '/' === $this->html[ $this->token_starts_at + $this->token_length - 1 ];
    19752008    }
    19762009
     
    21022135            $this->lexical_updates[ $comparable_name ] = new WP_HTML_Text_Replacement(
    21032136                $existing_attribute->start,
    2104                 $existing_attribute->end,
     2137                $existing_attribute->length,
    21052138                $updated_attribute
    21062139            );
     
    21202153            $this->lexical_updates[ $comparable_name ] = new WP_HTML_Text_Replacement(
    21212154                $this->tag_name_starts_at + $this->tag_name_length,
    2122                 $this->tag_name_starts_at + $this->tag_name_length,
     2155                0,
    21232156                ' ' . $updated_attribute
    21242157            );
     
    21952228        $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement(
    21962229            $this->attributes[ $name ]->start,
    2197             $this->attributes[ $name ]->end,
     2230            $this->attributes[ $name ]->length,
    21982231            ''
    21992232        );
     
    22042237                $this->lexical_updates[] = new WP_HTML_Text_Replacement(
    22052238                    $attribute_token->start,
    2206                     $attribute_token->end,
     2239                    $attribute_token->length,
    22072240                    ''
    22082241                );
     
    22902323         * be necessary for reparsing the current tag after updating the HTML.
    22912324         */
    2292         $before_current_tag = $this->tag_name_starts_at - 1;
     2325        $before_current_tag = $this->token_starts_at;
    22932326
    22942327        /*
     
    23262359
    23272360        $tag_ends_at                = strpos( $this->html, '>', $this->bytes_already_parsed );
    2328         $this->tag_ends_at          = $tag_ends_at;
     2361        $this->token_length         = $tag_ends_at - $this->token_starts_at;
    23292362        $this->bytes_already_parsed = $tag_ends_at;
    23302363
Note: See TracChangeset for help on using the changeset viewer.