Make WordPress Core


Ignore:
Timestamp:
08/08/2024 07:23:53 AM (15 months ago)
Author:
dmsnell
Message:

HTML API: Add support for SVG and MathML (Foreign content)

As part of work to add more spec support to the HTML API, this patch adds
support for SVG and MathML elements, or more generally, "foreign content."

The rules in foreign content are a mix of XML and HTML parsing rules and
introduce additional complexity into the processor, but is important in
order to avoid getting lost when inside these elements.

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

Props: dmsnell, jonsurrell, westonruter.
See #61576.

File:
1 edited

Legend:

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

    r58833 r58867  
    114114     * @param int $nth Retrieve the nth item on the stack, with 1 being
    115115     *                 the top element, 2 being the second, etc...
    116      * @return string|null Name of the node on the stack at the given location,
    117      *                     or `null` if the location isn't on the stack.
    118      */
    119     public function at( int $nth ): ?string {
     116     * @return WP_HTML_Token|null Name of the node on the stack at the given location,
     117     *                            or `null` if the location isn't on the stack.
     118     */
     119    public function at( int $nth ): ?WP_HTML_Token {
    120120        foreach ( $this->walk_down() as $item ) {
    121121            if ( 0 === --$nth ) {
    122                 return $item->node_name;
     122                return $item;
    123123            }
    124124        }
     
    243243    public function has_element_in_specific_scope( string $tag_name, $termination_list ): bool {
    244244        foreach ( $this->walk_up() as $node ) {
    245             if ( $node->node_name === $tag_name ) {
     245            $namespaced_name = 'html' === $node->namespace
     246                ? $node->node_name
     247                : "{$node->namespace} {$node->node_name}";
     248
     249            if ( $namespaced_name === $tag_name ) {
    246250                return true;
    247251            }
     
    249253            if (
    250254                '(internal: H1 through H6 - do not use)' === $tag_name &&
    251                 in_array( $node->node_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true )
     255                in_array( $namespaced_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true )
    252256            ) {
    253257                return true;
    254258            }
    255259
    256             if ( in_array( $node->node_name, $termination_list, true ) ) {
     260            if ( in_array( $namespaced_name, $termination_list, true ) ) {
    257261                return false;
    258262            }
     
    289293     *
    290294     * @since 6.4.0
    291      * @since 6.7.0 Supports all required HTML elements.
     295     * @since 6.7.0 Full support.
    292296     *
    293297     * @see https://html.spec.whatwg.org/#has-an-element-in-scope
     
    310314                'TEMPLATE',
    311315
    312                 /*
    313                  * @todo Support SVG and MathML nodes when support for foreign content is added.
    314                  *
    315                  * - MathML mi
    316                  * - MathML mo
    317                  * - MathML mn
    318                  * - MathML ms
    319                  * - MathML mtext
    320                  * - MathML annotation-xml
    321                  * - SVG foreignObject
    322                  * - SVG desc
    323                  * - SVG title
    324                  */
     316                'math MI',
     317                'math MO',
     318                'math MN',
     319                'math MS',
     320                'math MTEXT',
     321                'math ANNOTATION-XML',
     322
     323                'svg FOREIGNOBJECT',
     324                'svg DESC',
     325                'svg TITLE',
    325326            )
    326327        );
     
    364365                'UL',
    365366
    366                 /*
    367                  * @todo Support SVG and MathML nodes when support for foreign content is added.
    368                  *
    369                  * - MathML mi
    370                  * - MathML mo
    371                  * - MathML mn
    372                  * - MathML ms
    373                  * - MathML mtext
    374                  * - MathML annotation-xml
    375                  * - SVG foreignObject
    376                  * - SVG desc
    377                  * - SVG title
    378                  */
     367                'math MI',
     368                'math MO',
     369                'math MN',
     370                'math MS',
     371                'math MTEXT',
     372                'math ANNOTATION-XML',
     373
     374                'svg FOREIGNOBJECT',
     375                'svg DESC',
     376                'svg TITLE',
    379377            )
    380378        );
     
    414412                'TEMPLATE',
    415413
    416                 /*
    417                  * @todo Support SVG and MathML nodes when support for foreign content is added.
    418                  *
    419                  * - MathML mi
    420                  * - MathML mo
    421                  * - MathML mn
    422                  * - MathML ms
    423                  * - MathML mtext
    424                  * - MathML annotation-xml
    425                  * - SVG foreignObject
    426                  * - SVG desc
    427                  * - SVG title
    428                  */
     414                'math MI',
     415                'math MO',
     416                'math MN',
     417                'math MS',
     418                'math MTEXT',
     419                'math ANNOTATION-XML',
     420
     421                'svg FOREIGNOBJECT',
     422                'svg DESC',
     423                'svg TITLE',
    429424            )
    430425        );
     
    693688     */
    694689    public function after_element_push( WP_HTML_Token $item ): void {
     690        $namespaced_name = 'html' === $item->namespace
     691            ? $item->node_name
     692            : "{$item->namespace} {$item->node_name}";
     693
    695694        /*
    696695         * When adding support for new elements, expand this switch to trap
    697696         * cases where the precalculated value needs to change.
    698697         */
    699         switch ( $item->node_name ) {
     698        switch ( $namespaced_name ) {
    700699            case 'APPLET':
    701700            case 'BUTTON':
     
    708707            case 'OBJECT':
    709708            case 'TEMPLATE':
     709            case 'math MI':
     710            case 'math MO':
     711            case 'math MN':
     712            case 'math MS':
     713            case 'math MTEXT':
     714            case 'math ANNOTATION-XML':
     715            case 'svg FOREIGNOBJECT':
     716            case 'svg DESC':
     717            case 'svg TITLE':
    710718                $this->has_p_in_button_scope = false;
    711719                break;
     
    751759            case 'OBJECT':
    752760            case 'TEMPLATE':
     761            case 'math MI':
     762            case 'math MO':
     763            case 'math MN':
     764            case 'math MS':
     765            case 'math MTEXT':
     766            case 'math ANNOTATION-XML':
     767            case 'svg FOREIGNOBJECT':
     768            case 'svg DESC':
     769            case 'svg TITLE':
    753770                $this->has_p_in_button_scope = $this->has_element_in_button_scope( 'P' );
    754771                break;
Note: See TracChangeset for help on using the changeset viewer.