App-Music-ChordPro

 view release on metacpan or  search on metacpan

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

}

# Parse a string with one or more styles. Augments.
method read_string ( $string ) {

    state $ffi = "face000";	# for unique font-face ids

    $css->{'*'} //= $base;

    # Flatten whitespace and remove /* comment */ style comments.
    $string =~ s/\s+/ /g;
    $string =~ s!/\*.*?\*\/!!g;

    # Hide semicolon in url(data:application/octet-stream;base64,...)
    $string =~ s/(url\(['"]data:.*?\/.*?);(.*?),/$1\x{ff1b}$2,/g;

    # Split into styles.
    foreach ( grep { /\S/ } split /(?<=\})/, $string ) {
	unless ( /^\s*([^{]+?)\s*\{(.*)\}\s*$/ ) {
	    $errstr = "Invalid or unexpected style data '$_'";
	    return;
	}

	# Split in such a way as to support grouped styles.
	my $style      = $1;
	my $properties = $2;
	$style =~ s/\s{2,}/ /g;
	my @styles =
	  grep { s/\s+/ /g; 1; }
	    grep { /\S/ }
	      split( /\s*,\s*/, $style );
	foreach ( @styles ) {
	    # Give @font-face rules an unique id.
	    if ( $_ eq '@font-face' ) {
		$_ = '@font-'.$ffi;
		$ffi++;
	    }
	    $css->{$_} //= {};
	}

	# Split into properties.
	foreach ( grep { /\S/ } split /\;/, $properties ) {
	    unless ( /^\s*(\*?[\w._-]+)\s*:\s*(.*?)\s*$/ ) {
		$errstr = "Invalid or unexpected property '$_' in style '$style'";
		return;
	    }

	    my $s = lc($1);
	    my %s = ( $s => $2 );

	    # Split font shorthand.
	    if ( $s eq "font" ) {
		use Text::ParseWords qw(shellwords);
		my @spec = shellwords($s{$s});

		foreach my $spec ( @spec ) {
		    $spec =~ s/;$//;
		    if ( $spec =~ /^([.\d]+)px/ ) {
			$s{'font-size'} = $1;
		    }
		    elsif ( $spec eq "bold" ) {
			$s{'font-weight'} = "bold";
		    }
		    elsif ( $spec eq "italic" ) {
			$s{'font-style'} = "italic";
		    }
		    elsif ( $spec eq "bolditalic" ) {
			$s{'font-weight'} = "bold";
			$s{'font-style'} = "italic";
		    }
		    elsif ( $spec =~ /^(?:text,)?serif$/i ) {
			$s{'font-family'} = "serif";
		    }
		    elsif ( $spec =~ /^(?:text,)?sans(?:-serif)?$/i ) {
			$s{'font-family'} = "sans";
		    }

		    # These are for ABC SVG processing.
		    elsif ( $spec =~ /^abc2svg(?:\.ttf)?$/i ) {
			$s{'font-family'} = "abc2svg";
		    }
		    elsif ( lc($spec) =~ /^musejazz\s*text$/i ) {
			$s{'font-family'} = "musejazztext";
		    }
		    else {
			$s{'font-family'} = $spec;
		    }
		}

		# Remove the shorthand if we found something.
		delete($s{$s}) if keys(%s) > 1;
	    }

	    # Split outline shorthand.
	    elsif ( $s eq "outline" ) {
		use Text::ParseWords qw(shellwords);
		my @spec = shellwords($s{$s});

		foreach my $spec ( @spec ) {
		    $spec =~ s/;$//;
		    if ( $spec =~ /^([.\d]+)px/ ) {
			$s{'outline-width'} = $1;
		    }
		    elsif ( $spec =~ /^(dotted|dashed|solid|double|groove|ridge|inset|outset)$/i ) {
			$s{'outline-style'} = $1;
		    }
		    else {
			$s{'outline-color'} = $spec;
		    }
		}

		# Remove the shorthand if we found something.
		delete($s{$s}) if keys(%s) > 1;
	    }

	    foreach my $k ( keys %s ) {
		foreach ( @styles ) {
		    $css->{$_}->{$k} = $s{$k};
		}
	    }
	}
    }

    my @keys = keys( %$css );
    for my $k ( @keys ) {
	if ( $k =~ /^\@font-face/ ) {
	    # Unhide semicolons.
	    s/\x{ff1b}/;/g for values( %{$css->{$k}} );



( run in 0.568 second using v1.01-cache-2.11-cpan-98e64b0badf )