Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 46 additions & 9 deletions src/Model/Model_Required_Fonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public function flush(): void {
}

/**
* A font key's files on the core manifest (none for bundled and custom fonts)
* A font key's files on the core manifest (none for bundled and custom fonts), with those of its `sip-ext` font,
* which mPDF loads with it for the SIP characters (Sun-ExtA's Sun-ExtB)
*
* @param mixed $key A font key
*
Expand All @@ -131,22 +132,55 @@ public function flush(): void {
* @since 6.19.0
*/
public function get_font_files( $key ): array {
$family = $this->font_sources->get_font_data()[ $this->normalise_font( $key ) ] ?? null;
$fontdata = $this->font_sources->get_font_data();
$family = $fontdata[ $this->normalise_font( $key ) ] ?? null;
if ( ! is_array( $family ) ) {
return [];
}

/* One level only, as mPDF doesn't follow a sip-ext font's own */
$families = [ $family, $fontdata[ $this->get_sip_ext( $family ) ] ?? null ];

$files = [];
foreach ( [ 'R', 'B', 'I', 'BI' ] as $style ) {
$file = is_string( $family[ $style ] ?? null ) ? $this->font_sources->get_manifest_file( $family[ $style ] ) : '';
if ( $this->font_sources->is_core_font_file( $file ) ) {
$files[] = $file;
foreach ( array_filter( $families, 'is_array' ) as $linked ) {
foreach ( [ 'R', 'B', 'I', 'BI' ] as $style ) {
$file = is_string( $linked[ $style ] ?? null ) ? $this->font_sources->get_manifest_file( $linked[ $style ] ) : '';
if ( $this->font_sources->is_core_font_file( $file ) ) {
$files[] = $file;
}
}
}

return array_values( array_unique( $files ) );
}

/**
* The font keys whose `sip-ext` font is the key, so get_font_files() counts the key's files as theirs
*
* @return string[]
*
* @since 6.19.0
*/
protected function get_sip_parents( string $key ): array {
$parents = [];
foreach ( $this->font_sources->get_font_data() as $parent => $family ) {
if ( is_array( $family ) && $this->get_sip_ext( $family ) === $key ) {
$parents[] = (string) $parent;
}
}

return $parents;
}

/**
* The font key mPDF loads with a family for its SIP characters, or an empty string
*
* @since 6.19.0
*/
protected function get_sip_ext( array $family ): string {
return $this->normalise_font( $family['sip-ext'] ?? '' );
}

/**
* Files that should be on disk: default, language, required-source and PDF-selected fonts
*
Expand Down Expand Up @@ -237,13 +271,16 @@ static function ( array $reason ) use ( $none ): array {
* @since 6.19.0
*/
public function is_font_in_use( string $key, bool $network = false ): bool {
if ( isset( $this->get_settings_font_reasons()[ $key ] ) ) {
/* A font whose sip-ext font this is needs its files too */
$keys = array_merge( [ $key ], $this->get_sip_parents( $key ) );

if ( array_intersect_key( $this->get_settings_font_reasons(), array_flip( $keys ) ) !== [] ) {
return true;
}

$this->form_read_failed = false;
foreach ( $this->each_pdf_font() as $font => $unused ) {
if ( $font === $key ) {
if ( in_array( $font, $keys, true ) ) {
return true;
}
}
Expand All @@ -259,7 +296,7 @@ public function is_font_in_use( string $key, bool $network = false ): bool {

$sites = $this->get_site_font_records();
foreach ( $this->get_other_site_ids() as $site_id ) {
if ( ! isset( $sites[ $site_id ] ) || in_array( $key, $sites[ $site_id ], true ) ) {
if ( ! isset( $sites[ $site_id ] ) || array_intersect( $keys, $sites[ $site_id ] ) !== [] ) {
return true;
}
}
Expand Down
10 changes: 10 additions & 0 deletions tests/phpunit/integration/Model/Test_Model_Font_Downloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,16 @@ public function test_prune_replaces_needed_installer_sun_ext_fonts() {
$this->assertSame( [ [] ], $this->get_scheduled_args() );
}

public function test_prune_replaces_an_installer_sun_extb_a_sun_exta_default_font_needs() {
GPDFAPI::get_options_class()->update_option( 'default_font', 'sun-exta' );
wp_clear_scheduled_hook( Model_Font_Downloader::SYNC_EVENT );
$this->set_installer_manifest( [ 'Sun-ExtB.ttf' => 'Chewy.ttf' ] );
$this->copy_fixture( 'Chewy.ttf', 'Sun-ExtB.ttf' );

$this->assertSame( [ 'Sun-ExtB.ttf' ], $this->downloader->prune() );
$this->assertSame( [ [] ], $this->get_scheduled_args() );
}

public function test_the_replacement_for_an_installer_garuda_lands_under_its_plain_name() {
$this->use_shipped_installer_manifest();
$this->serve_fixture_as( 'Garuda-v1.1.1.ttf', 'Garuda.ttf' );
Expand Down
57 changes: 56 additions & 1 deletion tests/phpunit/integration/Model/Test_Model_Required_Fonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public function test_it_is_registered() {

public function test_get_font_files_lists_a_core_keys_files_on_the_manifest() {
$this->assertSame( [ 'DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf', 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf' ], $this->required->get_font_files( ' DejaVuSerif ' ) );
$this->assertSame( [ 'Sun-ExtA.ttf' ], $this->required->get_font_files( 'sun-exta' ) );
$this->assertSame( [ 'Sun-ExtA.ttf', 'Sun-ExtB.ttf' ], $this->required->get_font_files( 'sun-exta' ) );
$this->assertSame( [ 'Sun-ExtB.ttf' ], $this->required->get_font_files( 'sun-extb' ) );
$this->assertSame( [], $this->required->get_font_files( 'arimo' ) );
$this->assertSame( [], $this->required->get_font_files( 'notafont' ) );
}
Expand All @@ -71,6 +72,47 @@ public function test_get_font_files_skips_a_custom_font() {
$this->assertSame( [], $this->required->get_font_files( 'chewy' ) );
}

public function test_get_font_files_counts_a_sip_ext_font_one_level_deep() {
add_filter(
'mpdf_font_data',
static function ( array $fontdata ): array {
$fontdata['dejavuserif']['sip-ext'] = ' FreeSerif ';
$fontdata['freeserif']['sip-ext'] = 'dejavuserif';
$fontdata['garuda']['sip-ext'] = 'notafont';
$fontdata['kaputaunicode']['sip-ext'] = [ 'freeserif' ];

return $fontdata;
},
PHP_INT_MAX
);

$required = $this->required_with( $this->stub_font_sources() );
$dejavu = [ 'DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf', 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf' ];

$this->assertSame( array_merge( $dejavu, self::$freeserif ), $required->get_font_files( 'dejavuserif' ) );
$this->assertSame( array_merge( self::$freeserif, $dejavu ), $required->get_font_files( 'freeserif' ) );
$this->assertSame( self::GARUDA, $required->get_font_files( 'garuda' ) );
$this->assertSame( [ 'kaputaunicode.ttf' ], $required->get_font_files( 'kaputaunicode' ) );
}

public function test_a_sun_exta_default_font_requires_sun_extb() {
GPDFAPI::get_options_class()->update_option( 'default_font', 'sun-exta' );

$this->assertSame( [ 'Sun-ExtA.ttf', 'Sun-ExtB.ttf' ], $this->required->get_required_font_files() );
$this->assertSame( [ 'Sun-ExtA.ttf', 'Sun-ExtB.ttf' ], $this->required->get_install_font_files( [ 'sun-exta' ] ) );
}

public function test_a_sip_ext_font_is_in_use_while_a_font_linking_it_is() {
$this->assertFalse( $this->required->is_font_in_use( 'sun-extb' ) );

GPDFAPI::get_options_class()->update_option( 'default_font', 'sun-exta' );
$this->assertTrue( $this->required->is_font_in_use( 'sun-extb' ) );

GPDFAPI::get_options_class()->delete_option( 'default_font' );
$this->add_form_with_pdfs( [ [ 'font' => 'sun-exta' ] ] );
$this->assertTrue( $this->required->is_font_in_use( 'sun-extb' ) );
}

/**
* @dataProvider provider_junk_font_data
*
Expand Down Expand Up @@ -1003,6 +1045,19 @@ public function test_a_site_without_a_usable_record_counts_as_using_every_core_f
$this->assertTrue( $this->required->is_font_in_use( 'dejavuserif', true ) );
}

public function test_a_sip_ext_font_is_in_use_while_another_site_uses_a_font_linking_it() {
if ( ! is_multisite() ) {
$this->markTestSkipped( 'Multisite only' );
}

$site = self::factory()->blog->create();
update_network_option( get_main_network_id(), Model_Required_Fonts::SITE_FONTS_PREFIX . $site, [ 'dejavuserif' ] );
$this->assertFalse( $this->required->is_font_in_use( 'sun-extb', true ) );

update_network_option( get_main_network_id(), Model_Required_Fonts::SITE_FONTS_PREFIX . $site, [ 'sun-exta' ] );
$this->assertTrue( $this->required->is_font_in_use( 'sun-extb', true ) );
}

public function test_a_failed_form_read_records_nothing() {
if ( ! is_multisite() ) {
$this->markTestSkipped( 'Multisite only' );
Expand Down