diff -r be944660c56a -r 3d72ae0968f4 wp/wp-includes/block-supports/duotone.php
--- a/wp/wp-includes/block-supports/duotone.php Wed Sep 21 18:19:35 2022 +0200
+++ b/wp/wp-includes/block-supports/duotone.php Tue Sep 27 16:37:53 2022 +0200
@@ -45,7 +45,6 @@
*
* @param mixed $n Number of unknown type.
* @param int $max Upper value of the range to bound to.
- *
* @return float Value in the range [0, 1].
*/
function wp_tinycolor_bound01( $n, $max ) {
@@ -70,7 +69,29 @@
}
/**
- * Round and convert values of an RGB object.
+ * Direct port of tinycolor's boundAlpha function to maintain consistency with
+ * how tinycolor works.
+ *
+ * @see https://github.com/bgrins/TinyColor
+ *
+ * @since 5.9.0
+ * @access private
+ *
+ * @param mixed $n Number of unknown type.
+ * @return float Value in the range [0,1].
+ */
+function _wp_tinycolor_bound_alpha( $n ) {
+ if ( is_numeric( $n ) ) {
+ $n = (float) $n;
+ if ( $n >= 0 && $n <= 1 ) {
+ return $n;
+ }
+ }
+ return 1;
+}
+
+/**
+ * Rounds and converts values of an RGB object.
*
* Direct port of TinyColor's function, lightly simplified to maintain
* consistency with TinyColor.
@@ -81,7 +102,6 @@
* @access private
*
* @param array $rgb_color RGB object.
- *
* @return array Rounded and converted RGB object.
*/
function wp_tinycolor_rgb_to_rgb( $rgb_color ) {
@@ -106,7 +126,6 @@
* @param float $p first component.
* @param float $q second component.
* @param float $t third component.
- *
* @return float R, G, or B component.
*/
function wp_tinycolor_hue_to_rgb( $p, $q, $t ) {
@@ -129,7 +148,7 @@
}
/**
- * Convert an HSL object to an RGB object with converted and rounded values.
+ * Converts an HSL object to an RGB object with converted and rounded values.
*
* Direct port of TinyColor's function, lightly simplified to maintain
* consistency with TinyColor.
@@ -140,7 +159,6 @@
* @access private
*
* @param array $hsl_color HSL object.
- *
* @return array Rounded and converted RGB object.
*/
function wp_tinycolor_hsl_to_rgb( $hsl_color ) {
@@ -170,8 +188,7 @@
/**
* Parses hex, hsl, and rgb CSS strings using the same regex as TinyColor v1.4.2
- * used in the JavaScript. Only colors output from react-color are implemented
- * and the alpha value is ignored as it is not used in duotone.
+ * used in the JavaScript. Only colors output from react-color are implemented.
*
* Direct port of TinyColor's function, lightly simplified to maintain
* consistency with TinyColor.
@@ -180,10 +197,10 @@
* @see https://github.com/casesandberg/react-color/
*
* @since 5.8.0
+ * @since 5.9.0 Added alpha processing.
* @access private
*
* @param string $color_str CSS color string.
- *
* @return array RGB object.
*/
function wp_tinycolor_string_to_rgb( $color_str ) {
@@ -199,93 +216,254 @@
$rgb_regexp = '/^rgb' . $permissive_match3 . '$/';
if ( preg_match( $rgb_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
+ $rgb = wp_tinycolor_rgb_to_rgb(
+ array(
+ 'r' => $match[1],
+ 'g' => $match[2],
+ 'b' => $match[3],
+ )
+ );
+
+ $rgb['a'] = 1;
+
+ return $rgb;
+ }
+
+ $rgba_regexp = '/^rgba' . $permissive_match4 . '$/';
+ if ( preg_match( $rgba_regexp, $color_str, $match ) ) {
+ $rgb = wp_tinycolor_rgb_to_rgb(
array(
'r' => $match[1],
'g' => $match[2],
'b' => $match[3],
)
);
- }
- $rgba_regexp = '/^rgba' . $permissive_match4 . '$/';
- if ( preg_match( $rgba_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
- array(
- 'r' => $match[1],
- 'g' => $match[2],
- 'b' => $match[3],
- )
- );
+ $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] );
+
+ return $rgb;
}
$hsl_regexp = '/^hsl' . $permissive_match3 . '$/';
if ( preg_match( $hsl_regexp, $color_str, $match ) ) {
- return wp_tinycolor_hsl_to_rgb(
+ $rgb = wp_tinycolor_hsl_to_rgb(
array(
'h' => $match[1],
's' => $match[2],
'l' => $match[3],
)
);
+
+ $rgb['a'] = 1;
+
+ return $rgb;
}
$hsla_regexp = '/^hsla' . $permissive_match4 . '$/';
if ( preg_match( $hsla_regexp, $color_str, $match ) ) {
- return wp_tinycolor_hsl_to_rgb(
+ $rgb = wp_tinycolor_hsl_to_rgb(
array(
'h' => $match[1],
's' => $match[2],
'l' => $match[3],
)
);
+
+ $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] );
+
+ return $rgb;
}
$hex8_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/';
if ( preg_match( $hex8_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
+ $rgb = wp_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1], 16, 10 ),
'g' => base_convert( $match[2], 16, 10 ),
'b' => base_convert( $match[3], 16, 10 ),
)
);
+
+ $rgb['a'] = _wp_tinycolor_bound_alpha(
+ base_convert( $match[4], 16, 10 ) / 255
+ );
+
+ return $rgb;
}
$hex6_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/';
if ( preg_match( $hex6_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
+ $rgb = wp_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1], 16, 10 ),
'g' => base_convert( $match[2], 16, 10 ),
'b' => base_convert( $match[3], 16, 10 ),
)
);
+
+ $rgb['a'] = 1;
+
+ return $rgb;
}
$hex4_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/';
if ( preg_match( $hex4_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
+ $rgb = wp_tinycolor_rgb_to_rgb(
+ array(
+ 'r' => base_convert( $match[1] . $match[1], 16, 10 ),
+ 'g' => base_convert( $match[2] . $match[2], 16, 10 ),
+ 'b' => base_convert( $match[3] . $match[3], 16, 10 ),
+ )
+ );
+
+ $rgb['a'] = _wp_tinycolor_bound_alpha(
+ base_convert( $match[4] . $match[4], 16, 10 ) / 255
+ );
+
+ return $rgb;
+ }
+
+ $hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/';
+ if ( preg_match( $hex3_regexp, $color_str, $match ) ) {
+ $rgb = wp_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1] . $match[1], 16, 10 ),
'g' => base_convert( $match[2] . $match[2], 16, 10 ),
'b' => base_convert( $match[3] . $match[3], 16, 10 ),
)
);
+
+ $rgb['a'] = 1;
+
+ return $rgb;
}
- $hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/';
- if ( preg_match( $hex3_regexp, $color_str, $match ) ) {
- return wp_tinycolor_rgb_to_rgb(
- array(
- 'r' => base_convert( $match[1] . $match[1], 16, 10 ),
- 'g' => base_convert( $match[2] . $match[2], 16, 10 ),
- 'b' => base_convert( $match[3] . $match[3], 16, 10 ),
- )
+ /*
+ * The JS color picker considers the string "transparent" to be a hex value,
+ * so we need to handle it here as a special case.
+ */
+ if ( 'transparent' === $color_str ) {
+ return array(
+ 'r' => 0,
+ 'g' => 0,
+ 'b' => 0,
+ 'a' => 0,
);
}
}
+/**
+ * Returns the prefixed id for the duotone filter for use as a CSS id.
+ *
+ * @since 5.9.1
+ * @access private
+ *
+ * @param array $preset Duotone preset value as seen in theme.json.
+ * @return string Duotone filter CSS id.
+ */
+function wp_get_duotone_filter_id( $preset ) {
+ if ( ! isset( $preset['slug'] ) ) {
+ return '';
+ }
+
+ return 'wp-duotone-' . $preset['slug'];
+}
+
+/**
+ * Returns the CSS filter property url to reference the rendered SVG.
+ *
+ * @since 5.9.0
+ * @access private
+ *
+ * @param array $preset Duotone preset value as seen in theme.json.
+ * @return string Duotone CSS filter property url value.
+ */
+function wp_get_duotone_filter_property( $preset ) {
+ $filter_id = wp_get_duotone_filter_id( $preset );
+ return "url('#" . $filter_id . "')";
+}
+
+/**
+ * Returns the duotone filter SVG string for the preset.
+ *
+ * @since 5.9.1
+ * @access private
+ *
+ * @param array $preset Duotone preset value as seen in theme.json.
+ * @return string Duotone SVG filter.
+ */
+function wp_get_duotone_filter_svg( $preset ) {
+ $filter_id = wp_get_duotone_filter_id( $preset );
+
+ $duotone_values = array(
+ 'r' => array(),
+ 'g' => array(),
+ 'b' => array(),
+ 'a' => array(),
+ );
+
+ if ( ! isset( $preset['colors'] ) || ! is_array( $preset['colors'] ) ) {
+ $preset['colors'] = array();
+ }
+
+ foreach ( $preset['colors'] as $color_str ) {
+ $color = wp_tinycolor_string_to_rgb( $color_str );
+
+ $duotone_values['r'][] = $color['r'] / 255;
+ $duotone_values['g'][] = $color['g'] / 255;
+ $duotone_values['b'][] = $color['b'] / 255;
+ $duotone_values['a'][] = $color['a'];
+ }
+
+ ob_start();
+
+ ?>
+
+
+
+ ', '><', $svg );
+ $svg = trim( $svg );
+ }
+
+ return $svg;
+}
/**
* Registers the style and colors block attributes for block types that support it.
@@ -322,7 +500,6 @@
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
- *
* @return string Filtered block content.
*/
function wp_render_duotone_support( $block_content, $block ) {
@@ -342,84 +519,61 @@
return $block_content;
}
- $duotone_colors = $block['attrs']['style']['color']['duotone'];
-
- $duotone_values = array(
- 'r' => array(),
- 'g' => array(),
- 'b' => array(),
+ $filter_preset = array(
+ 'slug' => wp_unique_id( sanitize_key( implode( '-', $block['attrs']['style']['color']['duotone'] ) . '-' ) ),
+ 'colors' => $block['attrs']['style']['color']['duotone'],
);
- foreach ( $duotone_colors as $color_str ) {
- $color = wp_tinycolor_string_to_rgb( $color_str );
+ $filter_property = wp_get_duotone_filter_property( $filter_preset );
+ $filter_id = wp_get_duotone_filter_id( $filter_preset );
+ $filter_svg = wp_get_duotone_filter_svg( $filter_preset );
- $duotone_values['r'][] = $color['r'] / 255;
- $duotone_values['g'][] = $color['g'] / 255;
- $duotone_values['b'][] = $color['b'] / 255;
+ $scope = '.' . $filter_id;
+ $selectors = explode( ',', $duotone_support );
+ $scoped = array();
+ foreach ( $selectors as $sel ) {
+ $scoped[] = $scope . ' ' . trim( $sel );
}
+ $selector = implode( ', ', $scoped );
- $duotone_id = 'wp-duotone-filter-' . uniqid();
+ // !important is needed because these styles render before global styles,
+ // and they should be overriding the duotone filters set by global styles.
+ $filter_style = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG
+ ? $selector . " {\n\tfilter: " . $filter_property . " !important;\n}\n"
+ : $selector . '{filter:' . $filter_property . ' !important;}';
- $selectors = explode( ',', $duotone_support );
- $selectors_scoped = array_map(
- function ( $selector ) use ( $duotone_id ) {
- return '.' . $duotone_id . ' ' . trim( $selector );
- },
- $selectors
- );
- $selectors_group = implode( ', ', $selectors_scoped );
+ wp_register_style( $filter_id, false, array(), true, true );
+ wp_add_inline_style( $filter_id, $filter_style );
+ wp_enqueue_style( $filter_id );
+
+ add_action(
+ 'wp_footer',
+ static function () use ( $filter_svg, $selector ) {
+ echo $filter_svg;
- ob_start();
-
- ?>
-
-
-
-
-
-