@ 2021-10-18T22:33:50Z <?php
// All of the code needed for this test.
function __( $text ) {
return $text;
}
/**
* Webfonts Schema Validator.
*
* Validates the webfont schema.
*/
class WP_Webfonts_Schema_Validator {
/**
* Valid font styles.
*
* @since 5.9.0
*
* @var string[]
*/
const VALID_FONT_STYLE = array( 'normal', 'italic', 'oblique', 'inherit', 'initial', 'revert', 'unset' );
/**
* Valid font display values.
*
* @since 5.9.0
*
* @var string[]
*/
const VALID_FONT_DISPLAY = array( 'auto', 'block', 'fallback', 'swap' );
/**
* Valid font weight values.
*
* @since 5.9.0
*
* @var string[]
*/
const VALID_FONT_WEIGHT = array( 'normal', 'bold', 'bolder', 'lighter', 'inherit' );
/**
* An array of valid CSS properties for @font-face.
*
* @since 5.9.0
*
* @var string[]
*/
protected $font_face_properties = array(
'ascend-override',
'descend-override',
'font-display',
'font-family',
'font-stretch',
'font-style',
'font-weight',
'font-variant',
'font-feature-settings',
'font-variation-settings',
'line-gap-override',
'size-adjust',
'src',
'unicode-range',
);
/**
* Basic schema structure.
*
* @since 5.9.0
*
* @var array
*/
protected $basic_schema = array(
'provider' => '',
'font-family' => '',
'font-style' => 'normal',
'font-weight' => '400',
'font-display' => 'fallback',
);
/**
* Webfont being validated.
*
* Set as a property for performance.
*
* @var array
*/
private $webfont = array();
/**
* Checks if the given webfont schema is valid.
*
* @since 5.9.0
*
* @param array $webfont Webfont to validate.
* @return bool True when valid. False when invalid.
*/
public function is_valid_schema( array $webfont ) {
$is_valid = (
$this->is_valid_provider( $webfont ) &&
$this->is_valid_font_family( $webfont )
);
if ( ! $is_valid ) {
return false;
}
if ( 'local' === $webfont['provider'] || array_key_exists( 'src', $webfont ) ) {
$is_valid = $this->is_src_valid( $webfont );
}
return $is_valid;
}
/**
* Checks if the provider is validate.
*
* @since 5.9.0
*
* @param array $webfont Webfont to validate.
* @return bool True if valid. False if invalid.
*/
private function is_valid_provider( array $webfont ) {
// @todo check if provider is registered.
if (
empty( $webfont['provider'] ) ||
! is_string( $webfont['provider'] )
) {
trigger_error( __( 'Webfont provider must be a non-empty string.' ) );
return false;
}
return true;
}
/**
* Checks if the font family is validate.
*
* @since 5.9.0
*
* @param array $webfont Webfont to validate.
* @return bool True when valid. False when invalid.
*/
private function is_valid_font_family( array $webfont ) {
if (
empty( $webfont['font-family'] ) ||
! is_string( $webfont['font-family'] )
) {
trigger_error( __( 'Webfont font family must be a non-empty string.' ) );
return false;
}
return true;
}
/**
* Checks if the "src" value is valid.
*
* @since 5.9.0
*
* @param array $webfont Webfont to validate.
* @return bool True if valid. False if invalid.
*/
private function is_src_valid( $webfont ) {
if (
empty( $webfont['src'] ) ||
(
! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] )
)
) {
trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );
return false;
}
foreach ( (array) $webfont['src'] as $src ) {
if ( ! is_string( $src ) ) {
trigger_error( __( 'Each webfont src must be a non-empty string.' ) );
return false;
}
if ( ! $this->is_src_value_valid( $src ) ) {
trigger_error( __( 'Webfont src must be a valid URL or a data URI.' ) );
return false;
}
}
return true;
}
/**
* Checks if the given `src` value is valid.
*
* @since 5.9.0
*
* @param string $src Source to validate.
* @return bool True when valid. False when invalid.
*/
private function is_src_value_valid( $src ) {
// Validate data URLs.
if ( preg_match( '/^data:.+;base64/', $src ) ) {
return true;
}
// Validate URLs.
if ( filter_var( $src, FILTER_VALIDATE_URL ) ) {
return true;
}
// Check if it's a URL starting with "//" (omitted protocol).
if ( 0 === strpos( $src, '//' ) ) {
return true;
}
// Check if it's a relative URL.
if ( 0 === strpos( $src, 'file:./' ) ) {
return true;
}
return false;
}
/**
* Sets valid properties.
*
* @since 5.9.0
*
* @param array $webfont Webfont definition.
* @return array Updated webfont.
*/
public function set_valid_properties( array $webfont ) {
$this->webfont = array_merge( $this->basic_schema, $webfont );
$this->set_valid_font_face_property();
$this->set_valid_font_style();
$this->set_valid_font_weight();
$this->set_valid_font_display();
$webfont = $this->webfont;
$this->webfont = array(); // Reset property.
return $webfont;
}
/**
* Checks if the CSS property is valid for @font-face.
*
* @since 5.9.0
*/
private function set_valid_font_face_property() {
foreach ( array_keys( $this->webfont ) as $property ) {
/*
* Skip valid configuration parameters (these are configuring the webfont
* but are not @font-face properties.
*/
if ( 'provider' === $property ) {
continue;
}
if ( ! in_array( $property, $this->font_face_properties, true ) ) {
unset( $this->webfont[ $property ] );
}
}
}
/**
* Checks if the font style is validate.
*
* @since 5.9.0
*/
private function set_valid_font_style() {
// If empty or not a string, trigger an error and then set the default value.
if (
empty( $this->webfont['font-style'] ) ||
! is_string( $this->webfont['font-style'] )
) {
trigger_error( __( 'Webfont font style must be a non-empty string.' ) );
} elseif ( // Bail out if the font-weight is a valid value.
in_array( $this->webfont['font-style'], self::VALID_FONT_STYLE, true ) ||
preg_match( '/^oblique\s+(\d+)%/', $this->webfont['font-style'] )
) {
return;
}
$this->webfont['font-style'] = 'normal';
}
/**
* Sets a default font weight if invalid.
*
* @since 5.9.0
*/
private function set_valid_font_weight() {
// If empty or not a string, trigger an error and then set the default value.
if (
empty( $this->webfont['font-weight'] ) ||
! is_string( $this->webfont['font-weight'] )
) {
trigger_error( __( 'Webfont font weight must be a non-empty string.' ) );
} elseif ( // Bail out if the font-weight is a valid value.
// Check if value is a single font-weight, formatted as a number.
in_array( $this->webfont['font-weight'], self::VALID_FONT_WEIGHT, true ) ||
// Check if value is a single font-weight, formatted as a number.
preg_match( '/^(\d+)$/', $this->webfont['font-weight'], $matches ) ||
// Check if value is a range of font-weights, formatted as a number range.
preg_match( '/^(\d+)\s+(\d+)$/', $this->webfont['font-weight'], $matches )
) {
return;
}
// Not valid. Set the default value.
$this->webfont['font-weight'] = '400';
}
/**
* Sets a default font display if invalid.
*
* @since 5.9.0
*/
private function set_valid_font_display() {
if (
! empty( $this->webfont['font-display'] ) &&
in_array( $this->webfont['font-display'], self::VALID_FONT_DISPLAY, true )
) {
return;
}
$this->webfont['font-display'] = 'fallback';
}
}
class Profiler {
private $validator;
private $total_in_microseconds = 0.0;
private $cycles = 0;
public function __construct( $validator ) {
$this->validator = $validator;
}
public function register( array $webfont ) {
$webfont = $this->convert_to_kabeb_case( $webfont );
$this->cycles++;
$start_time = microtime( true );
// Validate schema.
if ( ! $this->validator->is_valid_schema( $webfont ) ) {
// return ''; // Skip for this test.
}
$webfont = $this->validator->set_valid_properties( $webfont );
// Do the registration.
// Get stats.
$end_time = microtime( true );
$this->total_in_microseconds += ( $end_time - $start_time ) * 1000000.0; // store in microseconds.
}
private function convert_to_kabeb_case( array $webfont ) {
$kebab_case = preg_replace( '/(?<!^)[A-Z]/', '-$0', array_keys( $webfont ) );
$kebab_case = array_map( 'strtolower', $kebab_case );
return array_combine( $kebab_case, array_values( $webfont ) );
}
public function get_avg_microseconds() {
return $this->total_in_microseconds / $this->cycles;
}
}
// Let's Go!
$profiler = new Profiler( new WP_Webfonts_Schema_Validator() );
$webfont = array(
'fontFamily' => 'Source Serif Pro',
'fontWeight' => '200 900',
'fontStyle' => 'normal',
'fontStretch' => 'normal',
'src' => 'file:./assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
'provider' => 'local',
);
/**
* Benchmark the average time the Validator takes to validate a single webfont.
* The profiler is set to 10,000 cycles to get a fair sampling and distribution.
*/
$num_time_to_run_validator = 10000;
// do work.
for ( $i = 1; $i <= $num_time_to_run_validator; $i++ ) {
$profiler->register( $webfont );
}
printf( "Ran %d in %s microseconds",
$num_time_to_run_validator,
number_format( $profiler->get_avg_microseconds(), 4 )
);
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).
Version System time (s) User time (s) Memory (MiB) 8.4.2 0.014 0.034 17.94 8.4.1 0.007 0.037 18.04 8.3.15 0.010 0.048 17.28 8.3.14 0.003 0.031 16.95 8.3.13 0.000 0.034 18.71 8.3.12 0.007 0.030 19.18 8.3.11 0.003 0.040 20.94 8.3.10 0.010 0.027 24.06 8.3.9 0.003 0.030 26.77 8.3.8 0.007 0.036 16.88 8.3.7 0.000 0.062 18.43 8.3.6 0.010 0.078 17.00 8.3.5 0.010 0.054 18.41 8.3.4 0.016 0.046 19.39 8.3.3 0.003 0.068 18.88 8.3.2 0.004 0.032 24.18 8.3.1 0.010 0.059 24.66 8.3.0 0.006 0.028 26.16 8.2.27 0.000 0.034 17.38 8.2.26 0.003 0.040 19.26 8.2.25 0.003 0.031 16.93 8.2.24 0.013 0.044 17.37 8.2.23 0.007 0.030 22.58 8.2.22 0.010 0.026 37.54 8.2.21 0.000 0.040 26.77 8.2.20 0.007 0.034 16.63 8.2.19 0.003 0.067 16.63 8.2.18 0.019 0.065 25.92 8.2.17 0.000 0.063 19.20 8.2.16 0.003 0.058 22.96 8.2.15 0.010 0.061 25.66 8.2.14 0.007 0.027 24.66 8.2.13 0.013 0.046 26.16 8.2.12 0.007 0.027 19.28 8.2.11 0.013 0.042 20.78 8.2.10 0.007 0.051 20.47 8.1.31 0.007 0.030 18.74 8.1.30 0.003 0.031 17.96 8.1.29 0.010 0.030 18.88 8.1.28 0.010 0.055 25.92 8.1.27 0.007 0.026 24.66 8.1.26 0.013 0.023 26.35 8.1.25 0.010 0.030 28.09 8.1.24 0.011 0.043 18.77 8.1.23 0.007 0.045 22.32 8.0.11 0.008 0.046 17.15 7.4.24 0.002 0.052 16.87
preferences:dark mode live preview
27.87 ms | 403 KiB | 5 Q