App-Music-ChordPro

 view release on metacpan or  search on metacpan

lib/ChordPro/lib/SVGPDF/FontManager.pm  view on Meta::CPAN

    my ( $font, $size, $src ) = $self->find_font($style);
    $xo->font( $font, $size );
}

method find_font ( $style ) {

    my $stl    = lc( $style->{'font-style'}  // "normal" );
    my $weight = lc( $style->{'font-weight'} // "normal" );
    ####TODO: normalize styles and weights.

    # Process the font-families, if any.
    for ( ffsplit( $style->{'font-family'} // [] ) ) {
	my $family = lc($_);

	# Check against @font-faces, if any.
	for ( @{ $style->{'@font-face'}//[] } ) {
	    my $fam = $_->{'font-family'};
	    next unless $fam && lc($fam) eq $family;
	    next unless $_->{src};
	    next if $_->{'font-style'} && $style->{'font-style'}
	      && $_->{'font-style'} ne $style->{'font-style'};
	    next if $_->{'font-weight'} && $style->{'font-weight'}
	      && $_->{'font-weight'} ne $style->{'font-weight'};

	    $fam = lc($fam);
	    my $key = join( "|", $fam, $stl, $weight );
	    # Font in cache?
	    if ( my $f = $fc->{$key} ) {
		return ( $f->{font},
			 $style->{'font-size'} || 12,
			 $f->{src} );
	    }

	    # Fetch font from source.
	    my $src = $_->{src};
	    ####TODO: Multiple sources
	    if ( $src =~ /^\s*url\s*\((["'])((?:data|https?|file):.*?)\1\s*\)/is ) {
		use File::LoadLines 1.044;
		my $opts = {};
		my $data = File::LoadLines::loadblob( $2, $opts );

		# To load font data from net and data urls.
		use File::Temp qw( tempfile tempdir );
		use MIME::Base64 qw( decode_base64 );
		$td //= tempdir( CLEANUP => 1 );

		my $sfx;	# suffix for font file name
		if ( $src =~ /\bformat\((["'])(.*?)\1\)/ ) {
		    $sfx =
		      lc($2) eq "truetype" ? ".ttf" :
		      lc($2) eq "opentype" ? ".otf" :
		      '';
		}
		elsif ( $opts->{_filesource} =~ /\.(\w+)$/ ) {
		    $sfx = $2;
		}
		# No (or unknown) format, skip.
		next unless $sfx;

		my ($fh,$fn) = tempfile( "${td}SVGXXXX", SUFFIX => $sfx );
		binmode( $fh => ':raw' );
		print $fh $data;
		close($fh);
		my $font = eval { $svg->pdf->font($fn) };
		croak($@) if $@;
		my $f = $fc->{$key} =
		  { font => $font,
		    src => $opts->{_filesource} };
		#warn("SRC: ", $opts->{_filesource}, "\n");
		return ( $f->{font},
			 $style->{'font-size'} || 12,
			 $f->{src} );
	    }
	    # Temp.
	    elsif ( $src =~ /^\s*url\s*\((["'])data:application\/octet-stream;base64,(.*?)\1\s*\)/is ) {

		my $data = $2;

		# To load font data from net and data urls.
		use File::Temp qw( tempfile tempdir );
		use MIME::Base64 qw( decode_base64 );
		$td //= tempdir( CLEANUP => 1 );

		my $sfx;	# suffix for font file name
		if ( $src =~ /\bformat\((["'])(.*?)\1\)/ ) {
		    $sfx =
		      lc($2) eq "truetype" ? ".ttf" :
		      lc($2) eq "opentype" ? ".otf" :
		      '';
		}
		# No (or unknown) format, skip.
		next unless $sfx;

		my ($fh,$fn) = tempfile( "${td}SVGXXXX", SUFFIX => $sfx );
		binmode( $fh => ':raw' );
		print $fh decode_base64($data);
		close($fh);
		my $font = eval { $svg->pdf->font($fn) };
		croak($@) if $@;
		my $f = $fc->{$key} =
		  { font => $font,
		    src => 'data' };
		return ( $f->{font},
			 $style->{'font-size'} || 12,
			 $f->{src} );
	    }
	    elsif ( $src =~ /^\s*url\s*\((["'])(.*?\.[ot]tf)\1\s*\)/is ) {
		my $fn = $2;
		my $font = eval { $svg->pdf->font($fn) };
		croak($@) if $@;
		my $f = $fc->{$key} =
		  { font => $font,
		    src => $fn };
		return ( $f->{font},
			 $style->{'font-size'} || 12,
			 $f->{src} );
	    }
	    else {
		croak("\@font-face: Unhandled src \"", substr($src,0,50), "...\"");
	    }
	}
    }

    my $key = join( "|", $style->{'font-family'}, $stl, $weight );
    # Font in cache?
    if ( my $f = $fc->{$key} ) {
	return ( $f->{font},
		 $style->{'font-size'} || 12,
		 $f->{src} );
    }

    if ( my $cb = $svg->fc ) {
	my $font;
	unless ( ref($cb) eq 'ARRAY' ) {
	    $cb = [ $cb ];
	}
	# Run callbacks.
	my %args = ( pdf => $svg->pdf, style => $style );
	for ( @$cb ) {
	    eval { $font = $_->( $svg, %args ) };
	    croak($@) if $@;
	    last if $font;
	}

	if ( $font ) {
	    my $src = "Callback($key)";
	    $fc->{$key} = { font => $font, src => $src };
	    return ( $font,
		     $style->{'font-size'} || 12,
		     $src );
	}
    }

    # No @font-face, no (or failed) callbacks, we're on our own.



( run in 1.219 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )