Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
68a6b4a
HTML API: Add support for SVG and MathML (Foreign content)
dmsnell Jul 30, 2024
85df3a3
Update test runner
dmsnell Jul 30, 2024
47f60fe
Lower-case tag names for foreign content in test runner.
dmsnell Jul 30, 2024
c216604
Use the namespace-adjusted tag name in tests.
dmsnell Jul 30, 2024
758d5b5
Merge branch 'trunk' into html-api/detect-foreign-content
dmsnell Jul 31, 2024
83db8f0
Various updates and changes. Currently experiencing infinite loops.
dmsnell Jul 31, 2024
0cdf0da
Prevent infinite loop.
dmsnell Jul 31, 2024
f9ac6d7
Check namespace against actual token, not Tag Processor state.
dmsnell Aug 1, 2024
c753249
Provide method for getting adjusted attribute names, and update testi…
dmsnell Aug 1, 2024
5bb9eb1
HTML5Lib: Prevent printing empty text nodes in tree
sirreal Aug 1, 2024
974c45a
phpcs fix
sirreal Aug 1, 2024
56ba291
Closing BR can occur outside of the HTML namespace.
dmsnell Aug 1, 2024
047825b
Fix an issue with mathml integration point check
sirreal Aug 5, 2024
28816c7
Change parsing namespace in push/pop handlers
sirreal Aug 5, 2024
3eb0654
Check for namespace in expects_closer atomic elements
sirreal Aug 5, 2024
5a64823
Use insert_foreign_element to insert foreign elements
sirreal Aug 5, 2024
31801d6
Do not report foreign content self-closing tags as closers
sirreal Aug 6, 2024
f66ba57
Fix typo in femorphology tag name
sirreal Aug 6, 2024
efbf5ef
Merge branch 'trunk' into html-api/detect-foreign-content
sirreal Aug 7, 2024
32c25d5
Fix svg:TEMPLATE handling in html5lib tests
sirreal Aug 7, 2024
9e0b884
Fix HTML5lib-test handling of self-closing tags
sirreal Aug 7, 2024
71cd1b2
Only transform attributes outside of html namespace
sirreal Aug 6, 2024
2a3f6cb
Use get_namespace() over parsing_namespace
sirreal Aug 6, 2024
0f94dcb
Use get_adjusted_current_node when getting namespace
sirreal Aug 6, 2024
e90fbc3
Fix adjusted_current_node to check _element_ nodes
sirreal Aug 6, 2024
00f9b68
More passing FC tests
sirreal Aug 6, 2024
58be2d8
Do not need to worry about those elements after all
sirreal Aug 7, 2024
9a83dc7
Move namespace handling into insert_foriegn_element
sirreal Aug 7, 2024
e004603
Handle namespace mucking inside "insert_foreign_element"
sirreal Aug 7, 2024
641e678
Revert "Handle namespace mucking inside "insert_foreign_element""
sirreal Aug 7, 2024
c944b1b
Revert "Move namespace handling into insert_foriegn_element"
sirreal Aug 7, 2024
0056d2f
Revert irrelevant change
sirreal Aug 7, 2024
781df79
Reapply "Move namespace handling into insert_foriegn_element"
sirreal Aug 7, 2024
64e3e5d
Reapply "Handle namespace mucking inside "insert_foreign_element""
sirreal Aug 7, 2024
4e6407e
Only insert foreign elements when handling foreign content
sirreal Aug 7, 2024
ce86164
Do not change the namespace to the integration node type
sirreal Aug 7, 2024
6afdbe6
Update comments, reorder `try`, support SCRIPT tags.
dmsnell Aug 8, 2024
a1e48e3
Revert change to BR closing tag behavior.
dmsnell Aug 8, 2024
8f01a18
Rename "namespaced" tag/attribute name getters to "get_qualified_...()"
dmsnell Aug 8, 2024
2016cc4
WPCS
dmsnell Aug 8, 2024
657df3b
New TODO ear-marking a logic review.
dmsnell Aug 8, 2024
57e8670
Move the foreign content other end tag label into condition
sirreal Aug 8, 2024
38aab38
Merge remote-tracking branch 'upstream/trunk' into html-api/detect-fo…
dmsnell Aug 8, 2024
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
Prev Previous commit
Next Next commit
Provide method for getting adjusted attribute names, and update testi…
…ng code.
  • Loading branch information
dmsnell committed Aug 1, 2024
commit c7532498e53a39cfa016bac8ee073567cbf686c6
239 changes: 239 additions & 0 deletions src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2898,6 +2898,245 @@ public function get_namespaced_tag_name(): ?string {
}
}

/**
* Returns the adjusted attribute name for a given attribute, taking into
* account the current parsing context, whether HTML, SVG, or MathML.
*
* @todo Find a better name.
*
* @since 6.7.0
*
* @param string $attribute_name Which attribute to adjust.
*
* @return string|null
*/
public function get_namespaced_attribute_name( $attribute_name ): ?string {
if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {
return null;
}

$lower_name = strtolower( $attribute_name );

if ( 'math' === $this->get_namespace() && 'definitionurl' === $lower_name ) {
return 'definitionURL';
}

if ( 'svg' === $this->get_namespace() ) {
switch ( $lower_name ) {
case 'attributename':
return 'attributeName';

case 'attributetype':
return 'attributeType';

case 'basefrequency':
return 'baseFrequency';

case 'baseprofile':
return 'baseProfile';

case 'calcmode':
return 'calcMode';

case 'clippathunits':
return 'clipPathUnits';

case 'diffuseconstant':
return 'diffuseConstant';

case 'edgemode':
return 'edgeMode';

case 'filterunits':
return 'filterUnits';

case 'glyphref':
return 'glyphRef';

case 'gradienttransform':
return 'gradientTransform';

case 'gradientunits':
return 'gradientUnits';

case 'kernelmatrix':
return 'kernelMatrix';

case 'kernelunitlength':
return 'kernelUnitLength';

case 'keypoints':
return 'keyPoints';

case 'keysplines':
return 'keySplines';

case 'keytimes':
return 'keyTimes';

case 'lengthadjust':
return 'lengthAdjust';

case 'limitingconeangle':
return 'limitingConeAngle';

case 'markerheight':
return 'markerHeight';

case 'markerunits':
return 'markerUnits';

case 'markerwidth':
return 'markerWidth';

case 'maskcontentunits':
return 'maskContentUnits';

case 'maskunits':
return 'maskUnits';

case 'numoctaves':
return 'numOctaves';

case 'pathlength':
return 'pathLength';

case 'patterncontentunits':
return 'patternContentUnits';

case 'patterntransform':
return 'patternTransform';

case 'patternunits':
return 'patternUnits';

case 'pointsatx':
return 'pointsAtX';

case 'pointsaty':
return 'pointsAtY';

case 'pointsatz':
return 'pointsAtZ';

case 'preservealpha':
return 'preserveAlpha';

case 'preserveaspectratio':
return 'preserveAspectRatio';

case 'primitiveunits':
return 'primitiveUnits';

case 'refx':
return 'refX';

case 'refy':
return 'refY';

case 'repeatcount':
return 'repeatCount';

case 'repeatdur':
return 'repeatDur';

case 'requiredextensions':
return 'requiredExtensions';

case 'requiredfeatures':
return 'requiredFeatures';

case 'specularconstant':
return 'specularConstant';

case 'specularexponent':
return 'specularExponent';

case 'spreadmethod':
return 'spreadMethod';

case 'startoffset':
return 'startOffset';

case 'stddeviation':
return 'stdDeviation';

case 'stitchtiles':
return 'stitchTiles';

case 'surfacescale':
return 'surfaceScale';

case 'systemlanguage':
return 'systemLanguage';

case 'tablevalues':
return 'tableValues';

case 'targetx':
return 'targetX';

case 'targety':
return 'targetY';

case 'textlength':
return 'textLength';

case 'viewbox':
return 'viewBox';

case 'viewtarget':
return 'viewTarget';

case 'xchannelselector':
return 'xChannelSelector';

case 'ychannelselector':
return 'yChannelSelector';

case 'zoomandpan':
return 'zoomAndPan';
}
}

switch ( $lower_name ) {
case 'xlink:actuate':
return 'xlink actuate';

case 'xlink:arcrole':
return 'xlink arcrole';

case 'xlink:href':
return 'xlink href';

case 'xlink:role':
return 'xlink role';

case 'xlink:show':
return 'xlink show';

case 'xlink:title':
return 'xlink title';

case 'xlink:type':
return 'xlink type';

case 'xml:lang':
return 'xml lang';

case 'xml:space':
return 'xml space';

case 'xmlns':
return 'xmlns';

case 'xmlns:xlink':
return 'xmlns xlink';
}

return $attribute_name;
}

/**
* Indicates if the currently matched tag contains the self-closing flag.
*
Expand Down
44 changes: 41 additions & 3 deletions tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,47 @@ private static function build_tree_representation( ?string $fragment_context, st

$attribute_names = $processor->get_attribute_names_with_prefix( '' );
if ( $attribute_names ) {
sort( $attribute_names, SORT_STRING );

$sorted_attributes = array();
foreach ( $attribute_names as $attribute_name ) {
$sorted_attributes[ $attribute_name ] = $processor->get_namespaced_attribute_name( $attribute_name );
}

/*
* Sorts attributes to match html5lib sort order.
*
* - First comes normal HTML attributes.
* - Then come adjusted foreign attributes; these have spaces in their names.
* - Finally come non-adjusted foreign attributes; these have a colon in their names.
*
* Example:
*
* From: <math xlink:author definitionurl xlink:title xlink:show>
* Sorted: 'definitionURL', 'xlink show', 'xlink title', 'xlink:author'
*/
uasort(
$sorted_attributes,
static function ( $a, $b ) {
$a_has_ns = str_contains( $a, ':' );
$b_has_ns = str_contains( $b, ':' );

// Attributes with `:` should follow all other attributes.
if ( $a_has_ns !== $b_has_ns ) {
return $a_has_ns ? 1 : -1;
}

$a_has_sp = str_contains( $a, ' ' );
$b_has_sp = str_contains( $b, ' ' );

// Attributes with a namespace ' ' should come after those without.
if ( $a_has_sp !== $b_has_sp ) {
return $a_has_sp ? 1 : -1;
}

return $a <=> $b;
}
);

foreach ( $sorted_attributes as $attribute_name => $display_name ) {
$val = $processor->get_attribute( $attribute_name );
/*
* Attributes with no value are `true` with the HTML API,
Expand All @@ -211,7 +249,7 @@ private static function build_tree_representation( ?string $fragment_context, st
if ( true === $val ) {
$val = '';
}
$output .= str_repeat( $indent, $tag_indent + 1 ) . "{$attribute_name}=\"{$val}\"\n";
$output .= str_repeat( $indent, $tag_indent + 1 ) . "{$display_name}=\"{$val}\"\n";
}
}

Expand Down